From 9979399fc8234b01914d904b12f031cca71581b6 Mon Sep 17 00:00:00 2001 From: Rajesh Rajendran Date: Mon, 6 Mar 2023 17:06:33 +0100 Subject: [PATCH 1/9] chore(init): Overwrite existing directory (#1017) cho Signed-off-by: rjshrjndrn --- scripts/helmcharts/init.sh | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/helmcharts/init.sh b/scripts/helmcharts/init.sh index 69a6944b2..525a00a82 100644 --- a/scripts/helmcharts/init.sh +++ b/scripts/helmcharts/init.sh @@ -175,8 +175,14 @@ function main() { install_openreplay sudo mkdir -p /var/lib/openreplay sudo cp -f openreplay-cli /bin/openreplay - sudo cp -rf ../../../openreplay /var/lib/openreplay - sudo cp -f vars.yaml /var/lib/openreplay + [[ ! -d /var/lib/openreplay/openreplay ]] || { + cd /var/lib/openreplay/openreplay + date +%m-%d-%Y-%H%M%S | sudo tee -a /var/lib/openreplay/or_versions.txt + sudo git log -1 2>&1 | sudo tee -a /var/lib/openreplay/or_versions.txt + sudo rm -rf /var/lib/openreplay/openreplay + cd - + } + sudo cp -rf $(cd ../.. && pwd) /var/lib/openreplay/openreplay } } From 45a585d110ed05b76c07a45442e73e8501d60b62 Mon Sep 17 00:00:00 2001 From: Shekar Siri Date: Tue, 7 Mar 2023 09:09:12 +0100 Subject: [PATCH 2/9] fix(ui) - events tab checking for payload --- frontend/app/types/session/stackEvent.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/app/types/session/stackEvent.ts b/frontend/app/types/session/stackEvent.ts index 8ce375fc2..8bbea2778 100644 --- a/frontend/app/types/session/stackEvent.ts +++ b/frontend/app/types/session/stackEvent.ts @@ -58,7 +58,7 @@ export default class StackEvent { level: IStackEvent["level"]; constructor(evt: IStackEvent) { - const event = { ...evt, source: evt.source || OPENREPLAY } + const event = { ...evt, source: evt.source || OPENREPLAY, payload: evt.payload || {} }; Object.assign(this, { ...event, isRed: isRed(event), From 67e8ad209e5281b73d2ca945c02fcaae75736070 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Tue, 7 Mar 2023 12:15:58 +0100 Subject: [PATCH 3/9] fix(ui) - player --- frontend/app/player/web/MessageManager.ts | 38 +++++++++++++---------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/frontend/app/player/web/MessageManager.ts b/frontend/app/player/web/MessageManager.ts index 330d1c861..2752d8bab 100644 --- a/frontend/app/player/web/MessageManager.ts +++ b/frontend/app/player/web/MessageManager.ts @@ -196,7 +196,7 @@ export default class MessageManager { async loadMessages(isClickmap: boolean = false) { this.setMessagesLoading(true) // TODO: reusable decryptor instance - const createNewParser = (shouldDecrypt = true) => { + const createNewParser = (shouldDecrypt = true, file) => { const decrypt = shouldDecrypt && this.session.fileKey ? (b: Uint8Array) => decryptSessionBytes(b, this.session.fileKey) : (b: Uint8Array) => Promise.resolve(b) @@ -206,11 +206,21 @@ export default class MessageManager { fileReader.append(b) const msgs: Array = [] for (let msg = fileReader.readNext();msg !== null;msg = fileReader.readNext()) { - this.distributeMessage(msg, msg._index) msgs.push(msg) } + const sorted = msgs.sort((m1, m2) => m1.time - m2.time) + + let indx = sorted[0]._index + let counter = 0 + sorted.forEach(msg => { + if (indx > msg._index) counter++ + else indx = msg._index + this.distributeMessage(msg, msg._index) + }) + + if (counter > 0) console.warn("Unsorted mob file, error count: ", counter) + logger.info("Messages count: ", msgs.length, sorted, file) - logger.info("Messages count: ", msgs.length, msgs) this._sortMessagesHack(msgs) this.setMessagesLoading(false) }) @@ -219,8 +229,8 @@ export default class MessageManager { this.waitingForFiles = true const loadMethod = this.session.domURL && this.session.domURL.length > 0 - ? { url: this.session.domURL, parser: createNewParser } - : { url: this.session.mobsUrl, parser: () => createNewParser(false)} + ? { url: this.session.domURL, parser: () => createNewParser(true, 'dom') } + : { url: this.session.mobsUrl, parser: () => createNewParser(false, 'dom')} loadFiles(loadMethod.url, loadMethod.parser()) // EFS fallback @@ -235,11 +245,11 @@ export default class MessageManager { // load devtools (TODO: start after the first DOM file download) if (isClickmap) return; this.state.update({ devtoolsLoading: true }) - loadFiles(this.session.devtoolsURL, createNewParser()) + loadFiles(this.session.devtoolsURL, createNewParser(true, 'devtools')) // EFS fallback .catch(() => requestEFSDevtools(this.session.sessionId) - .then(createNewParser(false)) + .then(createNewParser(false, 'devtools')) ) .then(() => { this.state.update(this.lists.getFullListsState()) // TODO: also in case of dynamic update through assist @@ -406,11 +416,8 @@ export default class MessageManager { this.lists.lists.fetch.insert(getResourceFromNetworkRequest(msg, this.sessionStart)) break; case MType.Redux: - decoded = this.decodeStateMessage(msg, ["state", "action"]); - logger.log('redux', decoded) - if (decoded != null) { - this.lists.lists.redux.append(decoded); - } + // logger.log('redux', msg) + this.lists.lists.redux.append(msg); break; case MType.NgRx: decoded = this.decodeStateMessage(msg, ["state", "action"]); @@ -420,11 +427,8 @@ export default class MessageManager { } break; case MType.Vuex: - decoded = this.decodeStateMessage(msg, ["state", "mutation"]); - logger.log('vuex', decoded) - if (decoded != null) { - this.lists.lists.vuex.append(decoded); - } + // logger.log('vuex', msg) + this.lists.lists.vuex.append(msg); break; case MType.Zustand: decoded = this.decodeStateMessage(msg, ["state", "mutation"]) From 3185eace860b8f9e8701c206045450c405ac1620 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Tue, 7 Mar 2023 12:18:43 +0100 Subject: [PATCH 4/9] fix(ui) - player --- frontend/app/player/web/MessageManager.ts | 38 +++++++++-------------- 1 file changed, 14 insertions(+), 24 deletions(-) diff --git a/frontend/app/player/web/MessageManager.ts b/frontend/app/player/web/MessageManager.ts index 2752d8bab..c54b86fb8 100644 --- a/frontend/app/player/web/MessageManager.ts +++ b/frontend/app/player/web/MessageManager.ts @@ -107,7 +107,7 @@ export default class MessageManager { private scrollManager: ListWalker = new ListWalker(); - private readonly decoder = new Decoder(); + public readonly decoder = new Decoder(); private readonly lists: Lists; private activityManager: ActivityManager | null = null; @@ -211,14 +211,14 @@ export default class MessageManager { const sorted = msgs.sort((m1, m2) => m1.time - m2.time) let indx = sorted[0]._index - let counter = 0 + let outOfOrderCounter = 0 sorted.forEach(msg => { - if (indx > msg._index) counter++ + if (indx > msg._index) outOfOrderCounter++ else indx = msg._index this.distributeMessage(msg, msg._index) }) - if (counter > 0) console.warn("Unsorted mob file, error count: ", counter) + if (outOfOrderCounter > 0) console.warn("Unsorted mob file, error count: ", outOfOrderCounter) logger.info("Messages count: ", msgs.length, sorted, file) this._sortMessagesHack(msgs) @@ -236,7 +236,7 @@ export default class MessageManager { // EFS fallback .catch((e) => requestEFSDom(this.session.sessionId) - .then(createNewParser(false)) + .then(createNewParser(false, 'domEFS')) ) .then(this.onFileReadSuccess) .catch(this.onFileReadFailed) @@ -249,7 +249,7 @@ export default class MessageManager { // EFS fallback .catch(() => requestEFSDevtools(this.session.sessionId) - .then(createNewParser(false, 'devtools')) + .then(createNewParser(false, 'devtoolsEFS')) ) .then(() => { this.state.update(this.lists.getFullListsState()) // TODO: also in case of dynamic update through assist @@ -416,33 +416,19 @@ export default class MessageManager { this.lists.lists.fetch.insert(getResourceFromNetworkRequest(msg, this.sessionStart)) break; case MType.Redux: - // logger.log('redux', msg) this.lists.lists.redux.append(msg); break; case MType.NgRx: - decoded = this.decodeStateMessage(msg, ["state", "action"]); - logger.log('ngrx', decoded) - if (decoded != null) { - this.lists.lists.ngrx.append(decoded); - } + this.lists.lists.ngrx.append(msg); break; case MType.Vuex: - // logger.log('vuex', msg) this.lists.lists.vuex.append(msg); break; case MType.Zustand: - decoded = this.decodeStateMessage(msg, ["state", "mutation"]) - logger.log('zustand', decoded) - if (decoded != null) { - this.lists.lists.zustand.append(decoded) - } + this.lists.lists.zustand.append(msg) + break case MType.MobX: - decoded = this.decodeStateMessage(msg, ["payload"]); - logger.log('mobx', decoded) - - if (decoded != null) { - this.lists.lists.mobx.append(decoded); - } + this.lists.lists.mobx.append(msg); break; case MType.GraphQl: this.lists.lists.graphql.append(msg); @@ -482,6 +468,10 @@ export default class MessageManager { this.state.update({ messagesLoading, ready: !messagesLoading && !this.state.get().cssLoading }); } + decodeMessage(msg: Message) { + return this.decoder.decode(msg) + } + private setSize({ height, width }: { height: number, width: number }) { this.screen.scale({ height, width }); this.state.update({ width, height }); From d047570eb936c29f0820ded4177bd8ac94f6a1ea Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 8 Mar 2023 12:49:32 +0100 Subject: [PATCH 5/9] fix(player): fix clickmap session size? --- .../app/components/Session/Player/ClickMapRenderer/Renderer.tsx | 1 - frontend/app/player/web/Screen/Screen.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx b/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx index 8a51717e5..29da5800c 100644 --- a/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx +++ b/frontend/app/components/Session/Player/ClickMapRenderer/Renderer.tsx @@ -16,7 +16,6 @@ function Player() { } }, []); - if (!playerContext.player) return null; return ( diff --git a/frontend/app/player/web/Screen/Screen.ts b/frontend/app/player/web/Screen/Screen.ts index cca56d402..377f704ed 100644 --- a/frontend/app/player/web/Screen/Screen.ts +++ b/frontend/app/player/web/Screen/Screen.ts @@ -218,7 +218,7 @@ export default class Screen { case ScaleMode.AdjustParentHeight: this.scaleRatio = offsetWidth / width translate = "translate(-50%, 0)" - posStyles = { top: 0, height: this.document!.documentElement.getBoundingClientRect().height + 'px', } + posStyles = { top: 0, height: height + 'px', } break; } From 022928d082ae0233189b1e164380df40f6f0cf72 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 8 Mar 2023 15:30:22 +0100 Subject: [PATCH 6/9] fix(player): fix clickmap url filtering, fix clickmap highliter --- .../CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx | 8 +++----- frontend/app/player/web/addons/TargetMarker.ts | 2 +- frontend/app/player/web/addons/clickmapStyles.ts | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx index e8ff709c9..c77dbcd95 100644 --- a/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx +++ b/frontend/app/components/Dashboard/Widgets/CustomMetricsWidgets/ClickMapCard/ClickMapCard.tsx @@ -20,6 +20,7 @@ function ClickMapCard({ const onMarkerClick = (s: string, innerText: string) => { metricStore.changeClickMapSearch(s, innerText) } + const mapUrl = metricStore.instance.series[0].filter.filters[0].value[0] React.useEffect(() => { return () => clearCurrentSession() @@ -32,12 +33,10 @@ function ClickMapCard({ React.useEffect(() => { if (visitedEvents.length) { - const urlOptions = visitedEvents.map(({ url, host }: any) => ({ label: url, value: url, host })) - const url = insightsFilters.url ? insightsFilters.url : host + urlOptions[0].value; const rangeValue = dashboardStore.drillDownPeriod.rangeValue const startDate = dashboardStore.drillDownPeriod.start const endDate = dashboardStore.drillDownPeriod.end - fetchInsights({ ...insightsFilters, url, startDate, endDate, rangeValue, clickRage: metricStore.clickMapFilter }) + fetchInsights({ ...insightsFilters, url: mapUrl || '/', startDate, endDate, rangeValue, clickRage: metricStore.clickMapFilter }) } }, [visitedEvents, metricStore.clickMapFilter]) @@ -62,9 +61,8 @@ function ClickMapCard({ return
Loading session
} - const searchUrl = metricStore.instance.series[0].filter.filters[0].value[0] const jumpToEvent = metricStore.instance.data.events.find((evt: Record) => { - if (searchUrl) return evt.path.includes(searchUrl) + if (mapUrl) return evt.path.includes(mapUrl) return evt }) || { timestamp: metricStore.instance.data.startTs } diff --git a/frontend/app/player/web/addons/TargetMarker.ts b/frontend/app/player/web/addons/TargetMarker.ts index 6629ceaec..452ddd00f 100644 --- a/frontend/app/player/web/addons/TargetMarker.ts +++ b/frontend/app/player/web/addons/TargetMarker.ts @@ -240,7 +240,7 @@ export default class TargetMarker { }) } - Object.assign(smallClicksBubble.style, clickmapStyles.clicks({ top, height, isRage: s.clickRage })) + Object.assign(smallClicksBubble.style, clickmapStyles.clicks({ top, height, isRage: s.clickRage, left })) border.appendChild(smallClicksBubble) overlay.appendChild(bubbleContainer) diff --git a/frontend/app/player/web/addons/clickmapStyles.ts b/frontend/app/player/web/addons/clickmapStyles.ts index 0ab795ea0..f0dc65a9c 100644 --- a/frontend/app/player/web/addons/clickmapStyles.ts +++ b/frontend/app/player/web/addons/clickmapStyles.ts @@ -16,7 +16,7 @@ export const clickmapStyles = { }, bubbleContainer: ({ top, left, height }: { top: number; left: number, height: number }) => ({ position: 'absolute', - top: top > 20 ? top + 'px' : height + 2 + 'px', + top: top > 75 ? top + 'px' : height+75 + 'px', width: '250px', left: `${left}px`, padding: '10px', @@ -51,9 +51,9 @@ export const clickmapStyles = { position: 'absolute', zIndex, }), - clicks: ({ top, height, isRage }: { top: number; height: number, isRage?: boolean }) => ({ + clicks: ({ top, height, isRage, left }: { top: number; height: number, isRage?: boolean, left: number }) => ({ top: top > 20 ? 0 : `${height}px`, - left: 0, + left: left < 5 ? '100%' : 0, position: 'absolute', borderRadius: '999px', padding: '6px', From 604b095b63c55d65ba73f205d0e0919fb9c56327 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 8 Mar 2023 16:13:56 +0100 Subject: [PATCH 7/9] 986b5a8802ec953f9035b16e87b47425bb6249f9 resolved conflicts --- frontend/app/player/web/Screen/Screen.ts | 3 +-- tracker/tracker/CHANGELOG.md | 5 ++++- tracker/tracker/package.json | 3 ++- tracker/tracker/src/main/modules/mouse.ts | 27 ++++++++--------------- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/frontend/app/player/web/Screen/Screen.ts b/frontend/app/player/web/Screen/Screen.ts index 377f704ed..f27a251f1 100644 --- a/frontend/app/player/web/Screen/Screen.ts +++ b/frontend/app/player/web/Screen/Screen.ts @@ -3,7 +3,6 @@ import Cursor from './Cursor' import type { Point, Dimensions } from './types'; - export type State = Dimensions export const INITIAL_STATE: State = { @@ -182,7 +181,7 @@ export default class Screen { getElementBySelector(selector: string) { if (!selector) return null; try { - const safeSelector = selector.replace(/:/g, '\\\\3A ').replace(/\//g, '\\/'); + const safeSelector = selector.replace(/\//g, '\\/'); return this.document?.querySelector(safeSelector) || null; } catch (e) { console.error("Can not select element. ", e) diff --git a/tracker/tracker/CHANGELOG.md b/tracker/tracker/CHANGELOG.md index 559e4e865..e3a4c3d78 100644 --- a/tracker/tracker/CHANGELOG.md +++ b/tracker/tracker/CHANGELOG.md @@ -1,4 +1,7 @@ -## 5.0.0 +## 5.0.1 + +- Default text input mode is now Obscured +- Use `@medv/finder` instead of our own implementation of `getSelector` for better clickmaps experience - Added "tel" to supported input types - Added `{ withCurrentTime: true }` to `tracker.getSessionURL` method which will return sessionURL with current session's timestamp diff --git a/tracker/tracker/package.json b/tracker/tracker/package.json index c45c15e4a..326b45575 100644 --- a/tracker/tracker/package.json +++ b/tracker/tracker/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker", "description": "The OpenReplay tracker main package", - "version": "5.0.0", + "version": "5.0.1-beta.1", "keywords": [ "logging", "replay" @@ -47,6 +47,7 @@ "typescript": "^4.9.4" }, "dependencies": { + "@medv/finder": "^3.0.0", "error-stack-parser": "^2.0.6" }, "engines": { diff --git a/tracker/tracker/src/main/modules/mouse.ts b/tracker/tracker/src/main/modules/mouse.ts index b00d6d304..2b32a99d7 100644 --- a/tracker/tracker/src/main/modules/mouse.ts +++ b/tracker/tracker/src/main/modules/mouse.ts @@ -3,26 +3,17 @@ import { hasTag, isSVGElement, isDocument } from '../app/guards.js' import { normSpaces, hasOpenreplayAttribute, getLabelAttribute } from '../utils.js' import { MouseMove, MouseClick } from '../app/messages.gen.js' import { getInputLabel } from './input.js' +import { finder } from '@medv/finder' function _getSelector(target: Element, document: Document): string { - let el: Element | null = target - let selector: string | null = null - do { - if (el.id) { - return `#${el.id}` + (selector ? ` > ${selector}` : '') - } - selector = - el.className - .split(' ') - .map((cn) => cn.trim()) - .filter((cn) => cn !== '') - .reduce((sel, cn) => `${sel}.${cn}`, el.tagName.toLowerCase()) + - (selector ? ` > ${selector}` : '') - if (el === document.body) { - return selector - } - el = el.parentElement - } while (el !== document.body && el !== null) + const selector = finder(target, { + root: document.body, + seedMinLength: 3, + optimizedMinLength: 2, + threshold: 1000, + maxNumberOfTries: 10_000, + }) + return selector } From 8c14743425dbb45b8089b37aae4bdbc3caf7b6a9 Mon Sep 17 00:00:00 2001 From: nick-delirium Date: Wed, 8 Mar 2023 16:41:49 +0100 Subject: [PATCH 8/9] fix(player): track tr th clicks for map --- third-party.md | 2 +- tracker/tracker/package.json | 2 +- tracker/tracker/src/main/modules/mouse.ts | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/third-party.md b/third-party.md index e0b68d9f6..0cfe2cac2 100644 --- a/third-party.md +++ b/third-party.md @@ -115,4 +115,4 @@ Below is the list of dependencies used in OpenReplay software. Licenses may chan | yq | MIT | Infrastructure | | html2canvas | MIT | JavaScript | | eget | MIT | Infrastructure | - +| @medv/finder | MIT | JavaScript | diff --git a/tracker/tracker/package.json b/tracker/tracker/package.json index 326b45575..a67073cc9 100644 --- a/tracker/tracker/package.json +++ b/tracker/tracker/package.json @@ -1,7 +1,7 @@ { "name": "@openreplay/tracker", "description": "The OpenReplay tracker main package", - "version": "5.0.1-beta.1", + "version": "5.0.1-beta.2", "keywords": [ "logging", "replay" diff --git a/tracker/tracker/src/main/modules/mouse.ts b/tracker/tracker/src/main/modules/mouse.ts index 2b32a99d7..155a14a8d 100644 --- a/tracker/tracker/src/main/modules/mouse.ts +++ b/tracker/tracker/src/main/modules/mouse.ts @@ -24,6 +24,8 @@ function isClickable(element: Element): boolean { tag === 'A' || tag === 'LI' || tag === 'SELECT' || + tag === 'TR' || + tag === 'TH' || (element as HTMLElement).onclick != null || element.getAttribute('role') === 'button' ) From b9d5daf9ca329af2ed7416dedd9abacfff05a692 Mon Sep 17 00:00:00 2001 From: Taha Yassine Kraiem Date: Wed, 8 Mar 2023 17:06:43 +0100 Subject: [PATCH 9/9] feat(chalice): funnels fixed negatif-event multi-value support --- api/chalicelib/core/significance.py | 6 ++++-- ee/api/chalicelib/core/significance.py | 6 ++++-- ee/api/chalicelib/core/significance_exp.py | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/api/chalicelib/core/significance.py b/api/chalicelib/core/significance.py index 64028a8df..fd824509d 100644 --- a/api/chalicelib/core/significance.py +++ b/api/chalicelib/core/significance.py @@ -167,12 +167,14 @@ def get_stages_and_events(filter_d, project_id) -> List[RealDictRow]: values = {**values, **sh.multi_values(helper.values_for_operator(value=s["value"], op=s["operator"]), value_key=f"value{i + 1}")} - if sh.is_negation_operator(op) and i > 0: + if sh.is_negation_operator(s["operator"]) and i > 0: op = sh.reverse_sql_operator(op) main_condition = "left_not.session_id ISNULL" extra_from.append(f"""LEFT JOIN LATERAL (SELECT session_id FROM {next_table} AS s_main - WHERE s_main.{next_col_name} {op} %(value{i + 1})s + WHERE + {sh.multi_conditions(f"s_main.{next_col_name} {op} %(value{i + 1})s", + values=s["value"], value_key=f"value{i + 1}")} AND s_main.timestamp >= T{i}.stage{i}_timestamp AND s_main.session_id = T1.session_id) AS left_not ON (TRUE)""") else: diff --git a/ee/api/chalicelib/core/significance.py b/ee/api/chalicelib/core/significance.py index ae1f0c867..52650bfd7 100644 --- a/ee/api/chalicelib/core/significance.py +++ b/ee/api/chalicelib/core/significance.py @@ -173,12 +173,14 @@ def get_stages_and_events(filter_d, project_id) -> List[RealDictRow]: values = {**values, **sh.multi_values(helper.values_for_operator(value=s["value"], op=s["operator"]), value_key=f"value{i + 1}")} - if sh.is_negation_operator(op) and i > 0: + if sh.is_negation_operator(s["operator"]) and i > 0: op = sh.reverse_sql_operator(op) main_condition = "left_not.session_id ISNULL" extra_from.append(f"""LEFT JOIN LATERAL (SELECT session_id FROM {next_table} AS s_main - WHERE s_main.{next_col_name} {op} %(value{i + 1})s + WHERE + {sh.multi_conditions(f"s_main.{next_col_name} {op} %(value{i + 1})s", + values=s["value"], value_key=f"value{i + 1}")} AND s_main.timestamp >= T{i}.stage{i}_timestamp AND s_main.session_id = T1.session_id) AS left_not ON (TRUE)""") else: diff --git a/ee/api/chalicelib/core/significance_exp.py b/ee/api/chalicelib/core/significance_exp.py index ae1f0c867..52650bfd7 100644 --- a/ee/api/chalicelib/core/significance_exp.py +++ b/ee/api/chalicelib/core/significance_exp.py @@ -173,12 +173,14 @@ def get_stages_and_events(filter_d, project_id) -> List[RealDictRow]: values = {**values, **sh.multi_values(helper.values_for_operator(value=s["value"], op=s["operator"]), value_key=f"value{i + 1}")} - if sh.is_negation_operator(op) and i > 0: + if sh.is_negation_operator(s["operator"]) and i > 0: op = sh.reverse_sql_operator(op) main_condition = "left_not.session_id ISNULL" extra_from.append(f"""LEFT JOIN LATERAL (SELECT session_id FROM {next_table} AS s_main - WHERE s_main.{next_col_name} {op} %(value{i + 1})s + WHERE + {sh.multi_conditions(f"s_main.{next_col_name} {op} %(value{i + 1})s", + values=s["value"], value_key=f"value{i + 1}")} AND s_main.timestamp >= T{i}.stage{i}_timestamp AND s_main.session_id = T1.session_id) AS left_not ON (TRUE)""") else: