added incidents
This commit is contained in:
parent
c6d64fc986
commit
5090891ee9
25 changed files with 352 additions and 196 deletions
|
|
@ -11,4 +11,4 @@ func IsMobileType(id int) bool {
|
|||
|
||||
func IsDOMType(id int) bool {
|
||||
return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 34 == id || 35 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id
|
||||
}
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ package messages
|
|||
const (
|
||||
MsgTimestamp = 0
|
||||
MsgSessionStart = 1
|
||||
MsgSessionEndDeprecated = 3
|
||||
MsgSetPageLocationDeprecated = 4
|
||||
MsgSetViewportSize = 5
|
||||
MsgSetViewportScroll = 6
|
||||
|
|
@ -25,6 +26,7 @@ const (
|
|||
MsgConsoleLog = 22
|
||||
MsgPageLoadTiming = 23
|
||||
MsgPageRenderTiming = 24
|
||||
MsgJSExceptionDeprecated = 25
|
||||
MsgIntegrationEvent = 26
|
||||
MsgCustomEvent = 27
|
||||
MsgUserID = 28
|
||||
|
|
@ -35,6 +37,9 @@ const (
|
|||
MsgPageEvent = 33
|
||||
MsgStringDictGlobal = 34
|
||||
MsgSetNodeAttributeDictGlobal = 35
|
||||
MsgCSSInsertRule = 37
|
||||
MsgCSSDeleteRule = 38
|
||||
MsgFetch = 39
|
||||
MsgProfiler = 40
|
||||
MsgOTable = 41
|
||||
MsgStateAction = 42
|
||||
|
|
@ -54,11 +59,14 @@ const (
|
|||
MsgPerformanceTrackAggr = 56
|
||||
MsgLoadFontFace = 57
|
||||
MsgSetNodeFocus = 58
|
||||
MsgLongTask = 59
|
||||
MsgSetNodeAttributeURLBased = 60
|
||||
MsgSetCSSDataURLBased = 61
|
||||
MsgIssueEventDeprecated = 62
|
||||
MsgTechnicalInfo = 63
|
||||
MsgCustomIssue = 64
|
||||
MsgAssetCache = 66
|
||||
MsgCSSInsertRuleURLBased = 67
|
||||
MsgMouseClick = 68
|
||||
MsgMouseClickDeprecated = 69
|
||||
MsgCreateIFrameDocument = 70
|
||||
|
|
@ -71,6 +79,7 @@ const (
|
|||
MsgAdoptedSSRemoveOwner = 77
|
||||
MsgJSException = 78
|
||||
MsgZustand = 79
|
||||
MsgBatchMeta = 80
|
||||
MsgBatchMetadata = 81
|
||||
MsgPartitionedMessage = 82
|
||||
MsgNetworkRequest = 83
|
||||
|
|
@ -734,7 +743,7 @@ func (msg *PageRenderTiming) TypeID() int {
|
|||
|
||||
type JSExceptionDeprecated struct {
|
||||
message
|
||||
Name string
|
||||
Name string
|
||||
Message string
|
||||
Payload string
|
||||
}
|
||||
|
|
@ -1061,8 +1070,8 @@ func (msg *SetNodeAttributeDictGlobal) TypeID() int {
|
|||
|
||||
type CSSInsertRule struct {
|
||||
message
|
||||
ID uint64
|
||||
Rule string
|
||||
ID uint64
|
||||
Rule string
|
||||
Index uint64
|
||||
}
|
||||
|
||||
|
|
@ -1086,7 +1095,7 @@ func (msg *CSSInsertRule) TypeID() int {
|
|||
|
||||
type CSSDeleteRule struct {
|
||||
message
|
||||
ID uint64
|
||||
ID uint64
|
||||
Index uint64
|
||||
}
|
||||
|
||||
|
|
@ -1109,13 +1118,13 @@ func (msg *CSSDeleteRule) TypeID() int {
|
|||
|
||||
type Fetch struct {
|
||||
message
|
||||
Method string
|
||||
URL string
|
||||
Request string
|
||||
Response string
|
||||
Status uint64
|
||||
Method string
|
||||
URL string
|
||||
Request string
|
||||
Response string
|
||||
Status uint64
|
||||
Timestamp uint64
|
||||
Duration uint64
|
||||
Duration uint64
|
||||
}
|
||||
|
||||
func (msg *Fetch) Encode() []byte {
|
||||
|
|
@ -1635,12 +1644,12 @@ func (msg *SetNodeFocus) TypeID() int {
|
|||
|
||||
type LongTask struct {
|
||||
message
|
||||
Timestamp uint64
|
||||
Duration uint64
|
||||
Context uint64
|
||||
Timestamp uint64
|
||||
Duration uint64
|
||||
Context uint64
|
||||
ContainerType uint64
|
||||
ContainerSrc string
|
||||
ContainerId string
|
||||
ContainerSrc string
|
||||
ContainerId string
|
||||
ContainerName string
|
||||
}
|
||||
|
||||
|
|
@ -1720,12 +1729,12 @@ func (msg *SetCSSDataURLBased) TypeID() int {
|
|||
|
||||
type IssueEventDeprecated struct {
|
||||
message
|
||||
MessageID uint64
|
||||
Timestamp uint64
|
||||
Type string
|
||||
MessageID uint64
|
||||
Timestamp uint64
|
||||
Type string
|
||||
ContextString string
|
||||
Context string
|
||||
Payload string
|
||||
Context string
|
||||
Payload string
|
||||
}
|
||||
|
||||
func (msg *IssueEventDeprecated) Encode() []byte {
|
||||
|
|
@ -1818,9 +1827,9 @@ func (msg *AssetCache) TypeID() int {
|
|||
|
||||
type CSSInsertRuleURLBased struct {
|
||||
message
|
||||
ID uint64
|
||||
Rule string
|
||||
Index uint64
|
||||
ID uint64
|
||||
Rule string
|
||||
Index uint64
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
|
|
@ -2145,9 +2154,9 @@ func (msg *Zustand) TypeID() int {
|
|||
|
||||
type BatchMeta struct {
|
||||
message
|
||||
PageNo uint64
|
||||
PageNo uint64
|
||||
FirstIndex uint64
|
||||
Timestamp int64
|
||||
Timestamp int64
|
||||
}
|
||||
|
||||
func (msg *BatchMeta) Encode() []byte {
|
||||
|
|
@ -2291,17 +2300,17 @@ func (msg *WSChannel) TypeID() int {
|
|||
type Incident struct {
|
||||
message
|
||||
Label string
|
||||
StartTime string
|
||||
EndTime string
|
||||
StartTime int64
|
||||
EndTime int64
|
||||
}
|
||||
|
||||
func (msg *Incident) Encode() []byte {
|
||||
buf := make([]byte, 31+len(msg.Label)+len(msg.StartTime)+len(msg.EndTime))
|
||||
buf := make([]byte, 31+len(msg.Label))
|
||||
buf[0] = 85
|
||||
p := 1
|
||||
p = WriteString(msg.Label, buf, p)
|
||||
p = WriteString(msg.StartTime, buf, p)
|
||||
p = WriteString(msg.EndTime, buf, p)
|
||||
p = WriteInt(msg.StartTime, buf, p)
|
||||
p = WriteInt(msg.EndTime, buf, p)
|
||||
return buf[:p]
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -69,12 +69,12 @@ func DecodeSessionStart(reader BytesReader) (Message, error) {
|
|||
}
|
||||
|
||||
func DecodeSessionEndDeprecated(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &SessionEndDeprecated{}
|
||||
if msg.Timestamp, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
var err error = nil
|
||||
msg := &SessionEndDeprecated{}
|
||||
if msg.Timestamp, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeSetPageLocationDeprecated(reader BytesReader) (Message, error) {
|
||||
|
|
@ -391,18 +391,18 @@ func DecodePageRenderTiming(reader BytesReader) (Message, error) {
|
|||
}
|
||||
|
||||
func DecodeJSExceptionDeprecated(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &JSExceptionDeprecated{}
|
||||
if msg.Name, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &JSExceptionDeprecated{}
|
||||
if msg.Name, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Message, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Payload, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeIntegrationEvent(reader BytesReader) (Message, error) {
|
||||
|
|
@ -634,57 +634,57 @@ func DecodeSetNodeAttributeDictGlobal(reader BytesReader) (Message, error) {
|
|||
}
|
||||
|
||||
func DecodeCSSInsertRule(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &CSSInsertRule{}
|
||||
if msg.ID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &CSSInsertRule{}
|
||||
if msg.ID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Rule, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Index, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeCSSDeleteRule(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &CSSDeleteRule{}
|
||||
if msg.ID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &CSSDeleteRule{}
|
||||
if msg.ID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Index, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeFetch(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &Fetch{}
|
||||
if msg.Method, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &Fetch{}
|
||||
if msg.Method, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.URL, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Request, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Response, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Status, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Timestamp, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Duration, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeProfiler(reader BytesReader) (Message, error) {
|
||||
|
|
@ -1000,30 +1000,30 @@ func DecodeSetNodeFocus(reader BytesReader) (Message, error) {
|
|||
}
|
||||
|
||||
func DecodeLongTask(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &LongTask{}
|
||||
if msg.Timestamp, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &LongTask{}
|
||||
if msg.Timestamp, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Duration, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Context, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.ContainerType, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.ContainerSrc, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.ContainerId, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.ContainerName, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeSetNodeAttributeURLBased(reader BytesReader) (Message, error) {
|
||||
|
|
@ -1060,27 +1060,27 @@ func DecodeSetCSSDataURLBased(reader BytesReader) (Message, error) {
|
|||
}
|
||||
|
||||
func DecodeIssueEventDeprecated(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &IssueEventDeprecated{}
|
||||
if msg.MessageID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &IssueEventDeprecated{}
|
||||
if msg.MessageID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Timestamp, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Type, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.ContextString, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Context, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Payload, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeTechnicalInfo(reader BytesReader) (Message, error) {
|
||||
|
|
@ -1117,21 +1117,21 @@ func DecodeAssetCache(reader BytesReader) (Message, error) {
|
|||
}
|
||||
|
||||
func DecodeCSSInsertRuleURLBased(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &CSSInsertRuleURLBased{}
|
||||
if msg.ID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &CSSInsertRuleURLBased{}
|
||||
if msg.ID, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.Rule, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Index, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.BaseURL, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeMouseClick(reader BytesReader) (Message, error) {
|
||||
|
|
@ -1315,18 +1315,18 @@ func DecodeZustand(reader BytesReader) (Message, error) {
|
|||
}
|
||||
|
||||
func DecodeBatchMeta(reader BytesReader) (Message, error) {
|
||||
var err error = nil
|
||||
msg := &BatchMeta{}
|
||||
if msg.PageNo, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var err error = nil
|
||||
msg := &BatchMeta{}
|
||||
if msg.PageNo, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.FirstIndex, err = reader.ReadUint(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
if msg.Timestamp, err = reader.ReadInt(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
}
|
||||
|
||||
func DecodeBatchMetadata(reader BytesReader) (Message, error) {
|
||||
|
|
@ -1425,10 +1425,10 @@ func DecodeIncident(reader BytesReader) (Message, error) {
|
|||
if msg.Label, err = reader.ReadString(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.StartTime, err = reader.ReadString(); err != nil {
|
||||
if msg.StartTime, err = reader.ReadInt(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if msg.EndTime, err = reader.ReadString(); err != nil {
|
||||
if msg.EndTime, err = reader.ReadInt(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return msg, err
|
||||
|
|
|
|||
|
|
@ -339,6 +339,23 @@ class PageEvent(Message):
|
|||
self.web_vitals = web_vitals
|
||||
|
||||
|
||||
class StringDictGlobal(Message):
|
||||
__id__ = 34
|
||||
|
||||
def __init__(self, key, value):
|
||||
self.key = key
|
||||
self.value = value
|
||||
|
||||
|
||||
class SetNodeAttributeDictGlobal(Message):
|
||||
__id__ = 35
|
||||
|
||||
def __init__(self, id, name, value):
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
|
||||
class CSSInsertRule(Message):
|
||||
__id__ = 37
|
||||
|
||||
|
|
|
|||
|
|
@ -511,6 +511,30 @@ cdef class PageEvent(PyMessage):
|
|||
self.web_vitals = web_vitals
|
||||
|
||||
|
||||
cdef class StringDictGlobal(PyMessage):
|
||||
cdef public int __id__
|
||||
cdef public unsigned long key
|
||||
cdef public str value
|
||||
|
||||
def __init__(self, unsigned long key, str value):
|
||||
self.__id__ = 34
|
||||
self.key = key
|
||||
self.value = value
|
||||
|
||||
|
||||
cdef class SetNodeAttributeDictGlobal(PyMessage):
|
||||
cdef public int __id__
|
||||
cdef public unsigned long id
|
||||
cdef public unsigned long name
|
||||
cdef public unsigned long value
|
||||
|
||||
def __init__(self, unsigned long id, unsigned long name, unsigned long value):
|
||||
self.__id__ = 35
|
||||
self.id = id
|
||||
self.name = name
|
||||
self.value = value
|
||||
|
||||
|
||||
cdef class CSSInsertRule(PyMessage):
|
||||
cdef public int __id__
|
||||
cdef public unsigned long id
|
||||
|
|
@ -1179,10 +1203,10 @@ cdef class WSChannel(PyMessage):
|
|||
cdef class Incident(PyMessage):
|
||||
cdef public int __id__
|
||||
cdef public str label
|
||||
cdef public str start_time
|
||||
cdef public str end_time
|
||||
cdef public long start_time
|
||||
cdef public long end_time
|
||||
|
||||
def __init__(self, str label, str start_time, str end_time):
|
||||
def __init__(self, str label, long start_time, long end_time):
|
||||
self.__id__ = 85
|
||||
self.label = label
|
||||
self.start_time = start_time
|
||||
|
|
|
|||
|
|
@ -360,6 +360,19 @@ class MessageCodec(Codec):
|
|||
web_vitals=self.read_string(reader)
|
||||
)
|
||||
|
||||
if message_id == 34:
|
||||
return StringDictGlobal(
|
||||
key=self.read_uint(reader),
|
||||
value=self.read_string(reader)
|
||||
)
|
||||
|
||||
if message_id == 35:
|
||||
return SetNodeAttributeDictGlobal(
|
||||
id=self.read_uint(reader),
|
||||
name=self.read_uint(reader),
|
||||
value=self.read_uint(reader)
|
||||
)
|
||||
|
||||
if message_id == 37:
|
||||
return CSSInsertRule(
|
||||
id=self.read_uint(reader),
|
||||
|
|
@ -719,8 +732,8 @@ class MessageCodec(Codec):
|
|||
if message_id == 85:
|
||||
return Incident(
|
||||
label=self.read_string(reader),
|
||||
start_time=self.read_string(reader),
|
||||
end_time=self.read_string(reader)
|
||||
start_time=self.read_int(reader),
|
||||
end_time=self.read_int(reader)
|
||||
)
|
||||
|
||||
if message_id == 112:
|
||||
|
|
|
|||
|
|
@ -458,6 +458,19 @@ cdef class MessageCodec:
|
|||
web_vitals=self.read_string(reader)
|
||||
)
|
||||
|
||||
if message_id == 34:
|
||||
return StringDictGlobal(
|
||||
key=self.read_uint(reader),
|
||||
value=self.read_string(reader)
|
||||
)
|
||||
|
||||
if message_id == 35:
|
||||
return SetNodeAttributeDictGlobal(
|
||||
id=self.read_uint(reader),
|
||||
name=self.read_uint(reader),
|
||||
value=self.read_uint(reader)
|
||||
)
|
||||
|
||||
if message_id == 37:
|
||||
return CSSInsertRule(
|
||||
id=self.read_uint(reader),
|
||||
|
|
@ -817,8 +830,8 @@ cdef class MessageCodec:
|
|||
if message_id == 85:
|
||||
return Incident(
|
||||
label=self.read_string(reader),
|
||||
start_time=self.read_string(reader),
|
||||
end_time=self.read_string(reader)
|
||||
start_time=self.read_int(reader),
|
||||
end_time=self.read_int(reader)
|
||||
)
|
||||
|
||||
if message_id == 112:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { TYPES } from 'Types/session/event';
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import { useStore } from 'App/mstore';
|
||||
import UxtEvent from 'Components/Session_/EventsBlock/UxtEvent';
|
||||
|
|
@ -32,6 +32,7 @@ function EventGroupWrapper(props) {
|
|||
presentInSearch,
|
||||
isNote,
|
||||
isTabChange,
|
||||
isIncident,
|
||||
filterOutNote,
|
||||
} = props;
|
||||
const { t } = useTranslation();
|
||||
|
|
@ -57,6 +58,16 @@ function EventGroupWrapper(props) {
|
|||
/>
|
||||
);
|
||||
}
|
||||
if (isIncident) {
|
||||
return (
|
||||
<Incident
|
||||
from={event.time}
|
||||
to={event.endTime - event.startTime + event.time}
|
||||
label={event.label}
|
||||
onClick={onEventClick}
|
||||
/>
|
||||
)
|
||||
}
|
||||
if (isLocation) {
|
||||
return (
|
||||
<Event
|
||||
|
|
@ -100,11 +111,19 @@ function EventGroupWrapper(props) {
|
|||
);
|
||||
};
|
||||
|
||||
const shadowColor = isSearched ? '#F0A930' : props.isPrev
|
||||
? '#A7BFFF'
|
||||
: props.isCurrent
|
||||
? '#394EFF'
|
||||
: 'transparent';
|
||||
const shadowColor = useMemo(() => {
|
||||
if (isSearched) {
|
||||
return '#F0A930';
|
||||
}
|
||||
if (props.isPrev) {
|
||||
return '#A7BFFF';
|
||||
}
|
||||
if (props.isCurrent) {
|
||||
return '#394EFF';
|
||||
}
|
||||
return 'transparent';
|
||||
}, [isSearched, props.isPrev, props.isCurrent]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
|
|
@ -172,4 +191,22 @@ function TabChange({ from, to, activeUrl, onClick }) {
|
|||
);
|
||||
};
|
||||
|
||||
function Incident({ label, onClick }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div
|
||||
onClick={onClick}
|
||||
className="pr-6 pl-4 py-2 relative user-select-none transition-all duration-200 cursor-pointer rounded-[3px] hover:bg-[var(--color-active-blue)] bg-[var(--color-white)]"
|
||||
>
|
||||
<div className='flex items-center py-2 gap-[10.5px]'>
|
||||
<Icon name="console/warning" size={18} color="gray-dark" />
|
||||
<div className="flex flex-col">
|
||||
<span style={{ fontWeight: 500 }}>{t('Incident')}</span>
|
||||
<span className="text-ellipsis overflow-hidden whitespace-nowrap max-w-full text-sm text-[var(--color-gray-medium)]">{label}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default observer(EventGroupWrapper);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ function EventsBlock(props: IProps) {
|
|||
useStore();
|
||||
const session = sessionStore.current;
|
||||
const { notesWithEvents } = session;
|
||||
const { uxtVideo } = session;
|
||||
const { uxtVideo, incidents } = session;
|
||||
const { filteredEvents } = sessionStore;
|
||||
const query = sessionStore.eventsQuery;
|
||||
const { eventsIndex } = sessionStore;
|
||||
|
|
@ -49,8 +49,6 @@ function EventsBlock(props: IProps) {
|
|||
const { store, player } = React.useContext(PlayerContext);
|
||||
const [currentTimeEventIndex, setCurrentTimeEventIndex] = React.useState(0);
|
||||
|
||||
console.log('FILTER', uiPlayerStore.showOnlySearchEvents)
|
||||
|
||||
const {
|
||||
time,
|
||||
endTime,
|
||||
|
|
@ -88,7 +86,7 @@ function EventsBlock(props: IProps) {
|
|||
}
|
||||
});
|
||||
}
|
||||
const eventsWithMobxNotes = [...notesWithEvents, ...notes].sort(sortEvents);
|
||||
const eventsWithMobxNotes = [...incidents, ...notesWithEvents, ...notes, ].sort(sortEvents);
|
||||
const filteredTabEvents = query.length
|
||||
? tabChangeEvents.filter((e) => (e.activeUrl as string).includes(query))
|
||||
: tabChangeEvents;
|
||||
|
|
@ -200,6 +198,7 @@ function EventsBlock(props: IProps) {
|
|||
const event = usedEvents[index];
|
||||
const isNote = 'noteId' in event;
|
||||
const isTabChange = 'type' in event && event.type === 'TABCHANGE';
|
||||
const isIncident = 'type' in event && event.type === 'INCIDENT';
|
||||
const isCurrent = index === currentTimeEventIndex;
|
||||
const isPrev = index < currentTimeEventIndex;
|
||||
const isSearched = event.isHighlighted;
|
||||
|
|
@ -218,6 +217,7 @@ function EventsBlock(props: IProps) {
|
|||
showSelection={!playing}
|
||||
isNote={isNote}
|
||||
isTabChange={isTabChange}
|
||||
isIncident={isIncident}
|
||||
isPrev={isPrev}
|
||||
filterOutNote={filterOutNote}
|
||||
setActiveTab={setActiveTab}
|
||||
|
|
|
|||
|
|
@ -6,13 +6,15 @@ import {
|
|||
import { observer } from 'mobx-react-lite';
|
||||
import { getTimelinePosition } from './getTimelinePosition';
|
||||
import { useStore } from '@/mstore';
|
||||
import { getTimelineEventWidth } from './getTimelineEventWidth';
|
||||
import { Tooltip } from 'antd';
|
||||
|
||||
function EventsList() {
|
||||
const { store } = useContext(PlayerContext);
|
||||
const { uiPlayerStore } = useStore();
|
||||
const { uiPlayerStore, sessionStore } = useStore();
|
||||
const { eventCount, endTime, tabStates, sessionStart } = store.get();
|
||||
const { incidents } = sessionStore.current;
|
||||
|
||||
const { eventCount, endTime } = store.get();
|
||||
const { tabStates } = store.get();
|
||||
const scale = 100 / endTime;
|
||||
const events = React.useMemo(
|
||||
() => Object.values(tabStates)[0]?.eventList.filter((e) => {
|
||||
|
|
@ -39,10 +41,25 @@ function EventsList() {
|
|||
<div
|
||||
/* @ts-ignore TODO */
|
||||
key={`${e.key}_${e.time}`}
|
||||
className={`absolute w-[2px] h-[10px] z-[3] pointer-events-none ${e.isHighlighted ? 'bg-[#f0a930]' : 'bg-[#394eff]'}`}
|
||||
className={`absolute w-[2px] h-[10px] z-[4] pointer-events-none ${e.isHighlighted ? 'bg-[#f0a930]' : 'bg-[#394eff]'}`}
|
||||
style={{ left: `${getTimelinePosition(e.time, scale)}%` }}
|
||||
/>
|
||||
))}
|
||||
{incidents.map((i) => {
|
||||
const width = getTimelineEventWidth(endTime, (i as any).time, (i as any).endTime - sessionStart);
|
||||
return (
|
||||
<Tooltip title={i.label} key={(i as any).startTime}>
|
||||
<div
|
||||
/* @ts-ignore TODO */
|
||||
className={`absolute h-[10px] z-[3] bg-[#ff5454]`}
|
||||
style={{
|
||||
left: `${getTimelinePosition((i as any).time, scale)}%`,
|
||||
width: typeof width === 'string' ? width : `${width}%`,
|
||||
}}
|
||||
/>
|
||||
</Tooltip>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
import { getTimelinePosition } from '@/utils';
|
||||
|
||||
export function getTimelineEventWidth(
|
||||
sessionDuration: number,
|
||||
eventStart: number,
|
||||
eventEnd: number,
|
||||
): number | string {
|
||||
if (eventStart < 0) {
|
||||
eventStart = 0;
|
||||
}
|
||||
if (eventEnd > sessionDuration) {
|
||||
eventEnd = sessionDuration;
|
||||
}
|
||||
if (eventStart === eventEnd) {
|
||||
return '2px';
|
||||
}
|
||||
|
||||
const width = ((eventEnd - eventStart) / sessionDuration) * 100;
|
||||
|
||||
return width < 1 ? '4px' : width;
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { issues_types, types } from 'Types/session/issue';
|
||||
import { Grid, Segmented } from 'antd';
|
||||
import { Angry, CircleAlert, Skull, WifiOff, ChevronDown } from 'lucide-react';
|
||||
import { Angry, CircleAlert, Skull, WifiOff, ChevronDown, MessageCircleWarning } from 'lucide-react';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useStore } from 'App/mstore';
|
||||
|
|
@ -15,6 +15,7 @@ const tagIcons = {
|
|||
[types.CLICK_RAGE]: <Angry size={14} />,
|
||||
[types.CRASH]: <Skull size={14} />,
|
||||
[types.TAP_RAGE]: <Angry size={14} />,
|
||||
[types.INCIDENTS]: <MessageCircleWarning size={14} />,
|
||||
} as Record<string, any>;
|
||||
|
||||
function SessionTags() {
|
||||
|
|
|
|||
|
|
@ -19,19 +19,6 @@ import { searchStore, searchStoreLive } from './index';
|
|||
import { checkEventWithFilters } from '@/components/Session_/Player/Controls/checkEventWithFilters';
|
||||
const range = getDateRangeFromValue(LAST_7_DAYS);
|
||||
|
||||
const mockIncidents = [
|
||||
{
|
||||
label: 'Inciden 1',
|
||||
startTime: 1746629916704,
|
||||
endTime: 1746629916704,
|
||||
},
|
||||
{
|
||||
label: 'Incident 2',
|
||||
startTime: 1746629916704,
|
||||
endTime: 1746629916704,
|
||||
},
|
||||
]
|
||||
|
||||
const defaultDateFilters = {
|
||||
url: '',
|
||||
rangeValue: LAST_7_DAYS,
|
||||
|
|
@ -357,9 +344,8 @@ export default class SessionStore {
|
|||
events: evData.events.map((e) => ({
|
||||
...e,
|
||||
isHighlighted: checkEventWithFilters(e, searchStore.instance.filters)
|
||||
})).concat(mockIncidents)
|
||||
})),
|
||||
});
|
||||
console.log('!!!!', eventsData)
|
||||
} catch (e) {
|
||||
console.error('Failed to fetch events', e);
|
||||
}
|
||||
|
|
@ -373,6 +359,7 @@ export default class SessionStore {
|
|||
stackEvents = [],
|
||||
userEvents = [],
|
||||
userTesting = [],
|
||||
incidents = [],
|
||||
} = eventsData;
|
||||
|
||||
const filterEvents = filter.events as Record<string, any>[];
|
||||
|
|
@ -413,6 +400,7 @@ export default class SessionStore {
|
|||
userEvents,
|
||||
stackEvents,
|
||||
userTesting,
|
||||
incidents,
|
||||
);
|
||||
this.current = session;
|
||||
this.eventsIndex = matching;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ const SIMPLE_LIST_NAMES = [
|
|||
'exceptions',
|
||||
'profiles',
|
||||
'frustrations',
|
||||
'incidents',
|
||||
] as const;
|
||||
const MARKED_LIST_NAMES = [
|
||||
'log',
|
||||
|
|
|
|||
|
|
@ -735,8 +735,8 @@ export default class RawMessageReader extends PrimitiveReader {
|
|||
|
||||
case 85: {
|
||||
const label = this.readString(); if (label === null) { return resetPointer() }
|
||||
const startTime = this.readString(); if (startTime === null) { return resetPointer() }
|
||||
const endTime = this.readString(); if (endTime === null) { return resetPointer() }
|
||||
const startTime = this.readInt(); if (startTime === null) { return resetPointer() }
|
||||
const endTime = this.readInt(); if (endTime === null) { return resetPointer() }
|
||||
return {
|
||||
tp: MType.Incident,
|
||||
label,
|
||||
|
|
|
|||
|
|
@ -502,8 +502,8 @@ export interface RawWsChannel {
|
|||
export interface RawIncident {
|
||||
tp: MType.Incident,
|
||||
label: string,
|
||||
startTime: string,
|
||||
endTime: string,
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
}
|
||||
|
||||
export interface RawSelectionChange {
|
||||
|
|
|
|||
|
|
@ -492,8 +492,8 @@ type TrWSChannel = [
|
|||
type TrIncident = [
|
||||
type: 85,
|
||||
label: string,
|
||||
startTime: string,
|
||||
endTime: string,
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
]
|
||||
|
||||
type TrInputChange = [
|
||||
|
|
|
|||
1
frontend/app/svg/icons/funnel/message-circle-warning.svg
Normal file
1
frontend/app/svg/icons/funnel/message-circle-warning.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-message-circle-warning-icon lucide-message-circle-warning"><path d="M7.9 20A9 9 0 1 0 4 16.1L2 22Z"/><path d="M12 8v4"/><path d="M12 16h.01"/></svg>
|
||||
|
After Width: | Height: | Size: 350 B |
|
|
@ -295,8 +295,7 @@ export class Incident extends Event {
|
|||
Object.assign(this, {
|
||||
...evt,
|
||||
label: evt.label || 'User signaled an incident',
|
||||
startTime: evt.startTime,
|
||||
endTime: evt.startTime || evt.endTime,
|
||||
type: 'INCIDENT',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -312,7 +311,6 @@ export type InjectedEvent =
|
|||
| Incident;
|
||||
|
||||
export default function (event: EventData) {
|
||||
console.log('DEETECT EVENT', event);
|
||||
if ('allow_typing' in event) {
|
||||
return new UxtEvent(event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import i18next, { TFunction } from 'i18next';
|
||||
import Record from 'Types/Record';
|
||||
|
||||
export const types = {
|
||||
|
|
@ -10,6 +9,7 @@ export const types = {
|
|||
MOUSE_THRASHING: 'mouse_thrashing',
|
||||
TAP_RAGE: 'tap_rage',
|
||||
DEAD_CLICK: 'dead_click',
|
||||
INCIDENTS: 'incidents',
|
||||
} as const;
|
||||
|
||||
type TypeKeys = keyof typeof types;
|
||||
|
|
@ -75,6 +75,13 @@ export const issues_types = [
|
|||
name: 'Mouse Thrashing',
|
||||
icon: 'cursor-trash',
|
||||
},
|
||||
{
|
||||
type: types.INCIDENTS,
|
||||
visible: true,
|
||||
order: 7,
|
||||
name: 'Incidents',
|
||||
icon: 'funnel/message-circle-warning',
|
||||
}
|
||||
// { 'type': 'memory', 'visible': true, 'order': 4, 'name': 'High Memory', 'icon': 'funnel/sd-card' },
|
||||
// { 'type': 'vault', 'visible': true, 'order': 5, 'name': 'Vault', 'icon': 'safe' },
|
||||
// { 'type': 'bookmark', 'visible': true, 'order': 5, 'name': 'Bookmarks', 'icon': 'safe' },
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Duration } from 'luxon';
|
||||
import { Note } from 'App/services/NotesService';
|
||||
import { toJS } from 'mobx';
|
||||
import SessionEvent, { TYPES, EventData, InjectedEvent } from './event';
|
||||
import SessionEvent, { TYPES, EventData, InjectedEvent, Incident } from './event';
|
||||
import StackEvent from './stackEvent';
|
||||
import SessionError, { IError } from './error';
|
||||
import Issue, { IIssue, types as issueTypes } from './issue';
|
||||
|
|
@ -281,6 +281,8 @@ export default class Session {
|
|||
|
||||
frustrations: Array<IIssue | InjectedEvent>;
|
||||
|
||||
incidents: Array<Incident>
|
||||
|
||||
timezone?: ISession['timezone'];
|
||||
|
||||
platform: ISession['platform'];
|
||||
|
|
@ -443,6 +445,7 @@ export default class Session {
|
|||
userEvents: any[] = [],
|
||||
stackEvents: any[] = [],
|
||||
userTestingEvents: any[] = [],
|
||||
incidents: any[] = [],
|
||||
) {
|
||||
const exceptions =
|
||||
(errors as IError[])?.map((e) => new SessionError(e)) || [];
|
||||
|
|
@ -503,6 +506,11 @@ export default class Session {
|
|||
const frustrationList =
|
||||
[...frustrationEvents, ...frustrationIssues].sort(sortEvents) || [];
|
||||
|
||||
const incidentsList = incidents.sort((a, b) => a.startTime - b.startTime).map((i) => ({
|
||||
...i,
|
||||
time: i.startTime - this.startedAt,
|
||||
})).map((i) => new Incident(i));
|
||||
|
||||
const mixedEventsWithIssues = mergeEventLists(
|
||||
events,
|
||||
frustrationIssues.filter((i) => i.type !== issueTypes.DEAD_CLICK),
|
||||
|
|
@ -521,6 +529,7 @@ export default class Session {
|
|||
this.frustrations = frustrationList;
|
||||
this.crashes = crashes || [];
|
||||
this.addedEvents = true;
|
||||
this.incidents = incidentsList;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -522,8 +522,8 @@ end
|
|||
|
||||
message 85, 'Incident', :replayer => :devtools do
|
||||
string 'Label'
|
||||
string 'StartTime'
|
||||
string 'EndTime'
|
||||
int 'StartTime'
|
||||
int 'EndTime'
|
||||
end
|
||||
|
||||
# 90-111 reserved iOS
|
||||
|
|
|
|||
|
|
@ -574,8 +574,8 @@ export type WSChannel = [
|
|||
export type Incident = [
|
||||
/*type:*/ Type.Incident,
|
||||
/*label:*/ string,
|
||||
/*startTime:*/ string,
|
||||
/*endTime:*/ string,
|
||||
/*startTime:*/ number,
|
||||
/*endTime:*/ number,
|
||||
]
|
||||
|
||||
export type InputChange = [
|
||||
|
|
|
|||
|
|
@ -907,8 +907,8 @@ export function WSChannel(
|
|||
|
||||
export function Incident(
|
||||
label: string,
|
||||
startTime: string,
|
||||
endTime: string,
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
): Messages.Incident {
|
||||
return [
|
||||
Messages.Type.Incident,
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ export default class MessageEncoder extends PrimitiveEncoder {
|
|||
break
|
||||
|
||||
case Messages.Type.Incident:
|
||||
return this.string(msg[1]) && this.string(msg[2]) && this.string(msg[3])
|
||||
return this.string(msg[1]) && this.int(msg[2]) && this.int(msg[3])
|
||||
break
|
||||
|
||||
case Messages.Type.InputChange:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue