Skip to content

Commit

Permalink
UI fixes v1.15.0 (openreplay#1693)
Browse files Browse the repository at this point in the history
* fix(ui): filter keys conflcit with metadata

* fix(player): fix msg reader bug

---------

Co-authored-by: nick-delirium <[email protected]>
  • Loading branch information
shekarsiri and nick-delirium authored Nov 22, 2023
1 parent 48dbbb5 commit 2bf450f
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function FilterAutoComplete(props: Props) {
const loadOptions = (inputValue: string, callback: (options: []) => void) => {
// remove underscore from params
const _params = Object.keys(params).reduce((acc: any, key: string) => {
acc[key] = params[key].replace('_', '');
acc[key] = params[key].replace(/^_/, '');
return acc;
}, {});

Expand Down
2 changes: 1 addition & 1 deletion frontend/app/duck/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ export const filterMap = ({ category, value, key, operator, sourceOperator, sour
custom,
type: category === FilterCategory.METADATA ? FilterKey.METADATA : key,
operator,
source: category === FilterCategory.METADATA ? key : source,
source: category === FilterCategory.METADATA ? key.replace(/^_/, '') : source,
sourceOperator,
isEvent,
filters: filters ? filters.map(filterMap) : [],
Expand Down
6 changes: 3 additions & 3 deletions frontend/app/mstore/types/filterItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export default class FilterItem {

fromJson(json: any, mainFilterKey = '') {
const isMetadata = json.type === FilterKey.METADATA;
let _filter: any = (isMetadata ? filtersMap[json.source] : filtersMap[json.type]) || {};
let _filter: any = (isMetadata ? filtersMap['_' + json.source] : filtersMap[json.type]) || {};

if (mainFilterKey) {
const mainFilter = filtersMap[mainFilterKey];
Expand All @@ -83,7 +83,7 @@ export default class FilterItem {

(this.value = !json.value || json.value.length === 0 ? [''] : json.value);
(this.operator = json.operator);
this.source = json.source;
this.source = isMetadata ? '_' + json.source : json.source;
this.sourceOperator = json.sourceOperator;

this.filters =
Expand All @@ -102,7 +102,7 @@ export default class FilterItem {
isEvent: this.isEvent,
value: this.value,
operator: this.operator,
source: isMetadata ? this.key : this.source,
source: isMetadata ? this.key.replace(/^_/, '') : this.source,
sourceOperator: this.sourceOperator,
filters: Array.isArray(this.filters) ? this.filters.map((i) => i.toJson()) : [],
};
Expand Down
165 changes: 86 additions & 79 deletions frontend/app/player/web/Screen/Screen.ts
Original file line number Diff line number Diff line change
@@ -1,69 +1,70 @@
import styles from './screen.module.css'
import Cursor from './Cursor'
import styles from './screen.module.css';
import Cursor from './Cursor';

import type { Point, Dimensions } from './types';

export type State = Dimensions
export type State = Dimensions;

export const INITIAL_STATE: State = {
width: 0,
height: 0,
}

};

export enum ScaleMode {
Embed,
//AdjustParentWidth
AdjustParentHeight,
}


function getElementsFromInternalPoint(doc: Document, { x, y }: Point): Element[] {
// @ts-ignore (IE, Edge)
if (typeof doc.msElementsFromRect === 'function') {
// @ts-ignore
return Array.prototype.slice.call(doc.msElementsFromRect(x,y)) || []
return Array.prototype.slice.call(doc.msElementsFromRect(x, y)) || [];
}

if (typeof doc.elementsFromPoint === 'function') {
return doc.elementsFromPoint(x, y)
return doc.elementsFromPoint(x, y);
}
const el = doc.elementFromPoint(x, y)
return el ? [ el ] : []
const el = doc.elementFromPoint(x, y);
return el ? [el] : [];
}

function getElementsFromInternalPointDeep(doc: Document, point: Point): Element[] {
const elements = getElementsFromInternalPoint(doc, point)
const elements = getElementsFromInternalPoint(doc, point);
// is it performant though??
for (let i = 0; i < elements.length; i++) {
const el = elements[i]
if (isIframe(el)){
const iDoc = el.contentDocument
const el = elements[i];
if (isIframe(el)) {
const iDoc = el.contentDocument;
if (iDoc) {
const iPoint: Point = {
x: point.x - el.clientLeft,
y: point.y - el.clientTop,
}
elements.push(...getElementsFromInternalPointDeep(iDoc, iPoint))
};
elements.push(...getElementsFromInternalPointDeep(iDoc, iPoint));
}
}
}
return elements
return elements;
}

function isIframe(el: Element): el is HTMLIFrameElement {
return el.tagName === "IFRAME"
return el.tagName === 'IFRAME';
}

export default class Screen {
readonly overlay: HTMLDivElement
readonly cursor: Cursor
private selectionTargets: { start?: HTMLDivElement, end?: HTMLDivElement } = { start: undefined, end: undefined }
readonly overlay: HTMLDivElement;
readonly cursor: Cursor;
private selectionTargets: { start?: HTMLDivElement; end?: HTMLDivElement } = {
start: undefined,
end: undefined,
};

private readonly iframe: HTMLIFrameElement;
private readonly screen: HTMLDivElement;
private parentElement: HTMLElement | null = null
private onUpdateHook: (w: number, h: number) => void
private parentElement: HTMLElement | null = null;
private onUpdateHook: (w: number, h: number) => void;

constructor(isMobile: boolean, private scaleMode: ScaleMode = ScaleMode.Embed) {
const iframe = document.createElement('iframe');
Expand All @@ -81,16 +82,16 @@ export default class Screen {
screen.appendChild(overlay);
this.screen = screen;

this.cursor = new Cursor(this.overlay, isMobile) // TODO: move outside
this.cursor = new Cursor(this.overlay, isMobile); // TODO: move outside
}

addMobileStyles() {
this.iframe.className = styles.mobileIframe
this.screen.className = styles.mobileScreen
this.iframe.className = styles.mobileIframe;
this.screen.className = styles.mobileScreen;
}

addFullscreenBoundary() {
this.screen.className = styles.mobileScreenFullview
this.screen.className = styles.mobileScreenFullview;
}

clean() {
Expand All @@ -101,8 +102,8 @@ export default class Screen {

attach(parentElement: HTMLElement) {
if (this.parentElement) {
this.parentElement = null
console.warn("BaseScreen: reattaching the screen.");
this.parentElement = null;
console.warn('BaseScreen: reattaching the screen.');
}

parentElement.appendChild(this.screen);
Expand All @@ -112,16 +113,16 @@ export default class Screen {
addToBody(el: HTMLElement) {
if (this.document) {
this.document.body.style.margin = '0';
this.document.body.appendChild(el)
this.document.body.appendChild(el);
}
}

getParentElement(): HTMLElement | null {
return this.parentElement
getParentElement(): HTMLElement | null {
return this.parentElement;
}

setBorderStyle(style: { border: string }) {
return Object.assign(this.screen.style, style)
return Object.assign(this.screen.style, style);
}

get window(): WindowProxy | null {
Expand All @@ -133,16 +134,17 @@ export default class Screen {
}

get iframeStylesRef(): CSSStyleDeclaration {
return this.iframe.style
return this.iframe.style;
}

public boundingRect: DOMRect | null = null;
public boundingRect: DOMRect | null = null;

private getBoundingClientRect(): DOMRect {
if (this.boundingRect === null) {
// TODO: use this.screen instead in order to separate overlay functionality
return this.boundingRect = this.screen.getBoundingClientRect() // expensive operation?
if (this.boundingRect === null) {
// TODO: use this.screen instead in order to separate overlay functionality
return (this.boundingRect = this.screen.getBoundingClientRect()); // expensive operation?
}
return this.boundingRect
return this.boundingRect;
}

getInternalViewportCoordinates({ x, y }: Point): Point {
Expand All @@ -158,18 +160,18 @@ export default class Screen {
}

getCurrentScroll(): Point {
const docEl = this.document?.documentElement
const x = docEl ? docEl.scrollLeft : 0
const y = docEl ? docEl.scrollTop : 0
return { x, y }
const docEl = this.document?.documentElement;
const x = docEl ? docEl.scrollLeft : 0;
const y = docEl ? docEl.scrollTop : 0;
return { x, y };
}

getInternalCoordinates(p: Point): Point {
const { x, y } = this.getInternalViewportCoordinates(p);

const sc = this.getCurrentScroll()
const sc = this.getCurrentScroll();

return { x: x+sc.x, y: y+sc.y };
return { x: x + sc.x, y: y + sc.y };
}

getElementFromInternalPoint({ x, y }: Point): Element | null {
Expand All @@ -179,9 +181,11 @@ export default class Screen {
}

getElementsFromInternalPoint(point: Point): Element[] {
const doc = this.document
if (!doc) { return [] }
return getElementsFromInternalPointDeep(doc, point)
const doc = this.document;
if (!doc) {
return [];
}
return getElementsFromInternalPointDeep(doc, point);
}

getElementFromPoint(point: Point): Element | null {
Expand All @@ -194,8 +198,8 @@ export default class Screen {
const safeSelector = selector.replace(/\//g, '\\/');
return this.document?.querySelector<HTMLElement>(safeSelector) || null;
} catch (e) {
console.error("Can not select element. ", e)
return null
console.error('Can not select element. ', e);
return null;
}
}

Expand All @@ -208,6 +212,7 @@ export default class Screen {
}

private scaleRatio: number = 1;

getScale() {
return this.scaleRatio;
}
Expand All @@ -216,21 +221,24 @@ export default class Screen {
if (!this.parentElement) return;
const { offsetWidth, offsetHeight } = this.parentElement;

let translate = ""
let posStyles = {}
let translate = '';
let posStyles = {};
switch (this.scaleMode) {
case ScaleMode.Embed:
this.scaleRatio = Math.min(offsetWidth / width, offsetHeight / height)
translate = "translate(-50%, -50%)"
posStyles = { height: height + 'px' }
break;
case ScaleMode.AdjustParentHeight:
// we want to scale the document with true height so the clickmap will be scrollable
const usedHeight = this.document?.body.offsetHeight && this.document?.body.offsetHeight > height ? this.document.body.offsetHeight + 'px' : height + 'px'
this.scaleRatio = offsetWidth / width
translate = "translate(-50%, 0)"
posStyles = { top: 0, height: usedHeight, }
break;
case ScaleMode.Embed:
this.scaleRatio = Math.min(offsetWidth / width, offsetHeight / height);
translate = 'translate(-50%, -50%)';
posStyles = { height: height + 'px' };
break;
case ScaleMode.AdjustParentHeight:
// we want to scale the document with true height so the clickmap will be scrollable
const usedHeight =
this.document?.body.offsetHeight && this.document?.body.offsetHeight > height
? this.document.body.offsetHeight + 'px'
: height + 'px';
this.scaleRatio = offsetWidth / width;
translate = 'translate(-50%, 0)';
posStyles = { top: 0, height: usedHeight };
break;
}

if (this.scaleRatio > 1) {
Expand All @@ -240,49 +248,48 @@ export default class Screen {
}

if (this.scaleMode === ScaleMode.AdjustParentHeight) {
this.parentElement.style.height = this.scaleRatio * height + 'px'
this.parentElement.style.height = this.scaleRatio * height + 'px';
}

Object.assign(this.screen.style, posStyles, {
width: width + 'px',
transform: `scale(${this.scaleRatio}) ${translate}`,
})
Object.assign(this.iframe.style, posStyles, {
});
Object.assign(this.iframe.style, posStyles, {
width: width + 'px',
})
});

this.boundingRect = this.screen.getBoundingClientRect();
this.onUpdateHook?.(width, height)
this.onUpdateHook?.(width, height);
}

setOnUpdate(cb: any) {
this.onUpdateHook = cb
this.onUpdateHook = cb;
}

public createSelection(start: HTMLDivElement, end: HTMLDivElement) {
this.selectionTargets = { start, end }
this.selectionTargets = { start, end };

this.overlay.appendChild(start);
this.overlay.appendChild(end);

setTimeout(() => {
start.className = styles.highlightoff
end.className = styles.highlightoff
}, 750)
start.className = styles.highlightoff;
end.className = styles.highlightoff;
}, 750);
}

public updateOverlayStyle(style: Partial<CSSStyleDeclaration>) {
Object.assign(this.overlay.style, style)
Object.assign(this.overlay.style, style);
}

public clearSelection() {
if (this.selectionTargets.start && this.selectionTargets.end) {
this.overlay.removeChild(this.selectionTargets.start);
this.overlay.removeChild(this.selectionTargets.end);
this.selectionTargets.start.remove()
this.selectionTargets.end.remove()
this.selectionTargets = { start: undefined, end: undefined }
this.selectionTargets.start.remove();
this.selectionTargets.end.remove();
this.selectionTargets = { start: undefined, end: undefined };
}

}
}
2 changes: 1 addition & 1 deletion frontend/app/player/web/messages/MFileReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export default class MFileReader extends RawMessageReader {

const index = this.noIndexes ? 0 : this.getLastMessageID()
const msg = Object.assign(rewriteMessage(rMsg), {
time: this.currentTime || rMsg.timestamp - this.startTime!,
time: this.currentTime ?? rMsg.timestamp - this.startTime!,
tabId: this.currentTab,
}, !this.noIndexes ? { _index: index } : {})

Expand Down

0 comments on commit 2bf450f

Please sign in to comment.