From c4cbeec8413f0fd807142fe989f96df157442c1e Mon Sep 17 00:00:00 2001 From: sylenien Date: Tue, 27 Dec 2022 16:41:00 +0100 Subject: [PATCH] change(ui): remove old reducers, rewrite eventsblock component --- .../Alerts/Notifications/Notifications.tsx | 26 +- .../CustomMetricWidget/CustomMetricWidget.tsx | 2 - .../components/FilterSeries/FilterSeries.tsx | 50 ++-- .../app/components/Session/RightBlock.tsx | 37 ++- .../components/Session_/EventsBlock/Event.js | 8 - .../EventsBlock/EventSearch/EventSearch.js | 8 +- .../Session_/EventsBlock/EventsBlock.js | 249 ------------------ .../Session_/EventsBlock/EventsBlock.tsx | 187 +++++++++++++ .../PageInsightsPanel/PageInsightsPanel.tsx | 1 - .../FilterSeries/FilterSeries.tsx | 112 -------- .../FilterSeries/SeriesName/SeriesName.tsx | 57 ---- .../FilterSeries/SeriesName/index.ts | 1 - .../CustomMetrics/FilterSeries/index.ts | 1 - .../shared/DevTools/useCellMeasurerCache.ts | 10 +- frontend/app/duck/ReducerModule.js.dev | 55 ---- frontend/app/duck/customMetrics.js | 43 +-- frontend/app/duck/environments.js | 7 - frontend/app/duck/events.js | 81 ------ frontend/app/duck/index.ts | 9 +- frontend/app/duck/notifications.js | 63 ----- frontend/app/duck/sessions.js | 16 +- frontend/app/duck/variables.js | 9 - frontend/app/mstore/userStore.ts | 4 +- frontend/app/types/address.js | 20 -- frontend/app/types/appTest.js | 87 ------ frontend/app/types/member.ts | 18 +- 26 files changed, 265 insertions(+), 896 deletions(-) delete mode 100644 frontend/app/components/Session_/EventsBlock/EventsBlock.js create mode 100644 frontend/app/components/Session_/EventsBlock/EventsBlock.tsx delete mode 100644 frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx delete mode 100644 frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx delete mode 100644 frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/index.ts delete mode 100644 frontend/app/components/shared/CustomMetrics/FilterSeries/index.ts delete mode 100644 frontend/app/duck/ReducerModule.js.dev delete mode 100644 frontend/app/duck/environments.js delete mode 100644 frontend/app/duck/events.js delete mode 100644 frontend/app/duck/notifications.js delete mode 100644 frontend/app/duck/variables.js delete mode 100644 frontend/app/types/address.js delete mode 100644 frontend/app/types/appTest.js diff --git a/frontend/app/components/Alerts/Notifications/Notifications.tsx b/frontend/app/components/Alerts/Notifications/Notifications.tsx index 05bcea06b..2bc78384f 100644 --- a/frontend/app/components/Alerts/Notifications/Notifications.tsx +++ b/frontend/app/components/Alerts/Notifications/Notifications.tsx @@ -1,34 +1,27 @@ import React, { useEffect } from 'react'; import stl from './notifications.module.css'; -import { connect } from 'react-redux'; import { Icon, Tooltip } from 'UI'; -import { fetchList, setViewed, clearAll } from 'Duck/notifications'; -import { setLastRead } from 'Duck/announcements'; import { useModal } from 'App/components/Modal'; import AlertTriggersModal from 'Shared/AlertTriggersModal'; import { useStore } from 'App/mstore'; -import { useObserver } from 'mobx-react-lite'; +import { observer } from 'mobx-react-lite'; const AUTOREFRESH_INTERVAL = 5 * 60 * 1000; -interface Props { - notifications: any; - fetchList: any; -} -function Notifications(props: Props) { +function Notifications() { const { showModal } = useModal(); const { notificationStore } = useStore(); - const count = useObserver(() => notificationStore.notificationsCount); + const count = notificationStore.notificationsCount; useEffect(() => { const interval = setInterval(() => { - notificationStore.fetchNotificationsCount(); + void notificationStore.fetchNotificationsCount(); }, AUTOREFRESH_INTERVAL); return () => clearInterval(interval); }, []); - return useObserver(() => ( + return (
- )); + ); } -export default connect( - (state: any) => ({ - notifications: state.getIn(['notifications', 'list']), - }), - { fetchList, setLastRead, setViewed, clearAll } -)(Notifications); +export default observer(Notifications) \ No newline at end of file diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx index b804ca439..71820c502 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/CustomMetricWidget/CustomMetricWidget.tsx @@ -9,7 +9,6 @@ import { init, edit, remove, - setAlertMetricId, setActiveWidget, updateActiveState, } from 'Duck/customMetrics'; @@ -181,7 +180,6 @@ export default connect( { remove, setShowAlerts, - setAlertMetricId, edit, setActiveWidget, updateActiveState, diff --git a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx index ccb269cbd..bcfd27406 100644 --- a/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx +++ b/frontend/app/components/Dashboard/components/FilterSeries/FilterSeries.tsx @@ -1,14 +1,5 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import FilterList from 'Shared/Filters/FilterList'; -import { - edit, - updateSeries, - addSeriesFilterFilter, - removeSeriesFilterFilter, - editSeriesFilterFilter, - editSeriesFilter, -} from 'Duck/customMetrics'; -import { connect } from 'react-redux'; import { Button, Icon } from 'UI'; import FilterSelection from 'Shared/Filters/FilterSelection'; import SeriesName from './SeriesName'; @@ -18,21 +9,21 @@ import { observer } from 'mobx-react-lite'; interface Props { seriesIndex: number; series: any; - edit: typeof edit; - updateSeries: typeof updateSeries; onRemoveSeries: (seriesIndex: any) => void; - canDelete?: boolean; - addSeriesFilterFilter: typeof addSeriesFilterFilter; - editSeriesFilterFilter: typeof editSeriesFilterFilter; - editSeriesFilter: typeof editSeriesFilter; - removeSeriesFilterFilter: typeof removeSeriesFilterFilter; + canDelete?: boolean; hideHeader?: boolean; emptyMessage?: any; observeChanges?: () => void; } function FilterSeries(props: Props) { - const { observeChanges = () => {}, canDelete, hideHeader = false, emptyMessage = 'Add user event or filter to define the series by clicking Add Step.' } = props; + const { + observeChanges = () => { + }, + canDelete, + hideHeader = false, + emptyMessage = 'Add user event or filter to define the series by clicking Add Step.' + } = props; const [expanded, setExpanded] = useState(true) const { series, seriesIndex } = props; @@ -46,7 +37,7 @@ function FilterSeries(props: Props) { observeChanges() } - const onChangeEventsOrder = (e, { name, value }: any) => { + const onChangeEventsOrder = (e: any, { name, value }: any) => { series.filter.updateKey(name, value) observeChanges() } @@ -60,11 +51,11 @@ function FilterSeries(props: Props) {
- series.update('name', name) } /> + series.update('name', name)} />
- +
-
+
@@ -73,17 +64,17 @@ function FilterSeries(props: Props) {
- { expanded && ( + {expanded && ( <>
- { series.filter.filters.length > 0 ? ( + {series.filter.filters.length > 0 ? ( - ): ( + ) : (
{emptyMessage}
)}
@@ -103,11 +94,4 @@ function FilterSeries(props: Props) { ); } -export default connect(null, { - edit, - updateSeries, - addSeriesFilterFilter, - editSeriesFilterFilter, - editSeriesFilter, - removeSeriesFilterFilter, -})(observer(FilterSeries)); \ No newline at end of file +export default observer(FilterSeries); \ No newline at end of file diff --git a/frontend/app/components/Session/RightBlock.tsx b/frontend/app/components/Session/RightBlock.tsx index 66f92a93c..9e4302648 100644 --- a/frontend/app/components/Session/RightBlock.tsx +++ b/frontend/app/components/Session/RightBlock.tsx @@ -1,33 +1,30 @@ import React from 'react' import EventsBlock from '../Session_/EventsBlock'; import PageInsightsPanel from '../Session_/PageInsightsPanel/PageInsightsPanel' -import { PlayerContext } from 'App/components/Session/playerContext'; -import { observer } from 'mobx-react-lite'; import cn from 'classnames'; import stl from './rightblock.module.css'; function RightBlock(props: any) { const { activeTab } = props; - const { player, store } = React.useContext(PlayerContext) - const { eventListNow, playing } = store.get() - const currentTimeEventIndex = eventListNow.length > 0 ? eventListNow.length - 1 : 0 - - const EventsBlockConnected = () => - const renderActiveTab = (tab: string) => { - switch(tab) { - case props.tabs.EVENTS: - return - case props.tabs.HEATMAPS: - return - } + if (activeTab === props.tabs.EVENTS) { + return ( +
+ +
+ ) } - return ( -
- {renderActiveTab(activeTab)} -
- ) + if (activeTab === props.tabs.HEATMAPS) { + return ( +
+ +
+ ) + } + return null } -export default observer(RightBlock) +export default RightBlock diff --git a/frontend/app/components/Session_/EventsBlock/Event.js b/frontend/app/components/Session_/EventsBlock/Event.js index bfae9fe5d..e8f985aa0 100644 --- a/frontend/app/components/Session_/EventsBlock/Event.js +++ b/frontend/app/components/Session_/EventsBlock/Event.js @@ -147,14 +147,6 @@ export default class Event extends React.PureComponent { }
- {/*
- -
*/}
{ this.renderBody() }
diff --git a/frontend/app/components/Session_/EventsBlock/EventSearch/EventSearch.js b/frontend/app/components/Session_/EventsBlock/EventSearch/EventSearch.js index 3c3396e72..965e9726d 100644 --- a/frontend/app/components/Session_/EventsBlock/EventSearch/EventSearch.js +++ b/frontend/app/components/Session_/EventsBlock/EventSearch/EventSearch.js @@ -5,16 +5,10 @@ import { PlayerContext } from 'App/components/Session/playerContext'; function EventSearch(props) { const { player } = React.useContext(PlayerContext) - const { onChange, clearSearch, value, header, setActiveTab } = props; + const { onChange, value, header, setActiveTab } = props; const toggleEvents = () => player.toggleEvents() - useEffect(() => { - return () => { - clearSearch() - } - }, []) - return (
diff --git a/frontend/app/components/Session_/EventsBlock/EventsBlock.js b/frontend/app/components/Session_/EventsBlock/EventsBlock.js deleted file mode 100644 index b3d978347..000000000 --- a/frontend/app/components/Session_/EventsBlock/EventsBlock.js +++ /dev/null @@ -1,249 +0,0 @@ -import React from 'react'; -import { connect } from 'react-redux'; -import cn from 'classnames'; -import { Icon } from 'UI'; -import { List, AutoSizer, CellMeasurer, CellMeasurerCache } from "react-virtualized"; -import { TYPES } from 'Types/session/event'; -import { setSelected } from 'Duck/events'; -import { setEventFilter, filterOutNote } from 'Duck/sessions'; -import { show as showTargetDefiner } from 'Duck/components/targetDefiner'; -import EventGroupWrapper from './EventGroupWrapper'; -import styles from './eventsBlock.module.css'; -import EventSearch from './EventSearch/EventSearch'; - -@connect(state => ({ - session: state.getIn([ 'sessions', 'current' ]), - filteredEvents: state.getIn([ 'sessions', 'filteredEvents' ]), - eventsIndex: state.getIn([ 'sessions', 'eventsIndex' ]), - selectedEvents: state.getIn([ 'events', 'selected' ]), - targetDefinerDisplayed: state.getIn([ 'components', 'targetDefiner', 'isDisplayed' ]), - testsAvaliable: false, -}), { - showTargetDefiner, - setSelected, - setEventFilter, - filterOutNote -}) -export default class EventsBlock extends React.Component { - state = { - editingEvent: null, - mouseOver: false, - query: '' - } - - scroller = React.createRef(); - cache = new CellMeasurerCache({ - fixedWidth: true, - defaultHeight: 300 - }); - - write = ({ target: { value, name } }) => { - const { filter } = this.state; - this.setState({ query: value }) - this.props.setEventFilter({ query: value, filter }) - - setTimeout(() => { - if (!this.scroller.current) return; - - this.scroller.current.scrollToRow(0); - }, 100) - } - - clearSearch = () => { - const { filter } = this.state; - this.setState({ query: '' }) - this.props.setEventFilter({ query: '', filter }) - if (this.scroller.current) { - this.scroller.current.forceUpdateGrid(); - } - - setTimeout(() => { - if (!this.scroller.current) return; - - this.scroller.current.scrollToRow(0); - }, 100) - } - - onSetEventFilter = (e, { name, value }) => { - const { query } = this.state; - this.setState({ filter: value }) - this.props.setEventFilter({ filter: value, query }); - } - - componentDidUpdate(prevProps) { - if (prevProps.targetDefinerDisplayed && !this.props.targetDefinerDisplayed) { - this.setState({ editingEvent: null }); - } - if (prevProps.session !== this.props.session) { // Doesn't happen - this.cache = new CellMeasurerCache({ - fixedWidth: true, - defaultHeight: 300 - }); - } - if (prevProps.currentTimeEventIndex !== this.props.currentTimeEventIndex && - this.scroller.current !== null) { - this.scroller.current.forceUpdateGrid(); - if (!this.state.mouseOver) { - this.scroller.current.scrollToRow(this.props.currentTimeEventIndex); - } - } - } - - onCheckboxClick(e, event) { - e.stopPropagation(); - const { - session: { events }, - selectedEvents, - } = this.props; - - this.props.player.pause(); - - let newSelectedSet; - const wasSelected = selectedEvents.contains(event); - if (wasSelected) { - newSelectedSet = selectedEvents.remove(event); - } else { - newSelectedSet = selectedEvents.add(event); - } - - let selectNextLoad = false; - events.reverse().forEach((sessEvent) => { - if (sessEvent.type === TYPES.LOCATION) { - if (selectNextLoad) { - newSelectedSet = newSelectedSet.add(sessEvent); - } - selectNextLoad = false; - } else if (newSelectedSet.contains(sessEvent)) { - selectNextLoad = true; - } - }); - this.props.setSelected(newSelectedSet); - } - - onEventClick = (e, event) => this.props.player.jump(event.time) - - onMouseOver = () => this.setState({ mouseOver: true }) - onMouseLeave = () => this.setState({ mouseOver: false }) - - get eventsList() { - const { session: { notesWithEvents }, filteredEvents } = this.props - const usedEvents = filteredEvents || notesWithEvents - - return usedEvents - } - - renderGroup = ({ index, key, style, parent }) => { - const { - selectedEvents, - currentTimeEventIndex, - testsAvaliable, - playing, - eventsIndex, - filterOutNote, - } = this.props; - - const { query } = this.state; - const _events = this.eventsList - const isLastEvent = index === _events.size - 1; - const isLastInGroup = isLastEvent || _events.get(index + 1).type === TYPES.LOCATION; - const event = _events.get(index); - const isNote = !!event.noteId - const isSelected = selectedEvents.includes(event); - const isCurrent = index === currentTimeEventIndex; - const isEditing = this.state.editingEvent === event; - - const heightBug = index === 0 && event.type === TYPES.LOCATION && event.referrer ? { top: 2 } : {} - return ( - - {({measure, registerChild}) => ( -
- -
- )} -
- ); - } - - render() { - const { query } = this.state; - const { - session: { - events, - }, - setActiveTab, - } = this.props; - - const _events = this.eventsList - - const isEmptySearch = query && (_events.size === 0 || !_events) - return ( - <> -
-
- User Steps { events.size }
- } - /> -
-
-
- {isEmptySearch && ( -
- - No Matching Results -
- )} - - {({ height }) => ( - - )} - -
- - ); - } -} diff --git a/frontend/app/components/Session_/EventsBlock/EventsBlock.tsx b/frontend/app/components/Session_/EventsBlock/EventsBlock.tsx new file mode 100644 index 000000000..0f0405cd5 --- /dev/null +++ b/frontend/app/components/Session_/EventsBlock/EventsBlock.tsx @@ -0,0 +1,187 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import cn from 'classnames'; +import { Icon } from 'UI'; +import { List, AutoSizer, CellMeasurer } from "react-virtualized"; +import { TYPES } from 'Types/session/event'; +import { setEventFilter, filterOutNote } from 'Duck/sessions'; +import { show as showTargetDefiner } from 'Duck/components/targetDefiner'; +import EventGroupWrapper from './EventGroupWrapper'; +import styles from './eventsBlock.module.css'; +import EventSearch from './EventSearch/EventSearch'; +import { PlayerContext } from 'App/components/Session/playerContext'; +import { observer } from 'mobx-react-lite'; +import { RootStore } from 'App/duck' +import { List as ImmList } from 'immutable' +import useCellMeasurerCache from 'Components/shared/DevTools/useCellMeasurerCache' + +interface IProps { + setEventFilter: (filter: { query: string }) => void + filteredEvents: ImmList> + setActiveTab: (tab?: string) => void + query: string + session: Record + filterOutNote: (id: string) => void + eventsIndex: number[] +} + +function EventsBlock(props: IProps) { + const [mouseOver, setMouseOver] = React.useState(true) + const scroller = React.useRef(null) + const cache = useCellMeasurerCache(undefined, { + fixedWidth: true, + defaultHeight: 300 + }); + + const { store, player } = React.useContext(PlayerContext) + + const { eventListNow, playing } = store.get() + + const { session: { events, notesWithEvents }, filteredEvents, + eventsIndex, + filterOutNote, + query, + setActiveTab, + } = props + const currentTimeEventIndex = eventListNow.length > 0 ? eventListNow.length - 1 : 0 + const usedEvents = filteredEvents || notesWithEvents + + const write = ({ target: { value } }: React.ChangeEvent) => { + props.setEventFilter({ query: value }) + + setTimeout(() => { + if (!scroller.current) return; + + scroller.current.scrollToRow(0); + }, 100) + } + + const clearSearch = () => { + props.setEventFilter({ query: '' }) + if (scroller.current) { + scroller.current.forceUpdateGrid(); + } + + setTimeout(() => { + if (!scroller.current) return; + + scroller.current.scrollToRow(0); + }, 100) + } + + React.useEffect(() => { + return () => { + clearSearch() + } + }, []) + React.useEffect(() => { + if (scroller.current) { + scroller.current.forceUpdateGrid(); + if (!mouseOver) { + scroller.current.scrollToRow(currentTimeEventIndex); + } + } + }, [currentTimeEventIndex]) + + const onEventClick = (_: React.MouseEvent, event: any) => player.jump(event.time) + const onMouseOver = () => setMouseOver(true) + const onMouseLeave = () => setMouseOver(false) + + const renderGroup = ({ index, key, style, parent }: { index: number; key: string; style: any; parent: any }) => { + const isLastEvent = index === usedEvents.size - 1; + const isLastInGroup = isLastEvent || usedEvents.get(index + 1)?.type === TYPES.LOCATION; + const event = usedEvents.get(index); + const isNote = !!event?.noteId + const isCurrent = index === currentTimeEventIndex; + + const heightBug = index === 0 && event?.type === TYPES.LOCATION && event.referrer ? { top: 2 } : {} + return ( + + {({measure, registerChild}) => ( +
+ +
+ )} +
+ ); + } + + const isEmptySearch = query && (usedEvents.size === 0 || !usedEvents) + return ( + <> +
+
+ User Steps { events.size }
+ } + /> +
+
+
+ {isEmptySearch && ( +
+ + No Matching Results +
+ )} + + {({ height }) => ( + + )} + +
+ + ); +} + +export default connect((state: RootStore) => ({ + session: state.getIn([ 'sessions', 'current' ]), + filteredEvents: state.getIn([ 'sessions', 'filteredEvents' ]), + query: state.getIn(['sessions', 'eventsQuery']), + eventsIndex: state.getIn([ 'sessions', 'eventsIndex' ]), + targetDefinerDisplayed: state.getIn([ 'components', 'targetDefiner', 'isDisplayed' ]), +}), { + showTargetDefiner, + setEventFilter, + filterOutNote +})(observer(EventsBlock)) diff --git a/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx b/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx index e1ba5ccba..b43f70ed9 100644 --- a/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx +++ b/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx @@ -13,7 +13,6 @@ const JUMP_OFFSET = 1000; interface Props { filters: any; fetchInsights: (filters: Record) => void; - urls: []; insights: any; events: Array; urlOptions: Array; diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx deleted file mode 100644 index 8f8aca480..000000000 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/FilterSeries.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import React, { useState } from 'react'; -import FilterList from 'Shared/Filters/FilterList'; -import { - edit, - updateSeries, - addSeriesFilterFilter, - removeSeriesFilterFilter, - editSeriesFilterFilter, - editSeriesFilter, -} from 'Duck/customMetrics'; -import { connect } from 'react-redux'; -import { IconButton, Icon } from 'UI'; -import FilterSelection from '../../Filters/FilterSelection'; -import SeriesName from './SeriesName'; -import cn from 'classnames'; - -interface Props { - seriesIndex: number; - series: any; - edit: typeof edit; - updateSeries: typeof updateSeries; - onRemoveSeries: (seriesIndex) => void; - canDelete?: boolean; - addSeriesFilterFilter: typeof addSeriesFilterFilter; - editSeriesFilterFilter: typeof editSeriesFilterFilter; - editSeriesFilter: typeof editSeriesFilter; - removeSeriesFilterFilter: typeof removeSeriesFilterFilter; - hideHeader?: boolean; - emptyMessage?: any; -} - -function FilterSeries(props: Props) { - const { canDelete, hideHeader = false, emptyMessage = 'Add user event or filter to define the series by clicking Add Step.' } = props; - const [expanded, setExpanded] = useState(true) - const { series, seriesIndex } = props; - - const onAddFilter = (filter) => { - filter.value = [""] - if (filter.hasOwnProperty('filters') && Array.isArray(filter.filters)) { - filter.filters = filter.filters.map(i => ({ ...i, value: [""] })) - } - props.addSeriesFilterFilter(seriesIndex, filter); - } - - const onUpdateFilter = (filterIndex, filter) => { - props.editSeriesFilterFilter(seriesIndex, filterIndex, filter); - } - - const onChangeEventsOrder = (e, { name, value }) => { - props.editSeriesFilter(seriesIndex, { eventsOrder: value }); - } - - const onRemoveFilter = (filterIndex) => { - props.removeSeriesFilterFilter(seriesIndex, filterIndex); - } - - return ( -
-
-
- props.updateSeries(seriesIndex, { name }) } /> -
- -
-
- -
- -
setExpanded(!expanded)} className="ml-3"> - -
- -
-
- { expanded && ( - <> -
- { series.filter.filters.size > 0 ? ( - - ): ( -
{emptyMessage}
- )} -
-
-
- - - -
-
- - )} -
- ); -} - -export default connect(null, { - edit, - updateSeries, - addSeriesFilterFilter, - editSeriesFilterFilter, - editSeriesFilter, - removeSeriesFilterFilter, -})(FilterSeries); \ No newline at end of file diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx deleted file mode 100644 index d6a69c73d..000000000 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/SeriesName.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import React, { useState, useRef, useEffect } from 'react'; -import { Icon } from 'UI'; - -interface Props { - name: string; - onUpdate: (name) => void; - seriesIndex?: number; -} -function SeriesName(props: Props) { - const { seriesIndex = 1 } = props; - const [editing, setEditing] = useState(false) - const [name, setName] = useState(props.name) - const ref = useRef(null) - - const write = ({ target: { value, name } }) => { - setName(value) - } - - const onBlur = () => { - setEditing(false) - props.onUpdate(name) - } - - useEffect(() => { - if (editing) { - ref.current.focus() - } - }, [editing]) - - useEffect(() => { - setName(props.name) - }, [props.name]) - - // const { name } = props; - return ( -
- { editing ? ( - setEditing(true)} - /> - ) : ( -
{name && name.trim() === '' ? 'Series ' + (seriesIndex + 1) : name }
- )} - -
setEditing(true)}>
-
- ); -} - -export default SeriesName; \ No newline at end of file diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/index.ts b/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/index.ts deleted file mode 100644 index 90e63cdb6..000000000 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/SeriesName/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './SeriesName'; \ No newline at end of file diff --git a/frontend/app/components/shared/CustomMetrics/FilterSeries/index.ts b/frontend/app/components/shared/CustomMetrics/FilterSeries/index.ts deleted file mode 100644 index 5882e382a..000000000 --- a/frontend/app/components/shared/CustomMetrics/FilterSeries/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './FilterSeries' \ No newline at end of file diff --git a/frontend/app/components/shared/DevTools/useCellMeasurerCache.ts b/frontend/app/components/shared/DevTools/useCellMeasurerCache.ts index 2c94f7856..692f2629f 100644 --- a/frontend/app/components/shared/DevTools/useCellMeasurerCache.ts +++ b/frontend/app/components/shared/DevTools/useCellMeasurerCache.ts @@ -1,12 +1,12 @@ import { useMemo } from 'react' -import { CellMeasurerCache } from 'react-virtualized'; +import { CellMeasurerCache, CellMeasurerCacheParams } from 'react-virtualized'; import useLatestRef from 'App/hooks/useLatestRef' - -export default function useCellMeasurerCache(itemList: any[]) { - const filteredListRef = useLatestRef(itemList) +export default function useCellMeasurerCache(itemList?: any[], options?: CellMeasurerCacheParams) { + const filteredListRef = itemList ? useLatestRef(itemList) : undefined return useMemo(() => new CellMeasurerCache({ fixedWidth: true, - keyMapper: (index) => filteredListRef.current[index], + keyMapper: filteredListRef ? (index) => filteredListRef.current[index] : undefined, + ...options }), []) } \ No newline at end of file diff --git a/frontend/app/duck/ReducerModule.js.dev b/frontend/app/duck/ReducerModule.js.dev deleted file mode 100644 index c80c65a37..000000000 --- a/frontend/app/duck/ReducerModule.js.dev +++ /dev/null @@ -1,55 +0,0 @@ - -redux -> other storage ::<< Entities + Lists + relations <|> methods:: crud. request declaration -> request realisation with middleware -< (uses) MODEL - - - -!request declaration - - - -action/request formatter => ReducerModule Fabrique => - - -class ReducerModule { - _ns = "common" - _switch = {} - _n = 0 - - constructor(namespace) { - this._ns = namespace - } - - /** - Action: state => newState | { reduce: state, action => newState, creator: () => {objects to action} } - */ - actions(actns): this { - Object.keys(actns).map(key => { - const type = `${this._namespace}/${key.toUpperCase()}`; - this._switch[ type ] = actns[ key ]; - }); - return this; - } - - requests(reqsts): this { - Object.keys(reqsts).map(key => { - const type = `${this._namespace}/${key.toUpperCase()}`; - this._switch[ type ] = actns[ key ]; - }); - return this; - } - - get actionTypes() { - - } - - get actionCreators() { - - } - - get reducer() { - return (state, action = {}) => { - const reduce = this._switch[ action.type ]; - return reduce ? reduce(state, action) : state; - } - } -} \ No newline at end of file diff --git a/frontend/app/duck/customMetrics.js b/frontend/app/duck/customMetrics.js index e6713acb4..82ce78277 100644 --- a/frontend/app/duck/customMetrics.js +++ b/frontend/app/duck/customMetrics.js @@ -1,8 +1,8 @@ import { List, Map } from 'immutable'; import CustomMetric, { FilterSeries } from 'Types/customMetric' -import { createFetch, fetchListType, fetchType, saveType, removeType, editType, createRemove, createEdit } from './funcTools/crud'; +import { fetchListType, fetchType, saveType, removeType, editType, createRemove, createEdit } from './funcTools/crud'; import { createRequestReducer, ROOT_KEY } from './funcTools/request'; -import { array, request, success, failure, createListUpdater, mergeReducers } from './funcTools/tools'; +import { array, success, createListUpdater, mergeReducers } from './funcTools/tools'; import Filter from 'Types/filter'; import Session from 'Types/session'; @@ -28,11 +28,6 @@ const INIT = `${name}/INIT`; const SET_ACTIVE_WIDGET = `${name}/SET_ACTIVE_WIDGET`; const REMOVE = removeType(name); const UPDATE_SERIES = `${name}/UPDATE_SERIES`; -const SET_ALERT_METRIC_ID = `${name}/SET_ALERT_METRIC_ID`; - -function chartWrapper(chart = []) { - return chart.map(point => ({ ...point, count: Math.max(point.count, 0) })); -} const updateItemInList = createListUpdater(idKey); const updateInstance = (state, instance) => state.getIn([ "instance", idKey ]) === instance[ idKey ] @@ -117,12 +112,6 @@ export default mergeReducers( export const edit = createEdit(name); export const remove = createRemove(name); -export const updateSeries = (index, series) => ({ - type: UPDATE_SERIES, - index, - series, -}); - export function fetch(id) { return { id, @@ -147,34 +136,6 @@ export function fetchList() { }; } -export function setAlertMetricId(id) { - return { - type: SET_ALERT_METRIC_ID, - id, - }; -} - -export const addSeries = (series = null) => (dispatch, getState) => { - const instance = getState().getIn([ 'customMetrics', 'instance' ]); - const seriesIndex = instance.series.size; - const newSeries = series || { - name: `Series ${seriesIndex + 1}`, - filter: new Filter({ filters: [], eventsOrder: 'then' }), - }; - - dispatch({ - type: ADD_SERIES, - series: newSeries, - }); -} - -export const removeSeries = (index) => (dispatch, getState) => { - dispatch({ - type: REMOVE_SERIES, - index, - }); -} - export const init = (instance = null, forceNull = false) => (dispatch, getState) => { dispatch({ type: INIT, diff --git a/frontend/app/duck/environments.js b/frontend/app/duck/environments.js deleted file mode 100644 index 8356c4281..000000000 --- a/frontend/app/duck/environments.js +++ /dev/null @@ -1,7 +0,0 @@ -import Environment from 'Types/environment'; -import crudDuckGenerator from './tools/crudDuck'; - -const crudDuck = crudDuckGenerator('environment', Environment); -export const { fetchList, fetch, init, edit, save, remove } = crudDuck.actions; - -export default crudDuck.reducer; diff --git a/frontend/app/duck/events.js b/frontend/app/duck/events.js deleted file mode 100644 index 000bd24b7..000000000 --- a/frontend/app/duck/events.js +++ /dev/null @@ -1,81 +0,0 @@ -import { List, Map, Set } from 'immutable'; -import withRequestState, { RequestTypes } from 'Duck/requestStateCreator'; -import Event from 'Types/filter/event'; -import CustomFilter from 'Types/filter/customFilter'; -import { KEYS } from 'Types/filter/customFilter'; -import logger from 'App/logger'; -import { countries } from 'App/constants'; -import { getRE } from 'App/utils'; - -const FETCH_LIST = new RequestTypes('events/FETCH_LIST'); -const TOGGLE_SELECT = 'events/TOGGLE_SELECT'; -const SET_SELECTED = 'events/SET_SELECTED'; - -const countryOptions = Object.keys(countries).map(c => ({filterKey: KEYS.USER_COUNTRY, label: KEYS.USER_COUNTRY, type: KEYS.USER_COUNTRY, value: c, actualValue: countries[c], isFilter: true })); - -const initialState = Map({ - list: List(), - store: Set(), - - // replace? - selected: Set(), -}); - -const filterKeys = ['METADATA', KEYS.USERID, KEYS.USER_COUNTRY, KEYS.USER_BROWSER, KEYS.USER_OS, KEYS.USER_DEVICE, KEYS.REFERRER] - -const reducer = (state = initialState, action = {}) => { - switch (action.type) { - case FETCH_LIST.SUCCESS: { - const regCountry = getRE(action.params.q, 'i'); - const countryOptionsFiltered = List(countryOptions).filter(({ actualValue }) => regCountry.test(actualValue)).take(5); - - const eventList = List(action.data).concat(countryOptionsFiltered).map(item => ( - filterKeys.includes(item.type) ? - CustomFilter({...item, isFilter: true }) : - Event({...item, key: item.type, filterKey: item.type, label: item.type}) ) - ); - - return state - .set('list', eventList) - .update('store', store => store.concat(eventList)); - } - // TODO: use ids. or make a set-hoc? - case TOGGLE_SELECT: { - const { event, flag } = action; - const shouldBeInSet = typeof flag === 'boolean' - ? flag - : !state.get('selected').contains(event); - return state.update('selected', set => (shouldBeInSet - ? set.add(event) - : set.remove(event))); - } - case SET_SELECTED: - return state.set('selected', Set(action.events)); - } - return state; -}; - -export default withRequestState(FETCH_LIST, reducer); - -export function fetchList(params) { - return { - types: FETCH_LIST.toArray(), - call: client => client.get('/events/search', params), - params, - }; -} - -export function toggleSelect(event, flag) { - return { - type: TOGGLE_SELECT, - event, - flag, - }; -} - -export function setSelected(events) { - return { - type: SET_SELECTED, - events, - }; -} diff --git a/frontend/app/duck/index.ts b/frontend/app/duck/index.ts index 0371396bf..91b92d5d1 100644 --- a/frontend/app/duck/index.ts +++ b/frontend/app/duck/index.ts @@ -1,3 +1,4 @@ +// @ts-ignore import { combineReducers } from 'redux-immutable'; import user from './user'; @@ -7,12 +8,8 @@ import target from './target'; import targetCustom from './targetCustom'; import filters from './filters'; import funnelFilters from './funnelFilters'; -import events from './events'; -import environments from './environments'; -import variables from './variables'; import templates from './templates'; import alerts from './alerts'; -import notifications from './notifications'; import dashboard from './dashboard'; import components from './components'; import sources from './sources'; @@ -41,12 +38,8 @@ const rootReducer = combineReducers({ filters, funnelFilters, - events, - environments, - variables, templates, alerts, - notifications, dashboard, components, members, diff --git a/frontend/app/duck/notifications.js b/frontend/app/duck/notifications.js deleted file mode 100644 index 129349792..000000000 --- a/frontend/app/duck/notifications.js +++ /dev/null @@ -1,63 +0,0 @@ -import { List, Map } from 'immutable'; -import Notification from 'Types/notification'; -import { mergeReducers, success, array, request, createListUpdater } from './funcTools/tools'; -import { createRequestReducer } from './funcTools/request'; -import { - createCRUDReducer, - getCRUDRequestTypes, - createFetchList, -} from './funcTools/crud'; - -const name = 'notification'; -const idKey = 'notificationId'; -const SET_VIEWED = 'notifications/SET_VIEWED'; -const CLEAR_ALL = 'notifications/CLEAR_ALL'; -const SET_VIEWED_SUCCESS = success(SET_VIEWED); -const CLEAR_ALL_SUCCESS = success(CLEAR_ALL); - -const listUpdater = createListUpdater(idKey); - -const initialState = Map({ - list: List(), -}); - -const reducer = (state = initialState, action = {}) => { - switch (action.type) { - case SET_VIEWED_SUCCESS: - if (!action.data) return state; - const item = state.get('list').find(item => item[ idKey ] === action.id) - return listUpdater(state, Notification({...item.toJS(), createdAt: item.createdAt.ts, viewed: true })); - case CLEAR_ALL_SUCCESS: - if (!action.data) return state; - return state.update('list', list => list.map(l => Notification({...l.toJS(), createdAt: l.createdAt.ts, viewed: true }))) - } - return state; -}; - -export const fetchList = createFetchList(name); - -export default mergeReducers( - reducer, - createCRUDReducer(name, Notification, idKey), - createRequestReducer({ - setViewed: SET_VIEWED, - clearAll: CLEAR_ALL, - ...getCRUDRequestTypes(name), - }), -); - -export function setViewed(id) { - return { - types: array(SET_VIEWED), - call: client => client.get(`/notifications/${ id }/view`), - id, - }; -} - -export function clearAll(params) { - return { - types: array(CLEAR_ALL), - call: client => client.post('/notifications/view', params), - }; -} - diff --git a/frontend/app/duck/sessions.js b/frontend/app/duck/sessions.js index 8afb6d073..b78d8fad4 100644 --- a/frontend/app/duck/sessions.js +++ b/frontend/app/duck/sessions.js @@ -60,6 +60,7 @@ const initialState = Map({ eventsIndex: [], sourcemapUploaded: true, filteredEvents: null, + eventsQuery: '', showChatWindow: false, liveSessions: List(), visitedEvents: List(), @@ -110,14 +111,17 @@ const reducer = (state = initialState, action = {}) => { case SET_EVENT_QUERY: { const events = state.get('current').events; const query = action.filter.query; - // const filter = action.filter.filter; const searchRe = getRE(query, 'i'); - let filteredEvents = query ? events.filter((e) => searchRe.test(e.url) || searchRe.test(e.value) || searchRe.test(e.label)) : null; - // if (filter) { - // filteredEvents = filteredEvents ? filteredEvents.filter(e => e.type === filter) : events.filter(e => e.type === filter); - // } - return state.set('filteredEvents', filteredEvents); + const filteredEvents = query ? events.filter( + (e) => searchRe.test(e.url) + || searchRe.test(e.value) + || searchRe.test(e.label) + || searchRe.test(e.type) + || (e.type === 'LOCATION' && searchRe.test('visited')) + ) : null; + + return state.set('filteredEvents', filteredEvents).set('eventsQuery', query); } case FETCH.SUCCESS: { // TODO: more common.. or TEMP diff --git a/frontend/app/duck/variables.js b/frontend/app/duck/variables.js deleted file mode 100644 index 21a0131c4..000000000 --- a/frontend/app/duck/variables.js +++ /dev/null @@ -1,9 +0,0 @@ -import Variable from 'Types/variable'; -import crudDuckGenerator from './tools/crudDuck'; - -const crudDuck = crudDuckGenerator('variable', Variable); -export const { - fetchList, fetch, init, edit, save, remove, -} = crudDuck.actions; - -export default crudDuck.reducer; diff --git a/frontend/app/mstore/userStore.ts b/frontend/app/mstore/userStore.ts index 8e8913de6..b46f776a3 100644 --- a/frontend/app/mstore/userStore.ts +++ b/frontend/app/mstore/userStore.ts @@ -44,7 +44,7 @@ export default class UserStore { } initUser(user?: any ): Promise { - return new Promise((resolve, reject) => { + return new Promise((resolve) => { if (user) { this.instance = new User().fromJson(user.toJson()); } else { @@ -54,7 +54,7 @@ export default class UserStore { }) } - updateKey(key: string, value: any) { + updateKey(key: keyof this, value: any) { this[key] = value if (key === 'searchQuery') { diff --git a/frontend/app/types/address.js b/frontend/app/types/address.js deleted file mode 100644 index 8d8e2ccf2..000000000 --- a/frontend/app/types/address.js +++ /dev/null @@ -1,20 +0,0 @@ -import Record from 'Types/Record'; - -export default Record({ - line1: '', - postal_code: '', - city: '', - state: '', - country: '', -}, { - methods: { - validate() { - return true; - }, - toData() { - const js = this.toJS(); - delete js.key; - return js; - }, - }, -}); diff --git a/frontend/app/types/appTest.js b/frontend/app/types/appTest.js deleted file mode 100644 index 248b759b7..000000000 --- a/frontend/app/types/appTest.js +++ /dev/null @@ -1,87 +0,0 @@ -import { Record, List, Set } from 'immutable'; -import { validateName } from 'App/validate'; -import { DateTime } from 'luxon'; -import Run from './run'; -import Step from './step'; - -class Test extends Record({ - testId: undefined, - name: 'Unnamed Test', - steps: List(), - stepsCount: undefined, - framework: 'selenium', - sessionId: undefined, - generated: false, - tags: Set(), - runHistory: List(), - editedAt: undefined, - seqId: undefined, - seqChange: false, - uptime: 0, -}) { - // ???TODO - // idKey = "testId" - - exists() { - return this.testId !== undefined; - } - - validate() { - if (this.steps.size === 0) return false; - - return validateName(this.name, { - empty: false, - admissibleChars: ':-', - }); - } - - isComplete() { - return this.stepsCount === this.steps.size; - } - - // not the best code - toData() { - const js = this - .update('steps', steps => steps.map(step => step.toData())) - .toJS(); - - if (js.seqChange) { - const { testId, seqId } = js; - return { testId, seqId }; - } - - delete js.stepsCount; - delete js.seqChange; - - return js; - } - // not the best code -} - -const fromJS = (test = {}) => { - if (test instanceof Test) return test; - - const stepsLength = test.steps && test.steps.length; // - const editedAt = test.editedAt ? DateTime.fromMillis(test.editedAt) : undefined; - - const lastRun = Run(test.lastRun); - const runHistory = List(test.runHistory) // TODO: GOOD ENDPOINTS - .map(run => { - if (typeof run === 'string') { - return run === lastRun.runId - ? lastRun - : Run({ runId: run }) - } - return Run(run); - }); - - return new Test({ ...test, editedAt, uptime: parseInt(test.passed / test.count * 100) || 0 }) - .set('stepsCount', typeof test.stepsCount === 'number' - ? test.stepsCount - : stepsLength) // - .set('runHistory', runHistory) - .set('steps', List(test.steps).map(Step)) - .set('tags', test.tags && Set(test.tags.map(t => t.toLowerCase()))); -}; - -export default fromJS; diff --git a/frontend/app/types/member.ts b/frontend/app/types/member.ts index d3914eac9..0a88d51ba 100644 --- a/frontend/app/types/member.ts +++ b/frontend/app/types/member.ts @@ -16,6 +16,20 @@ export interface IMember { invitationLink: string } +export interface IMemberApiRes { + userId: string + name: string + email: string + createdAt: string + admin: boolean + superAdmin: boolean + joined: boolean + expiredInvitation: boolean + roleId: string + roleName: string + invitationLink: string +} + export default Record({ id: undefined, name: '', @@ -42,9 +56,9 @@ export default Record({ return js; }, }, - fromJS: ({ createdAt, ...rest }) => ({ + fromJS: ({ createdAt, ...rest }: IMemberApiRes) => ({ ...rest, - createdAt: createdAt && DateTime.fromISO(createdAt || 0), + createdAt: createdAt && DateTime.fromISO(createdAt || '0'), id: rest.userId, }), });