commit
74e3c95bf2
18 changed files with 124 additions and 136 deletions
|
|
@ -18,41 +18,45 @@ import Roles from './Roles';
|
|||
|
||||
@withRouter
|
||||
export default class Client extends React.PureComponent {
|
||||
constructor(props){
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
}
|
||||
|
||||
setTab = (tab) => {
|
||||
this.props.history.push(clientRoute(tab));
|
||||
}
|
||||
};
|
||||
|
||||
renderActiveTab = () => (
|
||||
<Switch>
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.PROFILE) } component={ ProfileSettings } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.INTEGRATIONS) } component={ Integrations } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.MANAGE_USERS) } component={ UserView } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.SITES) } component={ Sites } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.CUSTOM_FIELDS) } component={ CustomFields } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.WEBHOOKS) } component={ Webhooks } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.NOTIFICATIONS) } component={ Notifications } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.MANAGE_ROLES) } component={ Roles } />
|
||||
<Route exact strict path={ clientRoute(CLIENT_TABS.AUDIT) } component={ AuditView } />
|
||||
<Redirect to={ clientRoute(CLIENT_TABS.PROFILE) } />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.PROFILE)} component={ProfileSettings} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.INTEGRATIONS)} component={Integrations} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.MANAGE_USERS)} component={UserView} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.SITES)} component={Sites} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.CUSTOM_FIELDS)} component={CustomFields} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.WEBHOOKS)} component={Webhooks} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.NOTIFICATIONS)} component={Notifications} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.MANAGE_ROLES)} component={Roles} />
|
||||
<Route exact strict path={clientRoute(CLIENT_TABS.AUDIT)} component={AuditView} />
|
||||
<Redirect to={clientRoute(CLIENT_TABS.PROFILE)} />
|
||||
</Switch>
|
||||
)
|
||||
);
|
||||
|
||||
render() {
|
||||
const { match: { params: { activeTab } } } = this.props;
|
||||
const {
|
||||
match: {
|
||||
params: { activeTab },
|
||||
},
|
||||
} = this.props;
|
||||
return (
|
||||
<div className={ cn(styles.wrapper, 'page-margin container-90') }>
|
||||
<div className={ styles.main }>
|
||||
<div className={ styles.tabMenu }>
|
||||
<div className={cn('page-margin container-90 flex relative')}>
|
||||
<div className={styles.tabMenu}>
|
||||
<PreferencesMenu activeTab={activeTab} />
|
||||
</div>
|
||||
<div className="bg-white w-full rounded-lg mx-4 my-8 border">
|
||||
{ activeTab && this.renderActiveTab() }
|
||||
<div className={cn('side-menu-margined w-full')}>
|
||||
<div className="bg-white w-full rounded-lg mx-auto mb-8 border" style={{ maxWidth: '1300px'}}>
|
||||
{activeTab && this.renderActiveTab()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
|
|||
function DashboardList() {
|
||||
const { dashboardStore } = useStore();
|
||||
const list = dashboardStore.filteredList;
|
||||
const dashboardsSearch = dashboardStore.dashboardsSearch;
|
||||
const dashboardsSearch = dashboardStore.filter.query;
|
||||
const lenth = list.length;
|
||||
|
||||
return (
|
||||
|
|
@ -18,17 +18,11 @@ function DashboardList() {
|
|||
title={
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<AnimatedSVG name={ICONS.NO_DASHBOARDS} size={180} />
|
||||
<div className="text-center my-4">
|
||||
{dashboardsSearch !== '' ? (
|
||||
'No matching results'
|
||||
) : (
|
||||
<div>
|
||||
<div>You haven't created any dashboards yet</div>
|
||||
<div className="text-sm color-gray-medium font-normal">
|
||||
A Dashboard is a collection of Cards that can be shared across teams.
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="text-center mt-4">
|
||||
{dashboardsSearch !== '' ? 'No matching results' : "You haven't created any dashboards yet"}
|
||||
</div>
|
||||
<div className="text-sm color-gray-medium font-normal">
|
||||
A Dashboard is a collection of Cards that can be shared across teams.
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,9 +5,9 @@ import SaveFilterButton from 'Shared/SaveFilterButton';
|
|||
import { connect } from 'react-redux';
|
||||
import { Button } from 'UI';
|
||||
import { edit, addFilter, fetchSessions, updateFilter } from 'Duck/search';
|
||||
import SessionSearchQueryParamHandler from 'Shared/SessionSearchQueryParamHandler';
|
||||
|
||||
import { debounce } from 'App/utils';
|
||||
import useSessionSearchQueryHandler from 'App/hooks/useSessionSearchQueryHandler';
|
||||
|
||||
let debounceFetch: any = () => {}
|
||||
|
||||
|
|
@ -24,6 +24,9 @@ function SessionSearch(props: Props) {
|
|||
const { appliedFilter, saveRequestPayloads = false, metaLoading } = props;
|
||||
const hasEvents = appliedFilter.filters.filter((i: any) => i.isEvent).size > 0;
|
||||
const hasFilters = appliedFilter.filters.filter((i: any) => !i.isEvent).size > 0;
|
||||
|
||||
useSessionSearchQueryHandler({ appliedFilter, applyFilter: props.updateFilter });
|
||||
|
||||
useEffect(() => {
|
||||
debounceFetch = debounce(() => props.fetchSessions(), 500);
|
||||
}, [])
|
||||
|
|
@ -71,7 +74,6 @@ function SessionSearch(props: Props) {
|
|||
|
||||
return !metaLoading && (
|
||||
<>
|
||||
<SessionSearchQueryParamHandler />
|
||||
{hasEvents || hasFilters ? (
|
||||
<div className="border bg-white rounded mt-4">
|
||||
<div className="p-5">
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ interface Props {
|
|||
fetchFilterSearch: (query: any) => void;
|
||||
addFilterByKeyAndValue: (key: string, value: string) => void;
|
||||
liveAddFilterByKeyAndValue: (key: string, value: string) => void;
|
||||
filterSearchList: any;
|
||||
liveFetchFilterSearch: any;
|
||||
}
|
||||
function SessionSearchField(props: Props) {
|
||||
|
|
|
|||
|
|
@ -1,39 +0,0 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { connect } from 'react-redux';
|
||||
import { addFilterByKeyAndValue, addFilter } from 'Duck/search';
|
||||
import { updateFilter } from 'Duck/search';
|
||||
import { createUrlQuery, getFiltersFromQuery } from 'App/utils/search';
|
||||
|
||||
interface Props {
|
||||
appliedFilter: any;
|
||||
updateFilter: any;
|
||||
addFilterByKeyAndValue: typeof addFilterByKeyAndValue;
|
||||
addFilter: typeof addFilter;
|
||||
}
|
||||
const SessionSearchQueryParamHandler = (props: Props) => {
|
||||
const { appliedFilter } = props;
|
||||
const history = useHistory();
|
||||
|
||||
const applyFilterFromQuery = () => {
|
||||
const filter = getFiltersFromQuery(history.location.search, appliedFilter);
|
||||
props.updateFilter(filter, true, false);
|
||||
};
|
||||
|
||||
const generateUrlQuery = () => {
|
||||
const search: any = createUrlQuery(appliedFilter);
|
||||
history.replace({ search });
|
||||
};
|
||||
|
||||
useEffect(applyFilterFromQuery, []);
|
||||
useEffect(generateUrlQuery, [appliedFilter]);
|
||||
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export default connect(
|
||||
(state: any) => ({
|
||||
appliedFilter: state.getIn(['search', 'instance']),
|
||||
}),
|
||||
{ addFilterByKeyAndValue, addFilter, updateFilter }
|
||||
)(SessionSearchQueryParamHandler);
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from './SessionSearchQueryParamHandler';
|
||||
35
frontend/app/hooks/useSessionSearchQueryHandler.ts
Normal file
35
frontend/app/hooks/useSessionSearchQueryHandler.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useHistory } from 'react-router';
|
||||
import { createUrlQuery, getFiltersFromQuery } from 'App/utils/search';
|
||||
|
||||
interface Props {
|
||||
appliedFilter: any;
|
||||
applyFilter: any;
|
||||
}
|
||||
|
||||
const useSessionSearchQueryHandler = (props: Props) => {
|
||||
const { appliedFilter, applyFilter } = props;
|
||||
const history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
const applyFilterFromQuery = () => {
|
||||
const filter = getFiltersFromQuery(history.location.search, appliedFilter);
|
||||
applyFilter(filter, true, false);
|
||||
};
|
||||
|
||||
applyFilterFromQuery();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const generateUrlQuery = () => {
|
||||
const search: any = createUrlQuery(appliedFilter);
|
||||
history.replace({ search });
|
||||
};
|
||||
|
||||
generateUrlQuery();
|
||||
}, [appliedFilter]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default useSessionSearchQueryHandler;
|
||||
|
|
@ -4,7 +4,7 @@ import type Screen from '../../Screen/Screen';
|
|||
import type { Message, SetNodeScroll } from '../../messages';
|
||||
import { MType } from '../../messages';
|
||||
import ListWalker from '../../../common/ListWalker';
|
||||
import StylesManager, { rewriteNodeStyleSheet } from './StylesManager';
|
||||
import StylesManager from './StylesManager';
|
||||
import FocusManager from './FocusManager';
|
||||
import SelectionManager from './SelectionManager';
|
||||
import type { StyleElement } from './VirtualDOM';
|
||||
|
|
@ -289,11 +289,6 @@ export default class DOMManager extends ListWalker<Message> {
|
|||
vn = this.vTexts.get(msg.id)
|
||||
if (!vn) { logger.error("SetCssData: Node not found", msg); return }
|
||||
vn.setData(msg.data)
|
||||
if (vn.node instanceof HTMLStyleElement) {
|
||||
doc = this.screen.document
|
||||
// TODO: move to message parsing
|
||||
doc && rewriteNodeStyleSheet(doc, vn.node)
|
||||
}
|
||||
if (msg.tp === MType.SetCssData) { // Styles in priority (do we need inlines as well?)
|
||||
vn.applyChanges()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,7 @@ import logger from 'App/logger';
|
|||
import type { SetNodeFocus } from '../../messages';
|
||||
import type { VElement } from './VirtualDOM';
|
||||
import ListWalker from '../../../common/ListWalker';
|
||||
|
||||
const FOCUS_CLASS = "-openreplay-focus"
|
||||
import { FOCUS_CLASSNAME } from '../../messages/rewriter/constants'
|
||||
|
||||
export default class FocusManager extends ListWalker<SetNodeFocus> {
|
||||
constructor(private readonly vElements: Map<number, VElement>) {super()}
|
||||
|
|
@ -11,7 +10,7 @@ export default class FocusManager extends ListWalker<SetNodeFocus> {
|
|||
move(t: number) {
|
||||
const msg = this.moveGetLast(t)
|
||||
if (!msg) {return}
|
||||
this.focused?.classList.remove(FOCUS_CLASS)
|
||||
this.focused?.classList.remove(FOCUS_CLASSNAME)
|
||||
if (msg.id === -1) {
|
||||
this.focused = null
|
||||
return
|
||||
|
|
@ -19,7 +18,7 @@ export default class FocusManager extends ListWalker<SetNodeFocus> {
|
|||
const vn = this.vElements.get(msg.id)
|
||||
if (!vn) { logger.error("Node not found", msg); return }
|
||||
this.focused = vn.node
|
||||
this.focused.classList.add(FOCUS_CLASS)
|
||||
this.focused.classList.add(FOCUS_CLASSNAME)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,19 +1,18 @@
|
|||
import type Screen from '../../Screen/Screen';
|
||||
import type { CssInsertRule, CssDeleteRule } from '../../messages';
|
||||
import { replaceCSSPseudoclasses } from '../../messages/rewriter/rewriteMessage'
|
||||
|
||||
type CSSRuleMessage = CssInsertRule | CssDeleteRule;
|
||||
|
||||
const HOVER_CN = "-openreplay-hover";
|
||||
const HOVER_SELECTOR = `.${HOVER_CN}`;
|
||||
|
||||
// Doesn't work with css files (hasOwnProperty)
|
||||
export function rewriteNodeStyleSheet(doc: Document, node: HTMLLinkElement | HTMLStyleElement) {
|
||||
// Doesn't work with css files (hasOwnProperty returns false)
|
||||
// TODO: recheck and remove if true
|
||||
function rewriteNodeStyleSheet(doc: Document, node: HTMLLinkElement | HTMLStyleElement) {
|
||||
const ss = Object.values(doc.styleSheets).find(s => s.ownerNode === node);
|
||||
if (!ss || !ss.hasOwnProperty('rules')) { return; }
|
||||
for(let i = 0; i < ss.rules.length; i++){
|
||||
const r = ss.rules[i]
|
||||
if (r instanceof CSSStyleRule) {
|
||||
r.selectorText = r.selectorText.replace('/\:hover/g', HOVER_SELECTOR)
|
||||
r.selectorText = replaceCSSPseudoclasses(r.selectorText)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -29,7 +28,7 @@ export default class StylesManager {
|
|||
this.linkLoadingCount = 0;
|
||||
this.linkLoadPromises = [];
|
||||
|
||||
//cancel all promises? tothinkaboutit
|
||||
//cancel all promises? thinkaboutit
|
||||
}
|
||||
|
||||
setStyleHandlers(node: HTMLLinkElement, value: string): void {
|
||||
|
|
@ -44,6 +43,7 @@ export default class StylesManager {
|
|||
}
|
||||
timeoutId = setTimeout(addSkipAndResolve, 4000);
|
||||
|
||||
// It would be better to make it more relyable with addEventListener
|
||||
node.onload = () => {
|
||||
const doc = this.screen.document;
|
||||
doc && rewriteNodeStyleSheet(doc, node);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,14 @@
|
|||
import type Screen from '../Screen/Screen'
|
||||
import type { MouseMove } from "../messages";
|
||||
|
||||
import { HOVER_CLASSNAME } from '../messages/rewriter/constants'
|
||||
import ListWalker from '../../common/ListWalker'
|
||||
|
||||
const HOVER_CLASS = "-openreplay-hover";
|
||||
const HOVER_CLASS_DEPR = "-asayer-hover";
|
||||
|
||||
export default class MouseMoveManager extends ListWalker<MouseMove> {
|
||||
private hoverElements: Array<Element> = []
|
||||
|
||||
constructor(private screen: Screen) {super()}
|
||||
|
||||
// private getCursorTarget() {
|
||||
// return this.screen.getElementFromInternalPoint(this.current)
|
||||
// }
|
||||
|
||||
private getCursorTargets() {
|
||||
return this.screen.getElementsFromInternalPoint(this.current)
|
||||
}
|
||||
|
|
@ -25,12 +19,10 @@ export default class MouseMoveManager extends ListWalker<MouseMove> {
|
|||
const diffRemove = this.hoverElements.filter(elem => !curHoverElements.includes(elem))
|
||||
this.hoverElements = curHoverElements
|
||||
diffAdd.forEach(elem => {
|
||||
elem.classList.add(HOVER_CLASS)
|
||||
elem.classList.add(HOVER_CLASS_DEPR)
|
||||
elem.classList.add(HOVER_CLASSNAME)
|
||||
})
|
||||
diffRemove.forEach(elem => {
|
||||
elem.classList.remove(HOVER_CLASS)
|
||||
elem.classList.remove(HOVER_CLASS_DEPR)
|
||||
elem.classList.remove(HOVER_CLASSNAME)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { RawMessage } from './raw.gen'
|
|||
import type { TrackerMessage } from './tracker.gen'
|
||||
import translate from './tracker.gen'
|
||||
import { TP_MAP } from './tracker-legacy.gen'
|
||||
import resolveURL from './urlBasedResolver'
|
||||
import rewriteMessage from './rewriter/rewriteMessage'
|
||||
|
||||
|
||||
function legacyTranslate(msg: any): RawMessage | null {
|
||||
|
|
@ -30,7 +30,7 @@ export default class JSONRawMessageReader {
|
|||
if (!rawMsg) {
|
||||
return this.readMessage()
|
||||
}
|
||||
return resolveURL(rawMsg)
|
||||
return rewriteMessage(rawMsg)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import type { Message } from './message.gen';
|
|||
import type { RawMessage } from './raw.gen';
|
||||
import { MType } from './raw.gen';
|
||||
import RawMessageReader from './RawMessageReader.gen';
|
||||
import resolveURL from './urlBasedResolver'
|
||||
import rewriteMessage from './rewriter/rewriteMessage'
|
||||
import Logger from 'App/logger'
|
||||
|
||||
// TODO: composition instead of inheritance
|
||||
|
|
@ -77,7 +77,7 @@ export default class MFileReader extends RawMessageReader {
|
|||
}
|
||||
|
||||
const index = this.getLastMessageID()
|
||||
const msg = Object.assign(resolveURL(rMsg), {
|
||||
const msg = Object.assign(rewriteMessage(rMsg), {
|
||||
time: this.currentTime,
|
||||
_index: index,
|
||||
})
|
||||
|
|
|
|||
2
frontend/app/player/web/messages/rewriter/constants.ts
Normal file
2
frontend/app/player/web/messages/rewriter/constants.ts
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export const HOVER_CLASSNAME = "-openreplay-hover"
|
||||
export const FOCUS_CLASSNAME = "-openreplay-focus"
|
||||
|
|
@ -10,24 +10,31 @@ import type {
|
|||
RawAdoptedSsInsertRule,
|
||||
RawAdoptedSsReplaceURLBased,
|
||||
RawAdoptedSsReplace,
|
||||
} from './raw.gen'
|
||||
import { MType } from './raw.gen'
|
||||
} from '../raw.gen'
|
||||
import { MType } from '../raw.gen'
|
||||
import { resolveURL, resolveCSS } from './urlResolve'
|
||||
import { HOVER_CLASSNAME, FOCUS_CLASSNAME } from './constants'
|
||||
|
||||
// type PickMessage<T extends MType> = Extract<RawMessage, { tp: T }>;
|
||||
// type ResolversMap = {
|
||||
// [Key in MType]: (event: PickMessage<Key>) => RawMessage
|
||||
// }
|
||||
const HOVER_SELECTOR = `.${HOVER_CLASSNAME}`
|
||||
const FOCUS_SELECTOR = `.${FOCUS_CLASSNAME}`
|
||||
export function replaceCSSPseudoclasses(cssText: string): string {
|
||||
return cssText
|
||||
.replace('/\:hover/g', HOVER_SELECTOR)
|
||||
.replace('/\:focus/g', FOCUS_SELECTOR)
|
||||
}
|
||||
function rewriteCSS(baseURL: string, cssText: string): string {
|
||||
return replaceCSSPseudoclasses(resolveCSS(baseURL, cssText))
|
||||
}
|
||||
|
||||
// TODO: commonURLBased logic for feilds
|
||||
const resolvers = {
|
||||
// TODO: common logic for URL fields in all the ...URLBased messages
|
||||
const REWRITERS = {
|
||||
[MType.SetNodeAttributeURLBased]: (msg: RawSetNodeAttributeURLBased): RawSetNodeAttribute =>
|
||||
({
|
||||
...msg,
|
||||
value: msg.name === 'src' || msg.name === 'href'
|
||||
? resolveURL(msg.baseURL, msg.value)
|
||||
: (msg.name === 'style'
|
||||
? resolveCSS(msg.baseURL, msg.value)
|
||||
? rewriteCSS(msg.baseURL, msg.value)
|
||||
: msg.value
|
||||
),
|
||||
tp: MType.SetNodeAttribute,
|
||||
|
|
@ -35,35 +42,35 @@ const resolvers = {
|
|||
[MType.SetCssDataURLBased]: (msg: RawSetCssDataURLBased): RawSetCssData =>
|
||||
({
|
||||
...msg,
|
||||
data: resolveCSS(msg.baseURL, msg.data),
|
||||
data: rewriteCSS(msg.baseURL, msg.data),
|
||||
tp: MType.SetCssData,
|
||||
}),
|
||||
[MType.CssInsertRuleURLBased]: (msg: RawCssInsertRuleURLBased): RawCssInsertRule =>
|
||||
({
|
||||
...msg,
|
||||
rule: resolveCSS(msg.baseURL, msg.rule),
|
||||
rule: rewriteCSS(msg.baseURL, msg.rule),
|
||||
tp: MType.CssInsertRule,
|
||||
}),
|
||||
[MType.AdoptedSsInsertRuleURLBased]: (msg: RawAdoptedSsInsertRuleURLBased): RawAdoptedSsInsertRule =>
|
||||
({
|
||||
...msg,
|
||||
rule: resolveCSS(msg.baseURL, msg.rule),
|
||||
rule: rewriteCSS(msg.baseURL, msg.rule),
|
||||
tp: MType.AdoptedSsInsertRule,
|
||||
}),
|
||||
[MType.AdoptedSsReplaceURLBased]: (msg: RawAdoptedSsReplaceURLBased): RawAdoptedSsReplace =>
|
||||
({
|
||||
...msg,
|
||||
text: resolveCSS(msg.baseURL, msg.text),
|
||||
text: rewriteCSS(msg.baseURL, msg.text),
|
||||
tp: MType.AdoptedSsReplace,
|
||||
}),
|
||||
} as const
|
||||
|
||||
|
||||
export default function resolve(msg: RawMessage): RawMessage {
|
||||
// @ts-ignore --- any idea?
|
||||
if (resolvers[msg.tp]) {
|
||||
export default function rewriteMessage(msg: RawMessage): RawMessage {
|
||||
// @ts-ignore --- any idea for correct typing?
|
||||
if (REWRITERS[msg.tp]) {
|
||||
// @ts-ignore
|
||||
return resolvers[msg.tp](msg)
|
||||
return REWRITERS[msg.tp](msg)
|
||||
}
|
||||
return msg
|
||||
}
|
||||
|
|
@ -35,7 +35,7 @@ message 92, 'IOSMetadata' do
|
|||
string 'Value'
|
||||
end
|
||||
|
||||
message 93, 'IOSCustomEvent', :seq_index => true, :replayer => true do
|
||||
message 93, 'IOSCustomEvent', :replayer => true do
|
||||
uint 'Timestamp'
|
||||
uint 'Length'
|
||||
string 'Name'
|
||||
|
|
@ -63,7 +63,7 @@ message 96, 'IOSScreenChanges', :replayer => true do
|
|||
uint 'Height'
|
||||
end
|
||||
|
||||
message 97, 'IOSCrash', :seq_index => true do
|
||||
message 97, 'IOSCrash' do
|
||||
uint 'Timestamp'
|
||||
uint 'Length'
|
||||
string 'Name'
|
||||
|
|
@ -71,7 +71,7 @@ message 97, 'IOSCrash', :seq_index => true do
|
|||
string 'Stacktrace'
|
||||
end
|
||||
|
||||
message 98, 'IOSScreenEnter', :seq_index => true do
|
||||
message 98, 'IOSScreenEnter' do
|
||||
uint 'Timestamp'
|
||||
uint 'Length'
|
||||
string 'Title'
|
||||
|
|
@ -85,7 +85,7 @@ message 99, 'IOSScreenLeave' do
|
|||
string 'ViewName'
|
||||
end
|
||||
|
||||
message 100, 'IOSClickEvent', :seq_index => true, :replayer => true do
|
||||
message 100, 'IOSClickEvent', :replayer => true do
|
||||
uint 'Timestamp'
|
||||
uint 'Length'
|
||||
string 'Label'
|
||||
|
|
@ -93,7 +93,7 @@ message 100, 'IOSClickEvent', :seq_index => true, :replayer => true do
|
|||
uint 'Y'
|
||||
end
|
||||
|
||||
message 101, 'IOSInputEvent', :seq_index => true do
|
||||
message 101, 'IOSInputEvent' do
|
||||
uint 'Timestamp'
|
||||
uint 'Length'
|
||||
string 'Value'
|
||||
|
|
@ -115,7 +115,7 @@ Name/Value may be :
|
|||
"mainThreadCPU": Possible values (0 .. 100)
|
||||
"memoryUsage": Used memory in bytes
|
||||
=end
|
||||
message 102, 'IOSPerformanceEvent', :replayer => true, :seq_index => true do
|
||||
message 102, 'IOSPerformanceEvent', :replayer => true do
|
||||
uint 'Timestamp'
|
||||
uint 'Length'
|
||||
string 'Name'
|
||||
|
|
@ -135,7 +135,7 @@ message 104, 'IOSInternalError' do
|
|||
string 'Content'
|
||||
end
|
||||
|
||||
message 105, 'IOSNetworkCall', :replayer => true, :seq_index => true do
|
||||
message 105, 'IOSNetworkCall', :replayer => true do
|
||||
uint 'Timestamp'
|
||||
uint 'Length'
|
||||
uint 'Duration'
|
||||
|
|
@ -163,7 +163,7 @@ message 110, 'IOSPerformanceAggregated', :swift => false do
|
|||
uint 'MaxBattery'
|
||||
end
|
||||
|
||||
message 111, 'IOSIssueEvent', :seq_index => true do
|
||||
message 111, 'IOSIssueEvent' do
|
||||
uint 'Timestamp'
|
||||
string 'Type'
|
||||
string 'ContextString'
|
||||
|
|
|
|||
|
|
@ -84,14 +84,13 @@ end
|
|||
$context = :web
|
||||
|
||||
class Message
|
||||
attr_reader :id, :name, :tracker, :replayer, :swift, :seq_index, :attributes, :context
|
||||
def initialize(name:, id:, tracker: $context == :web, replayer: $context == :web, swift: $context == :ios, seq_index: false, &block)
|
||||
attr_reader :id, :name, :tracker, :replayer, :swift, :attributes, :context
|
||||
def initialize(name:, id:, tracker: $context == :web, replayer: $context == :web, swift: $context == :ios, &block)
|
||||
@id = id
|
||||
@name = name
|
||||
@tracker = tracker
|
||||
@replayer = replayer
|
||||
@swift = swift
|
||||
@seq_index = seq_index
|
||||
@context = $context
|
||||
@attributes = []
|
||||
# opts.each { |key, value| send "#{key}=", value }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue