From 3a636bda68eb901783d0f8520797b69ba70f2a77 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Thu, 21 Jul 2022 15:35:01 +0200 Subject: [PATCH 01/17] fix(ui) - click maps count and percentage, dropdown --- .../PageInsightsPanel/PageInsightsPanel.tsx | 178 +++++++++--------- .../components/SelectorCard/SelectorCard.tsx | 44 +++-- .../SelectorsList/SelectorsList.tsx | 41 ++-- .../StatedScreen/StatedScreen.ts | 4 +- 4 files changed, 133 insertions(+), 134 deletions(-) diff --git a/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx b/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx index cec3e1af2..03d74a247 100644 --- a/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx +++ b/frontend/app/components/Session_/PageInsightsPanel/PageInsightsPanel.tsx @@ -1,6 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Dropdown, Loader, Icon } from 'UI'; -import DateRange from 'Shared/DateRange'; +import { Loader, Icon } from 'UI'; import { connect } from 'react-redux'; import { fetchInsights } from 'Duck/sessions'; import SelectorsList from './components/SelectorsList/SelectorsList'; @@ -11,100 +10,103 @@ import Period from 'Types/app/period'; const JUMP_OFFSET = 1000; interface Props { - filters: any - fetchInsights: (filters: Record) => void - urls: [] - insights: any - events: Array - urlOptions: Array - loading: boolean - host: string - setActiveTab: (tab: string) => void + filters: any; + fetchInsights: (filters: Record) => void; + urls: []; + insights: any; + events: Array; + urlOptions: Array; + loading: boolean; + host: string; + setActiveTab: (tab: string) => void; } -function PageInsightsPanel({ - filters, fetchInsights, events = [], insights, urlOptions, host, loading = true, setActiveTab -}: Props) { - const [insightsFilters, setInsightsFilters] = useState(filters) - const defaultValue = (urlOptions && urlOptions[0]) ? urlOptions[0].value : '' +function PageInsightsPanel({ filters, fetchInsights, events = [], insights, urlOptions, host, loading = true, setActiveTab }: Props) { + const [insightsFilters, setInsightsFilters] = useState(filters); + const defaultValue = urlOptions && urlOptions[0] ? urlOptions[0].value : ''; - const period = new Period({ - start: insightsFilters.startDate, - end: insightsFilters.endDate, - rangeName: insightsFilters.rangeValue - }); + const period = Period({ + start: insightsFilters.startDate, + end: insightsFilters.endDate, + rangeName: insightsFilters.rangeValue, + }); - const onDateChange = (e) => { - const { startDate, endDate, rangeValue } = e.toJSON(); - setInsightsFilters({ ...insightsFilters, startDate, endDate, rangeValue }) - } + const onDateChange = (e: any) => { + const { startDate, endDate, rangeValue } = e.toJSON(); + setInsightsFilters({ ...insightsFilters, startDate, endDate, rangeValue }); + }; - useEffect(() => { - markTargets(insights.toJS()); - return () => { - markTargets(null) - } - }, [insights]) + useEffect(() => { + markTargets(insights.toJS()); + return () => { + markTargets(null); + }; + }, [insights]); - useEffect(() => { - if (urlOptions && urlOptions[0]) { - const url = insightsFilters.url ? insightsFilters.url : host + urlOptions[0].value; - Player.pause(); - fetchInsights({ ...insightsFilters, url }) - } - }, [insightsFilters]) + useEffect(() => { + if (urlOptions && urlOptions[0]) { + const url = insightsFilters.url ? insightsFilters.url : host + urlOptions[0].value; + Player.pause(); + fetchInsights({ ...insightsFilters, url }); + } + }, [insightsFilters]); - const onPageSelect = ({ value }: { value: Array }) => { - const event = events.find(item => item.url === value) - Player.jump(event.time + JUMP_OFFSET) - setInsightsFilters({ ...insightsFilters, url: host + value }) - markTargets([]) - }; + const onPageSelect = ({ value }: any) => { + const event = events.find((item) => item.url === value.value); + Player.jump(event.time + JUMP_OFFSET); + setInsightsFilters({ ...insightsFilters, url: host + value.value }); + markTargets([]); + }; - return ( -
-
-
- Clicks - + return ( +
+
+
+ Clicks + +
+
{ + setActiveTab(''); + }} + className="ml-auto flex items-center justify-center bg-white cursor-pointer" + > + +
+
+
+
In Page
+ -
- - - -
- ) + ); } -export default connect(state => { - const events = state.getIn([ 'sessions', 'visitedEvents' ]) - return { - filters: state.getIn(['sessions', 'insightFilters']), - host: state.getIn([ 'sessions', 'host' ]), - insights: state.getIn([ 'sessions', 'insights' ]), - events: events, - urlOptions: events.map(({ url, host }: any) => ({ label: url, value: url, host })), - loading: state.getIn([ 'sessions', 'fetchInsightsRequest', 'loading' ]), - } -}, { fetchInsights })(PageInsightsPanel); +export default connect( + (state) => { + const events = state.getIn(['sessions', 'visitedEvents']); + return { + filters: state.getIn(['sessions', 'insightFilters']), + host: state.getIn(['sessions', 'host']), + insights: state.getIn(['sessions', 'insights']), + events: events, + urlOptions: events.map(({ url, host }: any) => ({ label: url, value: url, host })), + loading: state.getIn(['sessions', 'fetchInsightsRequest', 'loading']), + }; + }, + { fetchInsights } +)(PageInsightsPanel); diff --git a/frontend/app/components/Session_/PageInsightsPanel/components/SelectorCard/SelectorCard.tsx b/frontend/app/components/Session_/PageInsightsPanel/components/SelectorCard/SelectorCard.tsx index 9007b6684..9a3ecc210 100644 --- a/frontend/app/components/Session_/PageInsightsPanel/components/SelectorCard/SelectorCard.tsx +++ b/frontend/app/components/Session_/PageInsightsPanel/components/SelectorCard/SelectorCard.tsx @@ -1,30 +1,34 @@ -import React, { useState } from 'react' -import stl from './SelectorCard.module.css' +import React, { useState } from 'react'; +import stl from './SelectorCard.module.css'; import cn from 'classnames'; import type { MarkedTarget } from 'Player/MessageDistributor/StatedScreen/StatedScreen'; import { activeTarget } from 'Player'; import { Tooltip } from 'react-tippy'; interface Props { - index?: number, - target: MarkedTarget, - showContent: boolean + index?: number; + target: MarkedTarget; + showContent: boolean; } -export default function SelectorCard({ index = 1, target, showContent } : Props) { - return ( -
activeTarget(index)}> -
- {/* @ts-ignore */} -
{index + 1}
-
{target.selector}
-
- { showContent && ( -
-
{target.count} Clicks - {target.percent}%
-
TOTAL CLICKS
+export default function SelectorCard({ index = 1, target, showContent }: Props) { + return ( +
activeTarget(index)}> +
+ {/* @ts-ignore */} + +
{index + 1}
+
+
{target.selector}
+
+ {showContent && ( +
+
+ {target.count} Clicks - {target.percent}% +
+
TOTAL CLICKS
+
+ )}
- ) } -
- ) + ); } diff --git a/frontend/app/components/Session_/PageInsightsPanel/components/SelectorsList/SelectorsList.tsx b/frontend/app/components/Session_/PageInsightsPanel/components/SelectorsList/SelectorsList.tsx index aceefb3b7..86274baba 100644 --- a/frontend/app/components/Session_/PageInsightsPanel/components/SelectorsList/SelectorsList.tsx +++ b/frontend/app/components/Session_/PageInsightsPanel/components/SelectorsList/SelectorsList.tsx @@ -1,33 +1,26 @@ -import React, { useState } from 'react' -import { NoContent } from 'UI' +import React from 'react'; +import { NoContent } from 'UI'; import { connectPlayer } from 'Player/store'; import SelectorCard from '../SelectorCard/SelectorCard'; import type { MarkedTarget } from 'Player/MessageDistributor/StatedScreen/StatedScreen'; -import stl from './selectorList.module.css' +import stl from './selectorList.module.css'; interface Props { - targets: Array, - activeTargetIndex: number + targets: Array; + activeTargetIndex: number; } -function SelectorsList({ targets, activeTargetIndex }: Props) { - return ( - -
- { targets && targets.map((target, index) => ( - - ))} -
-
- ) +function SelectorsList({ targets, activeTargetIndex }: Props) { + return ( + +
+ {targets && targets.map((target, index) => )} +
+
+ ); } - -export default connectPlayer(state => ({ - targets: state.markedTargets, - activeTargetIndex: state.activeTargetIndex, -}))(SelectorsList) +export default connectPlayer((state: any) => ({ + targets: state.markedTargets, + activeTargetIndex: state.activeTargetIndex, +}))(SelectorsList); diff --git a/frontend/app/player/MessageDistributor/StatedScreen/StatedScreen.ts b/frontend/app/player/MessageDistributor/StatedScreen/StatedScreen.ts index 5b74d9a3f..177419f35 100644 --- a/frontend/app/player/MessageDistributor/StatedScreen/StatedScreen.ts +++ b/frontend/app/player/MessageDistributor/StatedScreen/StatedScreen.ts @@ -145,9 +145,9 @@ export default class StatedScreen extends Screen { ...s, el, index: index++, - percent: 0, + percent: Math.round((s.count * 100) / totalCount), boundingRect: this.calculateRelativeBoundingRect(el), - count: Math.round((s.count * 100) / totalCount) + count: s.count, }) }); From 5262bf16bf5bc0bf82cc04838b448fb1ed406929 Mon Sep 17 00:00:00 2001 From: sylenien Date: Thu, 21 Jul 2022 16:12:05 +0200 Subject: [PATCH 02/17] fix(ui): fix clickmap card items selectors --- .../MessageDistributor/StatedScreen/Screen/BaseScreen.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts b/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts index fc52660f5..81ced7774 100644 --- a/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts +++ b/frontend/app/player/MessageDistributor/StatedScreen/Screen/BaseScreen.ts @@ -138,7 +138,8 @@ export default abstract class BaseScreen { getElementBySelector(selector: string): Element | null { if (!selector) return null; try { - return this.document?.querySelector(selector) || null; + const safeSelector = selector.replace(/:/g, '\\\\3A ').replace(/\//g, '\\/'); + return this.document?.querySelector(safeSelector) || null; } catch (e) { console.error("Can not select element. ", e) return null @@ -186,4 +187,4 @@ export default abstract class BaseScreen { clean() { window.removeEventListener('resize', this.scale); } -} \ No newline at end of file +} From e17fde7f379dd2940522204b80a6487906ec5ab4 Mon Sep 17 00:00:00 2001 From: Delirium Date: Thu, 21 Jul 2022 17:28:28 +0300 Subject: [PATCH 03/17] fix(ui): fix timezone settings (#629) --- .../SessionList/SessionListHeader.js | 26 ++++++++++++++++--- .../SelectDateRange/SelectDateRange.tsx | 17 +++++++----- .../components/shared/SessionItem/Counter.tsx | 4 +-- frontend/app/types/app/period.js | 11 +++++++- 4 files changed, 46 insertions(+), 12 deletions(-) diff --git a/frontend/app/components/BugFinder/SessionList/SessionListHeader.js b/frontend/app/components/BugFinder/SessionList/SessionListHeader.js index bf4bf8b55..5e2702639 100644 --- a/frontend/app/components/BugFinder/SessionList/SessionListHeader.js +++ b/frontend/app/components/BugFinder/SessionList/SessionListHeader.js @@ -4,7 +4,10 @@ import SortDropdown from '../Filters/SortDropdown'; import { numberWithCommas } from 'App/utils'; import SelectDateRange from 'Shared/SelectDateRange'; import { applyFilter } from 'Duck/search'; -import Period from 'Types/app/period'; +import Record from 'Types/app/period'; +import { useStore } from 'App/mstore'; +import { useObserver } from 'mobx-react-lite'; +import { moment } from 'App/dateRange'; const sortOptionsMap = { 'startTs-desc': 'Newest', @@ -15,13 +18,30 @@ const sortOptionsMap = { const sortOptions = Object.entries(sortOptionsMap).map(([value, label]) => ({ value, label })); function SessionListHeader({ activeTab, count, applyFilter, filter }) { + const { settingsStore } = useStore(); + + const label = useObserver(() => settingsStore.sessionSettings.timezone.label); + const getTimeZoneOffset = React.useCallback(() => { + return label.slice(-6); + }, [label]); + const { startDate, endDate, rangeValue } = filter; - const period = new Period({ start: startDate, end: endDate, rangeName: rangeValue }); + const period = new Record({ start: startDate, end: endDate, rangeName: rangeValue }); const onDateChange = (e) => { const dateValues = e.toJSON(); + dateValues.startDate = moment(dateValues.startDate).utcOffset(getTimeZoneOffset(), true).valueOf(); + dateValues.endDate = moment(dateValues.endDate).utcOffset(getTimeZoneOffset(), true).valueOf(); applyFilter(dateValues); }; + + React.useEffect(() => { + const dateValues = period.toJSON(); + dateValues.startDate = moment(dateValues.startDate).startOf('day').utcOffset(getTimeZoneOffset(), true).valueOf(); + dateValues.endDate = moment(dateValues.endDate).endOf('day').utcOffset(getTimeZoneOffset(), true).valueOf(); + applyFilter(dateValues); + }, [label]); + return (
@@ -32,7 +52,7 @@ function SessionListHeader({ activeTab, count, applyFilter, filter }) { {
Sessions Captured in - +
}
diff --git a/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx b/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx index 12b6ba016..da8a940a5 100644 --- a/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx +++ b/frontend/app/components/shared/SelectDateRange/SelectDateRange.tsx @@ -6,17 +6,19 @@ import { components } from 'react-select'; import DateRangePopup from 'Shared/DateRangeDropdown/DateRangePopup'; import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; import cn from 'classnames'; +import { observer } from 'mobx-react-lite'; interface Props { period: any; onChange: (data: any) => void; disableCustom?: boolean; right?: boolean; + timezone?: string; [x: string]: any; } function SelectDateRange(props: Props) { const [isCustom, setIsCustom] = React.useState(false); - const { right = false, period, disableCustom = false, ...rest } = props; + const { right = false, period, disableCustom = false, timezone, ...rest } = props; let selectedValue = DATE_RANGE_OPTIONS.find((obj: any) => obj.value === period.rangeName); const options = DATE_RANGE_OPTIONS.filter((obj: any) => (disableCustom ? obj.value !== CUSTOM_RANGE : true)); @@ -24,15 +26,20 @@ function SelectDateRange(props: Props) { if (value === CUSTOM_RANGE) { setIsCustom(true); } else { + // @ts-ignore props.onChange(new Period({ rangeName: value })); } }; const onApplyDateRange = (value: any) => { - props.onChange(new Period({ rangeName: CUSTOM_RANGE, start: value.start, end: value.end })); + // @ts-ignore + const range = new Period({ rangeName: CUSTOM_RANGE, start: value.start, end: value.end }) + props.onChange(range); setIsCustom(false); }; + const isCustomRange = period.rangeName === CUSTOM_RANGE; + const customRange = isCustomRange ? period.rangeFormatted(undefined, timezone) : ''; return (
; + } + }; - const renderFiled = () => { - switch(filter.sourceType) { - case FilterType.NUMBER: - return ( - - ) - } - } - - return ( -
- { renderFiled()} -
- ); + return
{renderFiled()}
; } -export default FilterSource; \ No newline at end of file +export default FilterSource; From b5f65cf6e62e214178f8395e98a8d2eaee10c9ad Mon Sep 17 00:00:00 2001 From: Delirium Date: Thu, 21 Jul 2022 19:35:50 +0300 Subject: [PATCH 11/17] fix(ui): set default timezone as local tz in option select (#633) --- .../components/DefaultTimezone.tsx | 28 +------ frontend/app/mstore/types/sessionSettings.ts | 74 +++++++++++++------ 2 files changed, 53 insertions(+), 49 deletions(-) diff --git a/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx b/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx index 5ee40a489..dc14f6245 100644 --- a/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx +++ b/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx @@ -8,36 +8,10 @@ import { toast } from 'react-toastify'; type TimezonesDropdown = Timezone[] -const generateGMTZones = (): TimezonesDropdown => { - const timezones: TimezonesDropdown = [] - - const positiveNumbers = [...Array(12).keys()]; - const negativeNumbers = [...Array(12).keys()].reverse(); - negativeNumbers.pop(); // remove trailing zero since we have one in positive numbers array - - const combinedArray = [...negativeNumbers, ...positiveNumbers]; - - for (let i = 0; i < combinedArray.length; i++) { - let symbol = i < 11 ? '-' : '+'; - let isUTC = i === 11 - let prefix = isUTC ? 'UTC / GMT' : 'GMT'; - let value = String(combinedArray[i]).padStart(2, '0'); - - let tz = `${prefix} ${symbol}${String(combinedArray[i]).padStart(2, '0')}:00` - - let dropdownValue = `UTC${symbol}${value}` - timezones.push({ label: tz, value: isUTC ? 'UTC' : dropdownValue }) - } - - timezones.splice(17, 0, { label: 'GMT +05:30', value: 'UTC+05:30' }) - return timezones -} - -const timezoneOptions: TimezonesDropdown = [...generateGMTZones()] - function DefaultTimezone() { const [changed, setChanged] = React.useState(false); const { settingsStore } = useStore(); + const timezoneOptions: TimezonesDropdown = settingsStore.sessionSettings.defaultTimezones; const [timezone, setTimezone] = React.useState(settingsStore.sessionSettings.timezone); const sessionSettings = useObserver(() => settingsStore.sessionSettings); diff --git a/frontend/app/mstore/types/sessionSettings.ts b/frontend/app/mstore/types/sessionSettings.ts index 47ed12917..493edd523 100644 --- a/frontend/app/mstore/types/sessionSettings.ts +++ b/frontend/app/mstore/types/sessionSettings.ts @@ -1,24 +1,54 @@ -import { makeAutoObservable, runInAction, action } from "mobx" -import { SKIP_TO_ISSUE, TIMEZONE, DURATION_FILTER } from 'App/constants/storageKeys' +import { makeAutoObservable, runInAction, action } from 'mobx'; +import moment from 'moment'; +import { SKIP_TO_ISSUE, TIMEZONE, DURATION_FILTER } from 'App/constants/storageKeys'; export type Timezone = { - label: string, - value: string, - } + label: string; + value: string; +}; + +export const generateGMTZones = (): Timezone[] => { + const timezones: Timezone[] = []; + + const positiveNumbers = [...Array(12).keys()]; + const negativeNumbers = [...Array(12).keys()].reverse(); + negativeNumbers.pop(); // remove trailing zero since we have one in positive numbers array + + const combinedArray = [...negativeNumbers, ...positiveNumbers]; + + for (let i = 0; i < combinedArray.length; i++) { + let symbol = i < 11 ? '-' : '+'; + let isUTC = i === 11; + let prefix = isUTC ? 'UTC / GMT' : 'GMT'; + let value = String(combinedArray[i]).padStart(2, '0'); + + let tz = `${prefix} ${symbol}${String(combinedArray[i]).padStart(2, '0')}:00`; + + let dropdownValue = `UTC${symbol}${value}`; + timezones.push({ label: tz, value: isUTC ? 'UTC' : dropdownValue }); + } + + timezones.splice(17, 0, { label: 'GMT +05:30', value: 'UTC+05:30' }); + return timezones; +}; export default class SessionSettings { + defaultTimezones = [...generateGMTZones()] skipToIssue: boolean = localStorage.getItem(SKIP_TO_ISSUE) === 'true'; timezone: Timezone; durationFilter: any = JSON.parse(localStorage.getItem(DURATION_FILTER) || '{}'); - captureRate: string = '0' - captureAll: boolean = false + captureRate: string = '0'; + captureAll: boolean = false; constructor() { // compatibility fix for old timezone storage // TODO: remove after a while (1.7.1?) - this.timezoneFix() - this.timezone = JSON.parse(localStorage.getItem(TIMEZONE)) || { label: 'UTC / GMT +00:00', value: 'UTC' } - makeAutoObservable(this) + const userTimezoneOffset = moment().format('Z'); + const defaultTimezone = this.defaultTimezones.find(tz => tz.value.includes('UTC' + userTimezoneOffset.slice(0,3))) || { label: 'Local', value: `UTC${userTimezoneOffset}` }; + + this.timezoneFix(defaultTimezone); + this.timezone = JSON.parse(localStorage.getItem(TIMEZONE)) || defaultTimezone; + makeAutoObservable(this); } merge = (settings: any) => { @@ -27,35 +57,35 @@ export default class SessionSettings { this.updateKey(key, settings[key]); } } - } + }; changeCaptureRate = (rate: string) => { - if (!rate) return this.captureRate = '0'; + if (!rate) return (this.captureRate = '0'); // react do no see the difference between 01 and 1 decimals, this is why we have to use string casting if (parseInt(rate, 10) <= 100) this.captureRate = `${parseInt(rate, 10)}`; - } + }; changeCaptureAll = (all: boolean) => { this.captureAll = all; - } + }; - timezoneFix() { - if (localStorage.getItem(TIMEZONE) === '[object Object]') { - localStorage.setItem(TIMEZONE, JSON.stringify({ label: 'UTC / GMT +00:00', value: 'UTC' })); + timezoneFix(defaultTimezone: Record) { + if (localStorage.getItem(TIMEZONE) === '[object Object]' || !localStorage.getItem(TIMEZONE)) { + localStorage.setItem(TIMEZONE, JSON.stringify(defaultTimezone)); } } - + updateKey = (key: string, value: any) => { runInAction(() => { - this[key] = value - }) + this[key] = value; + }); - if (key === 'captureRate' || key === 'captureAll') return + if (key === 'captureRate' || key === 'captureAll') return; if (key === 'durationFilter' || key === 'timezone') { localStorage.setItem(`__$session-${key}$__`, JSON.stringify(value)); } else { localStorage.setItem(`__$session-${key}$__`, value); } - } + }; } From 4654dccd29e3e1b7dcb0bf4c7ae5b7782990e0b9 Mon Sep 17 00:00:00 2001 From: rjshrjndrn Date: Thu, 21 Jul 2022 19:04:34 +0200 Subject: [PATCH 12/17] chore(helm): override the pvc name --- .../charts/utilities/templates/efs-cron.yaml | 6 +++--- .../openreplay/charts/utilities/values.yaml | 16 +++++++--------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml b/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml index b74b0cbad..a960ebea4 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml @@ -32,17 +32,17 @@ spec: - mountPath: /mnt/efs name: datadir restartPolicy: Never - {{- if eq .Values.pvc.name "hostPath" }} + {{- if eq .Values.efsCleaner.pvc.name "hostPath" }} volumes: - name: datadir hostPath: # Ensure the file directory is created. - path: {{ .Values.pvc.hostMountPath }} + path: {{ .Values.efsCleaner.pvc.hostMountPath }} type: DirectoryOrCreate {{- else }} volumes: - name: datadir persistentVolumeClaim: - claimName: {{ .Values.pvc.name }} + claimName: {{ .Values.efsCleaner.pvc.name }} {{- end }} diff --git a/scripts/helmcharts/openreplay/charts/utilities/values.yaml b/scripts/helmcharts/openreplay/charts/utilities/values.yaml index 17caeb5b5..49838d774 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/values.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/values.yaml @@ -9,8 +9,13 @@ efsCleaner: repository: "{{ .Values.global.openReplayContainerRegistry }}/alpine" pullPolicy: Always tag: 3.16.1 - # Overrides the image tag whose default is the chart appVersion. - tag: "" + pvc: + # This can be either persistentVolumeClaim or hostPath. + # In case of pvc, you'll have to provide the pvc name. + # For example + # name: openreplay-efs + name: hostPath + hostMountPath: /openreplay/storage/nfs telemetry: # https://crontab.guru/#5_12_*_*_* @@ -78,10 +83,3 @@ fullnameOverride: "utilities-openreplay" # refer: https://crontab.guru/#5_3_*_*_1 cron: "5 3 * * 1" -pvc: - # This can be either persistentVolumeClaim or hostPath. - # In case of pvc, you'll have to provide the pvc name. - # For example - # name: openreplay-efs - name: hostPath - hostMountPath: /openreplay/storage/nfs From 4f5c16896695368882e66da2373648d0a5e1d8a6 Mon Sep 17 00:00:00 2001 From: rjshrjndrn Date: Thu, 21 Jul 2022 19:17:12 +0200 Subject: [PATCH 13/17] chore(helm): change job backoff policy Signed-off-by: rjshrjndrn --- .../openreplay/charts/utilities/templates/efs-cron.yaml | 2 ++ .../openreplay/charts/utilities/templates/report-cron.yaml | 1 + .../charts/utilities/templates/sessions-cleaner-cron.yaml | 1 + .../openreplay/charts/utilities/templates/telemetry-cron.yaml | 1 + 4 files changed, 5 insertions(+) diff --git a/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml b/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml index a960ebea4..d27a678da 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml @@ -9,8 +9,10 @@ spec: successfulJobsHistoryLimit: 1 jobTemplate: spec: + backoffLimit: 0 # Don't restart the failed jobs template: spec: + restartPolicy: Never containers: - name: efs-cleaner image: alpine diff --git a/scripts/helmcharts/openreplay/charts/utilities/templates/report-cron.yaml b/scripts/helmcharts/openreplay/charts/utilities/templates/report-cron.yaml index 350de8c12..678c15111 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/templates/report-cron.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/templates/report-cron.yaml @@ -10,6 +10,7 @@ spec: successfulJobsHistoryLimit: 1 jobTemplate: spec: + backoffLimit: 0 # Don't restart the failed jobs template: spec: restartPolicy: Never diff --git a/scripts/helmcharts/openreplay/charts/utilities/templates/sessions-cleaner-cron.yaml b/scripts/helmcharts/openreplay/charts/utilities/templates/sessions-cleaner-cron.yaml index 47246a5bd..2d625e97f 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/templates/sessions-cleaner-cron.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/templates/sessions-cleaner-cron.yaml @@ -10,6 +10,7 @@ spec: successfulJobsHistoryLimit: 1 jobTemplate: spec: + backoffLimit: 0 # Don't restart the failed jobs template: spec: restartPolicy: Never diff --git a/scripts/helmcharts/openreplay/charts/utilities/templates/telemetry-cron.yaml b/scripts/helmcharts/openreplay/charts/utilities/templates/telemetry-cron.yaml index 74d24b624..57de6ce90 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/templates/telemetry-cron.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/templates/telemetry-cron.yaml @@ -10,6 +10,7 @@ spec: successfulJobsHistoryLimit: 1 jobTemplate: spec: + backoffLimit: 0 # Don't restart the failed jobs template: spec: restartPolicy: Never From 8e52ee610d12732d837ec0f10991298e8c9204a8 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Thu, 21 Jul 2022 20:19:29 +0200 Subject: [PATCH 14/17] feat(chalice): changed pg helper feat(crons): changed pg helper feat(alerts): changed pg helper --- api/chalicelib/utils/pg_client.py | 8 +++++--- api/routers/core.py | 3 ++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/api/chalicelib/utils/pg_client.py b/api/chalicelib/utils/pg_client.py index 2abc9f6c7..eda7747f8 100644 --- a/api/chalicelib/utils/pg_client.py +++ b/api/chalicelib/utils/pg_client.py @@ -75,9 +75,11 @@ class PostgresClient: connection = None cursor = None long_query = False + unlimited_query = False def __init__(self, long_query=False, unlimited_query=False): self.long_query = long_query + self.unlimited_query = unlimited_query if unlimited_query: long_config = dict(_PG_CONFIG) long_config["application_name"] += "-UNLIMITED" @@ -85,7 +87,7 @@ class PostgresClient: elif long_query: long_config = dict(_PG_CONFIG) long_config["application_name"] += "-LONG" - long_config["options"] = f"-c statement_timeout={config('pg_long_timeout', cast=int, default=5*60) * 1000}" + long_config["options"] = f"-c statement_timeout={config('pg_long_timeout', cast=int, default=5 * 60) * 1000}" self.connection = psycopg2.connect(**long_config) else: self.connection = postgreSQL_pool.getconn() @@ -99,11 +101,11 @@ class PostgresClient: try: self.connection.commit() self.cursor.close() - if self.long_query: + if self.long_query or self.unlimited_query: self.connection.close() except Exception as error: print("Error while committing/closing PG-connection", error) - if str(error) == "connection already closed": + if str(error) == "connection already closed" and not self.long_query and not self.unlimited_query: print("Recreating the connexion pool") make_pool() else: diff --git a/api/routers/core.py b/api/routers/core.py index df98c1c09..2c3ff5b90 100644 --- a/api/routers/core.py +++ b/api/routers/core.py @@ -1171,4 +1171,5 @@ def get_limits(context: schemas.CurrentContext = Depends(OR_context)): @public_app.put('/', tags=["health"]) @public_app.delete('/', tags=["health"]) def health_check(): - return {"data": f"live {config('version_number', default='')}"} + return {"data": {"stage": f"live {config('version_number', default='')}", + "internalCrons": config("LOCAL_CRONS", default=False, cast=bool)}} From 4355829e16e45fe3c75830bd8899ccce9a05d85f Mon Sep 17 00:00:00 2001 From: rjshrjndrn Date: Fri, 22 Jul 2022 10:35:56 +0200 Subject: [PATCH 15/17] chore(helm): efs cleaner enable verbose output Signed-off-by: rjshrjndrn --- .../openreplay/charts/utilities/templates/efs-cron.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml b/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml index d27a678da..233025bf2 100644 --- a/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml +++ b/scripts/helmcharts/openreplay/charts/utilities/templates/efs-cron.yaml @@ -23,6 +23,7 @@ spec: args: - | # Delete all the files older than 7 days + set -x echo "Cleaning NFS strorage for data older than 7 days" storage=`du -sh /mnt/efs` find /mnt/efs -type f -mtime +7 -delete From f038cf1dea3cdb089955b2e79d3d26f651521160 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Fri, 22 Jul 2022 15:11:11 +0200 Subject: [PATCH 16/17] change(ui) - performance filters show unit --- .../shared/Filters/FilterItem/FilterItem.tsx | 18 +++++++++--------- .../FilterSource/FilterSource.module.css | 2 +- .../Filters/FilterSource/FilterSource.tsx | 12 +++++++++--- .../shared/Filters/FilterValue/FilterValue.tsx | 4 +++- frontend/app/types/filter/newFilter.js | 11 ++++++----- 5 files changed, 28 insertions(+), 19 deletions(-) diff --git a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx index 154e862a7..3d82dae7c 100644 --- a/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx +++ b/frontend/app/components/shared/Filters/FilterItem/FilterItem.tsx @@ -10,7 +10,7 @@ import SubFilterItem from '../SubFilterItem'; interface Props { filterIndex: number; filter: any; // event/filter - onUpdate: (filter) => void; + onUpdate: (filter: any) => void; onRemoveFilter: () => void; isFilter?: boolean; saveRequestPayloads?: boolean; @@ -20,26 +20,26 @@ function FilterItem(props: Props) { const canShowValues = !(filter.operator === 'isAny' || filter.operator === 'onAny' || filter.operator === 'isUndefined'); const isSubFilter = filter.type === FilterType.SUB_FILTERS; - const replaceFilter = (filter) => { + const replaceFilter = (filter: any) => { props.onUpdate({ ...filter, value: [''], - filters: filter.filters ? filter.filters.map((i) => ({ ...i, value: [''] })) : [], + filters: filter.filters ? filter.filters.map((i: any) => ({ ...i, value: [''] })) : [], }); }; - const onOperatorChange = (e, { name, value }) => { + const onOperatorChange = (e: any, { name, value }: any) => { props.onUpdate({ ...filter, operator: value.value }); }; - const onSourceOperatorChange = (e, { name, value }) => { + const onSourceOperatorChange = (e: any, { name, value }: any) => { props.onUpdate({ ...filter, sourceOperator: value.value }); }; - const onUpdateSubFilter = (subFilter, subFilterIndex) => { + const onUpdateSubFilter = (subFilter: any, subFilterIndex: any) => { props.onUpdate({ ...filter, - filters: filter.filters.map((i, index) => { + filters: filter.filters.map((i: any, index: any) => { if (index === subFilterIndex) { return subFilter; } @@ -90,8 +90,8 @@ function FilterItem(props: Props) { {isSubFilter && (
{filter.filters - .filter((i) => (i.key !== FilterKey.FETCH_REQUEST_BODY && i.key !== FilterKey.FETCH_RESPONSE_BODY) || saveRequestPayloads) - .map((subFilter, subFilterIndex) => ( + .filter((i: any) => (i.key !== FilterKey.FETCH_REQUEST_BODY && i.key !== FilterKey.FETCH_RESPONSE_BODY) || saveRequestPayloads) + .map((subFilter: any, subFilterIndex: any) => ( void; + onUpdate: (filter: any) => void; } function FilterSource(props: Props) { const { filter } = props; const [value, setValue] = useState(filter.source[0] || ''); - const debounceUpdate: any = React.useCallback(debounce(props.onUpdate, 1000), []); + const debounceUpdate: any = React.useCallback(debounce(props.onUpdate, 1000), [props.onUpdate]); useEffect(() => { setValue(filter.source[0] || ''); @@ -25,7 +26,12 @@ function FilterSource(props: Props) { const renderFiled = () => { switch (filter.sourceType) { case FilterType.NUMBER: - return ; + return ( +
+ +
{filter.sourceUnit}
+
+ ); } }; diff --git a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx index 29dce323d..5638f9a1d 100644 --- a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx +++ b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx @@ -6,6 +6,7 @@ import FilterValueDropdown from '../FilterValueDropdown'; import FilterDuration from '../FilterDuration'; import { debounce } from 'App/utils'; import { assist as assistRoute, isRoute } from 'App/routes'; +import cn from 'classnames'; const ASSIST_ROUTE = assistRoute(); @@ -172,7 +173,8 @@ function FilterValue(props: Props) { }; return ( -
+ // +
{filter.type === FilterType.DURATION ? renderValueFiled(filter.value, 0) : filter.value && diff --git a/frontend/app/types/filter/newFilter.js b/frontend/app/types/filter/newFilter.js index 9034eba6f..9a87da2c6 100644 --- a/frontend/app/types/filter/newFilter.js +++ b/frontend/app/types/filter/newFilter.js @@ -44,11 +44,11 @@ export const filters = [ { key: FilterKey.USERANONYMOUSID, type: FilterType.MULTIPLE, category: FilterCategory.USER, label: 'User AnonymousId', operator: 'is', operatorOptions: filterOptions.stringOperators, icon: 'filters/userid' }, // PERFORMANCE - { key: FilterKey.DOM_COMPLETE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'DOM Complete', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/dom-complete', isEvent: true, hasSource: true, sourceOperator: '>=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, - { key: FilterKey.LARGEST_CONTENTFUL_PAINT_TIME, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Largest Contentful Paint', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/lcpt', isEvent: true, hasSource: true, sourceOperator: '>=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, - { key: FilterKey.TTFB, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Time to First Byte', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/ttfb', isEvent: true, hasSource: true, sourceOperator: '>=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, - { key: FilterKey.AVG_CPU_LOAD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg CPU Load', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/cpu-load', isEvent: true, hasSource: true, sourceOperator: '>=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, - { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg Memory Usage', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/memory-load', isEvent: true, hasSource: true, sourceOperator: '>=', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, + { key: FilterKey.DOM_COMPLETE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'DOM Complete', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/dom-complete', isEvent: true, hasSource: true, sourceOperator: '>=', sourceUnit: 'ms', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, + { key: FilterKey.LARGEST_CONTENTFUL_PAINT_TIME, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Largest Contentful Paint', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/lcpt', isEvent: true, hasSource: true, sourceOperator: '>=', sourceUnit: 'ms', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, + { key: FilterKey.TTFB, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Time to First Byte', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/ttfb', isEvent: true, hasSource: true, sourceOperator: '>=', sourceUnit: 'ms', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, + { key: FilterKey.AVG_CPU_LOAD, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg CPU Load', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/cpu-load', isEvent: true, hasSource: true, sourceOperator: '>=', sourceUnit: '%', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, + { key: FilterKey.AVG_MEMORY_USAGE, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Avg Memory Usage', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, source: [], icon: 'filters/memory-load', isEvent: true, hasSource: true, sourceOperator: '>=', sourceUnit: 'mb', sourceType: FilterType.NUMBER, sourceOperatorOptions: filterOptions.customOperators }, { key: FilterKey.FETCH_FAILED, type: FilterType.MULTIPLE, category: FilterCategory.PERFORMANCE, label: 'Failed Request', operator: 'isAny', operatorOptions: filterOptions.stringOperatorsPerformance, icon: 'filters/fetch-failed', isEvent: true }, { key: FilterKey.ISSUE, type: FilterType.ISSUE, category: FilterCategory.JAVASCRIPT, label: 'Issue', operator: 'is', operatorOptions: filterOptions.getOperatorsByKeys(['is', 'isAny', 'isNot']), icon: 'filters/click', options: filterOptions.issueOptions }, ]; @@ -142,6 +142,7 @@ export default Record({ source: [""], sourceType: '', sourceOperator: '=', + sourceUnit: '', sourceOperatorOptions: [], operator: '', From 7d419225a0ffb580f5f04126f92db89ed00071ab Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Fri, 22 Jul 2022 16:30:34 +0200 Subject: [PATCH 17/17] feat(chalice): changed configuration feat(crons): changed configuration feat(alerts): changed configuration --- api/app.py | 2 +- api/app_alerts.py | 2 +- ee/api/app.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/api/app.py b/api/app.py index 959f1ef8f..4fd042d1a 100644 --- a/api/app.py +++ b/api/app.py @@ -13,7 +13,7 @@ from routers.crons import core_crons from routers.crons import core_dynamic_crons from routers.subs import dashboard, insights, metrics, v1_api -app = FastAPI(root_path="/api") +app = FastAPI(root_path="/api", docs_url=config("docs_url", default=""), redoc_url=config("redoc_url", default="")) @app.middleware('http') diff --git a/api/app_alerts.py b/api/app_alerts.py index 57bfcd55d..4e05ab1a8 100644 --- a/api/app_alerts.py +++ b/api/app_alerts.py @@ -6,7 +6,7 @@ from fastapi import FastAPI from chalicelib.core import alerts_processor -app = FastAPI() +app = FastAPI(root_path="/alerts", docs_url=config("docs_url", default=""), redoc_url=config("redoc_url", default="")) print("============= ALERTS =============") diff --git a/ee/api/app.py b/ee/api/app.py index 505f1393c..1e12e6015 100644 --- a/ee/api/app.py +++ b/ee/api/app.py @@ -16,7 +16,7 @@ from routers.crons import core_crons from routers.crons import core_dynamic_crons from routers.subs import dashboard, insights, metrics, v1_api_ee -app = FastAPI(root_path="/api") +app = FastAPI(root_path="/api", docs_url=config("docs_url", default=""), redoc_url=config("redoc_url", default="")) @app.middleware('http')