Merge remote-tracking branch 'origin/api-dev-v1.8.0' into api-v1.8.0

This commit is contained in:
Taha Yassine Kraiem 2022-07-28 12:30:00 +02:00
commit 264df362d0
153 changed files with 5198 additions and 2792 deletions

View file

@ -3,6 +3,7 @@ LABEL Maintainer="Rajesh Rajendran<rjshrjndrn@gmail.com>"
LABEL Maintainer="KRAIEM Taha Yassine<tahayk2@gmail.com>"
RUN apk upgrade busybox --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
RUN apk add --no-cache build-base nodejs npm tini
RUN apk upgrade busybox --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
ARG envarg
# Add Tini
# Startup daemon

View file

@ -35,9 +35,10 @@ def get_live_sessions_ws(project_id, body: schemas.LiveSessionsSearchPayloadSche
}
for f in body.filters:
if f.type == schemas.LiveFilterType.metadata:
data["filter"][f.source] = f.value
data["filter"][f.source] = {"values": f.value, "operator": f.operator}
else:
data["filter"][f.type.value] = f.value
data["filter"][f.type.value] = {"values": f.value, "operator": f.operator}
return __get_live_sessions_ws(project_id=project_id, data=data)

View file

@ -1,8 +1,9 @@
import schemas
from chalicelib.core import integration_base
from chalicelib.core.integration_github_issue import GithubIntegrationIssue
from chalicelib.utils import pg_client, helper
PROVIDER = "GITHUB"
PROVIDER = schemas.IntegrationType.github
class GitHubIntegration(integration_base.BaseIntegration):

View file

@ -1,8 +1,9 @@
import schemas
from chalicelib.core import integration_base
from chalicelib.core.integration_jira_cloud_issue import JIRACloudIntegrationIssue
from chalicelib.utils import pg_client, helper
PROVIDER = "JIRA"
PROVIDER = schemas.IntegrationType.jira
def obfuscate_string(string):

View file

@ -0,0 +1,61 @@
import schemas
from chalicelib.utils import pg_client
def get_global_integrations_status(tenant_id, user_id, project_id):
with pg_client.PostgresClient() as cur:
cur.execute(
cur.mogrify(f"""\
SELECT EXISTS((SELECT 1
FROM public.oauth_authentication
WHERE user_id = %(user_id)s
AND provider = 'github')) AS {schemas.IntegrationType.github},
EXISTS((SELECT 1
FROM public.jira_cloud
WHERE user_id = %(user_id)s)) AS {schemas.IntegrationType.jira},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='bugsnag')) AS {schemas.IntegrationType.bugsnag},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='cloudwatch')) AS {schemas.IntegrationType.cloudwatch},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='datadog')) AS {schemas.IntegrationType.datadog},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='newrelic')) AS {schemas.IntegrationType.newrelic},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='rollbar')) AS {schemas.IntegrationType.rollbar},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='sentry')) AS {schemas.IntegrationType.sentry},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='stackdriver')) AS {schemas.IntegrationType.stackdriver},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='sumologic')) AS {schemas.IntegrationType.sumologic},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='elasticsearch')) AS {schemas.IntegrationType.elasticsearch},
EXISTS((SELECT 1
FROM public.webhooks
WHERE type='slack')) AS {schemas.IntegrationType.slack};""",
{"user_id": user_id, "tenant_id": tenant_id, "project_id": project_id})
)
current_integrations = cur.fetchone()
result = []
for k in current_integrations.keys():
result.append({"name": k, "integrated": current_integrations[k]})
return result

View file

@ -12,7 +12,7 @@ from chalicelib.core import log_tool_rollbar, sourcemaps, events, sessions_assig
log_tool_cloudwatch, log_tool_sentry, log_tool_sumologic, log_tools, errors, sessions, \
log_tool_newrelic, announcements, log_tool_bugsnag, weekly_report, integration_jira_cloud, integration_github, \
assist, heatmaps, mobile, signup, tenants, errors_favorite_viewed, boarding, notifications, webhook, users, \
custom_metrics, saved_search
custom_metrics, saved_search, integrations_global
from chalicelib.core.collaboration_slack import Slack
from chalicelib.utils import email_helper, helper, captcha
from chalicelib.utils.TimeUTC import TimeUTC
@ -173,6 +173,14 @@ def session_top_filter_values(projectId: int, context: schemas.CurrentContext =
return {'data': sessions_metas.get_top_key_values(projectId)}
@app.get('/{projectId}/integrations', tags=["integrations"])
def get_integrations_status(projectId: int, context: schemas.CurrentContext = Depends(OR_context)):
data = integrations_global.get_global_integrations_status(tenant_id=context.tenant_id,
user_id=context.user_id,
project_id=projectId)
return {"data": data}
@app.post('/{projectId}/integrations/{integration}/notify/{integrationId}/{source}/{sourceId}', tags=["integrations"])
@app.put('/{projectId}/integrations/{integration}/notify/{integrationId}/{source}/{sourceId}', tags=["integrations"])
def integration_notify(projectId: int, integration: str, integrationId: int, source: str, sourceId: str,

View file

@ -1026,13 +1026,15 @@ class LiveFilterType(str, Enum):
user_UUID = "USERUUID"
tracker_version = "TRACKERVERSION"
user_browser_version = "USERBROWSERVERSION"
user_device_type = "USERDEVICETYPE",
user_device_type = "USERDEVICETYPE"
class LiveSessionSearchFilterSchema(BaseModel):
value: Union[List[str], str] = Field(...)
type: LiveFilterType = Field(...)
source: Optional[str] = Field(None)
operator: Literal[SearchEventOperator._is.value,
SearchEventOperator._contains.value] = Field(SearchEventOperator._contains.value)
@root_validator
def validator(cls, values):
@ -1068,3 +1070,18 @@ class LiveSessionsSearchPayloadSchema(_PaginatedSchema):
class Config:
alias_generator = attribute_to_camel_case
class IntegrationType(str, Enum):
github = "GITHUB"
jira = "JIRA"
slack = "SLACK"
sentry = "SENTRY"
bugsnag = "BUGSNAG"
rollbar = "ROLLBAR"
elasticsearch = "ELASTICSEARCH"
datadog = "DATADOG"
sumologic = "SUMOLOGIC"
stackdriver = "STACKDRIVER"
cloudwatch = "CLOUDWATCH"
newrelic = "NEWRELIC"

View file

@ -50,7 +50,7 @@ ENV TZ=UTC \
ASSETS_SIZE_LIMIT=6291456 \
ASSETS_HEADERS="{ \"Cookie\": \"ABv=3;\" }" \
FS_CLEAN_HRS=72 \
FILE_SPLIT_SIZE=500000 \
FILE_SPLIT_SIZE=1000000 \
LOG_QUEUE_STATS_INTERVAL_SEC=60 \
DB_BATCH_QUEUE_LIMIT=20 \
DB_BATCH_SIZE_LIMIT=10000000 \

View file

@ -3,6 +3,7 @@ LABEL Maintainer="Rajesh Rajendran<rjshrjndrn@gmail.com>"
LABEL Maintainer="KRAIEM Taha Yassine<tahayk2@gmail.com>"
RUN apk upgrade busybox --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
RUN apk add --no-cache build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec nodejs npm tini
RUN apk upgrade busybox --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main
ARG envarg
ENV SOURCE_MAP_VERSION=0.7.4 \
APP_NAME=chalice \

View file

@ -0,0 +1,61 @@
import schemas
from chalicelib.utils import pg_client
def get_global_integrations_status(tenant_id, user_id, project_id):
with pg_client.PostgresClient() as cur:
cur.execute(
cur.mogrify(f"""\
SELECT EXISTS((SELECT 1
FROM public.oauth_authentication
WHERE user_id = %(user_id)s
AND provider = 'github')) AS {schemas.IntegrationType.github},
EXISTS((SELECT 1
FROM public.jira_cloud
WHERE user_id = %(user_id)s)) AS {schemas.IntegrationType.jira},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='bugsnag')) AS {schemas.IntegrationType.bugsnag},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='cloudwatch')) AS {schemas.IntegrationType.cloudwatch},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='datadog')) AS {schemas.IntegrationType.datadog},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='newrelic')) AS {schemas.IntegrationType.newrelic},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='rollbar')) AS {schemas.IntegrationType.rollbar},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='sentry')) AS {schemas.IntegrationType.sentry},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='stackdriver')) AS {schemas.IntegrationType.stackdriver},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='sumologic')) AS {schemas.IntegrationType.sumologic},
EXISTS((SELECT 1
FROM public.integrations
WHERE project_id=%(project_id)s
AND provider='elasticsearch')) AS {schemas.IntegrationType.elasticsearch},
EXISTS((SELECT 1
FROM public.webhooks
WHERE type='slack' AND tenant_id=%(tenant_id)s)) AS {schemas.IntegrationType.slack};""",
{"user_id": user_id, "tenant_id": tenant_id, "project_id": project_id})
)
current_integrations = cur.fetchone()
result = []
for k in current_integrations.keys():
result.append({"name": k, "integrated": current_integrations[k]})
return result

View file

@ -49,7 +49,7 @@ def main():
elif LEVEL == 'normal':
n = handle_normal_message(message)
session_id = codec.decode_key(msg.key)
session_id = decode_key(msg.key)
sessions[session_id] = handle_session(sessions[session_id], message)
if sessions[session_id]:
sessions[session_id].sessionid = session_id
@ -116,6 +116,15 @@ def attempt_batch_insert(batch):
except Exception as e:
print(repr(e))
def decode_key(b) -> int:
"""
Decode the message key (encoded with little endian)
"""
try:
decoded = int.from_bytes(b, "little", signed=False)
except Exception as e:
raise UnicodeDecodeError(f"Error while decoding message key (SessionID) from {b}\n{e}")
return decoded
if __name__ == '__main__':
main()

View file

@ -49,7 +49,7 @@ def main():
elif LEVEL == 'normal':
n = handle_normal_message(message)
session_id = codec.decode_key(msg.key)
session_id = decode_key(msg.key)
sessions[session_id] = handle_session(sessions[session_id], message)
if sessions[session_id]:
sessions[session_id].sessionid = session_id
@ -116,6 +116,15 @@ def attempt_batch_insert(batch):
except Exception as e:
print(repr(e))
def decode_key(b) -> int:
"""
Decode the message key (encoded with little endian)
"""
try:
decoded = int.from_bytes(b, "little", signed=False)
except Exception as e:
raise UnicodeDecodeError(f"Error while decoding message key (SessionID) from {b}\n{e}")
return decoded
if __name__ == '__main__':
main()

View file

@ -1,8 +1,5 @@
import io
from msgcodec.messages import *
class Codec:
"""
Implements encode/decode primitives
@ -63,608 +60,3 @@ class Codec:
return s.decode("utf-8", errors="replace").replace("\x00", "\uFFFD")
except UnicodeDecodeError:
return None
class MessageCodec(Codec):
def encode(self, m: Message) -> bytes:
...
def decode(self, b: bytes) -> Message:
reader = io.BytesIO(b)
message_id = self.read_message_id(reader)
if message_id == 0:
return Timestamp(
timestamp=self.read_uint(reader)
)
if message_id == 1:
return SessionStart(
timestamp=self.read_uint(reader),
project_id=self.read_uint(reader),
tracker_version=self.read_string(reader),
rev_id=self.read_string(reader),
user_uuid=self.read_string(reader),
user_agent=self.read_string(reader),
user_os=self.read_string(reader),
user_os_version=self.read_string(reader),
user_browser=self.read_string(reader),
user_browser_version=self.read_string(reader),
user_device=self.read_string(reader),
user_device_type=self.read_string(reader),
user_device_memory_size=self.read_uint(reader),
user_device_heap_size=self.read_uint(reader),
user_country=self.read_string(reader)
)
if message_id == 2:
return SessionDisconnect(
timestamp=self.read_uint(reader)
)
if message_id == 3:
return SessionEnd(
timestamp=self.read_uint(reader)
)
if message_id == 4:
return SetPageLocation(
url=self.read_string(reader),
referrer=self.read_string(reader),
navigation_start=self.read_uint(reader)
)
if message_id == 5:
return SetViewportSize(
width=self.read_uint(reader),
height=self.read_uint(reader)
)
if message_id == 6:
return SetViewportScroll(
x=self.read_int(reader),
y=self.read_int(reader)
)
if message_id == 7:
return CreateDocument()
if message_id == 8:
return CreateElementNode(
id=self.read_uint(reader),
parent_id=self.read_uint(reader),
index=self.read_uint(reader),
tag=self.read_string(reader),
svg=self.read_boolean(reader),
)
if message_id == 9:
return CreateTextNode(
id=self.read_uint(reader),
parent_id=self.read_uint(reader),
index=self.read_uint(reader)
)
if message_id == 10:
return MoveNode(
id=self.read_uint(reader),
parent_id=self.read_uint(reader),
index=self.read_uint(reader)
)
if message_id == 11:
return RemoveNode(
id=self.read_uint(reader)
)
if message_id == 12:
return SetNodeAttribute(
id=self.read_uint(reader),
name=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 13:
return RemoveNodeAttribute(
id=self.read_uint(reader),
name=self.read_string(reader)
)
if message_id == 14:
return SetNodeData(
id=self.read_uint(reader),
data=self.read_string(reader)
)
if message_id == 15:
return SetCSSData(
id=self.read_uint(reader),
data=self.read_string(reader)
)
if message_id == 16:
return SetNodeScroll(
id=self.read_uint(reader),
x=self.read_int(reader),
y=self.read_int(reader),
)
if message_id == 17:
return SetInputTarget(
id=self.read_uint(reader),
label=self.read_string(reader)
)
if message_id == 18:
return SetInputValue(
id=self.read_uint(reader),
value=self.read_string(reader),
mask=self.read_int(reader),
)
if message_id == 19:
return SetInputChecked(
id=self.read_uint(reader),
checked=self.read_boolean(reader)
)
if message_id == 20:
return MouseMove(
x=self.read_uint(reader),
y=self.read_uint(reader)
)
if message_id == 21:
return MouseClick(
id=self.read_uint(reader),
hesitation_time=self.read_uint(reader),
label=self.read_string(reader)
)
if message_id == 22:
return ConsoleLog(
level=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 23:
return PageLoadTiming(
request_start=self.read_uint(reader),
response_start=self.read_uint(reader),
response_end=self.read_uint(reader),
dom_content_loaded_event_start=self.read_uint(reader),
dom_content_loaded_event_end=self.read_uint(reader),
load_event_start=self.read_uint(reader),
load_event_end=self.read_uint(reader),
first_paint=self.read_uint(reader),
first_contentful_paint=self.read_uint(reader)
)
if message_id == 24:
return PageRenderTiming(
speed_index=self.read_uint(reader),
visually_complete=self.read_uint(reader),
time_to_interactive=self.read_uint(reader),
)
if message_id == 25:
return JSException(
name=self.read_string(reader),
message=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 26:
return RawErrorEvent(
timestamp=self.read_uint(reader),
source=self.read_string(reader),
name=self.read_string(reader),
message=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 27:
return RawCustomEvent(
name=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 28:
return UserID(
id=self.read_string(reader)
)
if message_id == 29:
return UserAnonymousID(
id=self.read_string(reader)
)
if message_id == 30:
return Metadata(
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 31:
return PageEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
url=self.read_string(reader),
referrer=self.read_string(reader),
loaded=self.read_boolean(reader),
request_start=self.read_uint(reader),
response_start=self.read_uint(reader),
response_end=self.read_uint(reader),
dom_content_loaded_event_start=self.read_uint(reader),
dom_content_loaded_event_end=self.read_uint(reader),
load_event_start=self.read_uint(reader),
load_event_end=self.read_uint(reader),
first_paint=self.read_uint(reader),
first_contentful_paint=self.read_uint(reader),
speed_index=self.read_uint(reader),
visually_complete=self.read_uint(reader),
time_to_interactive=self.read_uint(reader)
)
if message_id == 32:
return InputEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
value=self.read_string(reader),
value_masked=self.read_boolean(reader),
label=self.read_string(reader),
)
if message_id == 33:
return ClickEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
hesitation_time=self.read_uint(reader),
label=self.read_string(reader)
)
if message_id == 34:
return ErrorEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
source=self.read_string(reader),
name=self.read_string(reader),
message=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 35:
message_id = self.read_uint(reader)
ts = self.read_uint(reader)
if ts > 9999999999999:
ts = None
return ResourceEvent(
message_id=message_id,
timestamp=ts,
duration=self.read_uint(reader),
ttfb=self.read_uint(reader),
header_size=self.read_uint(reader),
encoded_body_size=self.read_uint(reader),
decoded_body_size=self.read_uint(reader),
url=self.read_string(reader),
type=self.read_string(reader),
success=self.read_boolean(reader),
method=self.read_string(reader),
status=self.read_uint(reader)
)
if message_id == 36:
return CustomEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
name=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 37:
return CSSInsertRule(
id=self.read_uint(reader),
rule=self.read_string(reader),
index=self.read_uint(reader)
)
if message_id == 38:
return CSSDeleteRule(
id=self.read_uint(reader),
index=self.read_uint(reader)
)
if message_id == 39:
return Fetch(
method=self.read_string(reader),
url=self.read_string(reader),
request=self.read_string(reader),
response=self.read_string(reader),
status=self.read_uint(reader),
timestamp=self.read_uint(reader),
duration=self.read_uint(reader)
)
if message_id == 40:
return Profiler(
name=self.read_string(reader),
duration=self.read_uint(reader),
args=self.read_string(reader),
result=self.read_string(reader)
)
if message_id == 41:
return OTable(
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 42:
return StateAction(
type=self.read_string(reader)
)
if message_id == 43:
return StateActionEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
type=self.read_string(reader)
)
if message_id == 44:
return Redux(
action=self.read_string(reader),
state=self.read_string(reader),
duration=self.read_uint(reader)
)
if message_id == 45:
return Vuex(
mutation=self.read_string(reader),
state=self.read_string(reader),
)
if message_id == 46:
return MobX(
type=self.read_string(reader),
payload=self.read_string(reader),
)
if message_id == 47:
return NgRx(
action=self.read_string(reader),
state=self.read_string(reader),
duration=self.read_uint(reader)
)
if message_id == 48:
return GraphQL(
operation_kind=self.read_string(reader),
operation_name=self.read_string(reader),
variables=self.read_string(reader),
response=self.read_string(reader)
)
if message_id == 49:
return PerformanceTrack(
frames=self.read_int(reader),
ticks=self.read_int(reader),
total_js_heap_size=self.read_uint(reader),
used_js_heap_size=self.read_uint(reader)
)
if message_id == 50:
return GraphQLEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
name=self.read_string(reader)
)
if message_id == 52:
return DomDrop(
timestamp=self.read_uint(reader)
)
if message_id == 53:
return ResourceTiming(
timestamp=self.read_uint(reader),
duration=self.read_uint(reader),
ttfb=self.read_uint(reader),
header_size=self.read_uint(reader),
encoded_body_size=self.read_uint(reader),
decoded_body_size=self.read_uint(reader),
url=self.read_string(reader),
initiator=self.read_string(reader)
)
if message_id == 54:
return ConnectionInformation(
downlink=self.read_uint(reader),
type=self.read_string(reader)
)
if message_id == 55:
return SetPageVisibility(
hidden=self.read_boolean(reader)
)
if message_id == 56:
return PerformanceTrackAggr(
timestamp_start=self.read_uint(reader),
timestamp_end=self.read_uint(reader),
min_fps=self.read_uint(reader),
avg_fps=self.read_uint(reader),
max_fps=self.read_uint(reader),
min_cpu=self.read_uint(reader),
avg_cpu=self.read_uint(reader),
max_cpu=self.read_uint(reader),
min_total_js_heap_size=self.read_uint(reader),
avg_total_js_heap_size=self.read_uint(reader),
max_total_js_heap_size=self.read_uint(reader),
min_used_js_heap_size=self.read_uint(reader),
avg_used_js_heap_size=self.read_uint(reader),
max_used_js_heap_size=self.read_uint(reader)
)
if message_id == 59:
return LongTask(
timestamp=self.read_uint(reader),
duration=self.read_uint(reader),
context=self.read_uint(reader),
container_type=self.read_uint(reader),
container_src=self.read_string(reader),
container_id=self.read_string(reader),
container_name=self.read_string(reader)
)
if message_id == 60:
return SetNodeURLBasedAttribute(
id=self.read_uint(reader),
name=self.read_string(reader),
value=self.read_string(reader),
base_url=self.read_string(reader)
)
if message_id == 61:
return SetStyleData(
id=self.read_uint(reader),
data=self.read_string(reader),
base_url=self.read_string(reader)
)
if message_id == 62:
return IssueEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
type=self.read_string(reader),
context_string=self.read_string(reader),
context=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 63:
return TechnicalInfo(
type=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 64:
return CustomIssue(
name=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 65:
return PageClose()
if message_id == 90:
return IOSSessionStart(
timestamp=self.read_uint(reader),
project_id=self.read_uint(reader),
tracker_version=self.read_string(reader),
rev_id=self.read_string(reader),
user_uuid=self.read_string(reader),
user_os=self.read_string(reader),
user_os_version=self.read_string(reader),
user_device=self.read_string(reader),
user_device_type=self.read_string(reader),
user_country=self.read_string(reader)
)
if message_id == 91:
return IOSSessionEnd(
timestamp=self.read_uint(reader)
)
if message_id == 92:
return IOSMetadata(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 94:
return IOSUserID(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
value=self.read_string(reader)
)
if message_id == 95:
return IOSUserAnonymousID(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
value=self.read_string(reader)
)
if message_id == 99:
return IOSScreenLeave(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
title=self.read_string(reader),
view_name=self.read_string(reader)
)
if message_id == 103:
return IOSLog(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
severity=self.read_string(reader),
content=self.read_string(reader)
)
if message_id == 104:
return IOSInternalError(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
content=self.read_string(reader)
)
if message_id == 110:
return IOSPerformanceAggregated(
timestamp_start=self.read_uint(reader),
timestamp_end=self.read_uint(reader),
min_fps=self.read_uint(reader),
avg_fps=self.read_uint(reader),
max_fps=self.read_uint(reader),
min_cpu=self.read_uint(reader),
avg_cpu=self.read_uint(reader),
max_cpu=self.read_uint(reader),
min_memory=self.read_uint(reader),
avg_memory=self.read_uint(reader),
max_memory=self.read_uint(reader),
min_battery=self.read_uint(reader),
avg_battery=self.read_uint(reader),
max_battery=self.read_uint(reader)
)
def read_message_id(self, reader: io.BytesIO) -> int:
"""
Read and return the first byte where the message id is encoded
"""
id_ = self.read_uint(reader)
return id_
@staticmethod
def check_message_id(b: bytes) -> int:
"""
todo: make it static and without reader. It's just the first byte
Read and return the first byte where the message id is encoded
"""
reader = io.BytesIO(b)
id_ = Codec.read_uint(reader)
return id_
@staticmethod
def decode_key(b) -> int:
"""
Decode the message key (encoded with little endian)
"""
try:
decoded = int.from_bytes(b, "little", signed=False)
except Exception as e:
raise UnicodeDecodeError(f"Error while decoding message key (SessionID) from {b}\n{e}")
return decoded

View file

@ -1,13 +1,20 @@
"""
Representations of Kafka messages
"""
from abc import ABC
# Auto-generated, do not edit
from abc import ABC
class Message(ABC):
pass
class BatchMeta(Message):
__id__ = 80
def __init__(self, page_no, first_index, timestamp):
self.page_no = page_no
self.first_index = first_index
self.timestamp = timestamp
class Timestamp(Message):
__id__ = 0
@ -18,10 +25,7 @@ class Timestamp(Message):
class SessionStart(Message):
__id__ = 1
def __init__(self, timestamp, project_id, tracker_version, rev_id, user_uuid,
user_agent, user_os, user_os_version, user_browser, user_browser_version,
user_device, user_device_type, user_device_memory_size, user_device_heap_size,
user_country):
def __init__(self, timestamp, project_id, tracker_version, rev_id, user_uuid, user_agent, user_os, user_os_version, user_browser, user_browser_version, user_device, user_device_type, user_device_memory_size, user_device_heap_size, user_country, user_id):
self.timestamp = timestamp
self.project_id = project_id
self.tracker_version = tracker_version
@ -37,6 +41,7 @@ class SessionStart(Message):
self.user_device_memory_size = user_device_memory_size
self.user_device_heap_size = user_device_heap_size
self.user_country = user_country
self.user_id = user_id
class SessionDisconnect(Message):
@ -48,7 +53,6 @@ class SessionDisconnect(Message):
class SessionEnd(Message):
__id__ = 3
__name__ = 'SessionEnd'
def __init__(self, timestamp):
self.timestamp = timestamp
@ -82,13 +86,16 @@ class SetViewportScroll(Message):
class CreateDocument(Message):
__id__ = 7
def __init__(self, ):
class CreateElementNode(Message):
__id__ = 8
def __init__(self, id, parent_id, index, tag, svg):
self.id = id
self.parent_id = parent_id,
self.parent_id = parent_id
self.index = index
self.tag = tag
self.svg = svg
@ -122,7 +129,7 @@ class RemoveNode(Message):
class SetNodeAttribute(Message):
__id__ = 12
def __init__(self, id, name: str, value: str):
def __init__(self, id, name, value):
self.id = id
self.name = name
self.value = value
@ -131,7 +138,7 @@ class SetNodeAttribute(Message):
class RemoveNodeAttribute(Message):
__id__ = 13
def __init__(self, id, name: str):
def __init__(self, id, name):
self.id = id
self.name = name
@ -139,7 +146,7 @@ class RemoveNodeAttribute(Message):
class SetNodeData(Message):
__id__ = 14
def __init__(self, id, data: str):
def __init__(self, id, data):
self.id = id
self.data = data
@ -147,7 +154,7 @@ class SetNodeData(Message):
class SetCSSData(Message):
__id__ = 15
def __init__(self, id, data: str):
def __init__(self, id, data):
self.id = id
self.data = data
@ -155,7 +162,7 @@ class SetCSSData(Message):
class SetNodeScroll(Message):
__id__ = 16
def __init__(self, id, x: int, y: int):
def __init__(self, id, x, y):
self.id = id
self.x = x
self.y = y
@ -164,7 +171,7 @@ class SetNodeScroll(Message):
class SetInputTarget(Message):
__id__ = 17
def __init__(self, id, label: str):
def __init__(self, id, label):
self.id = id
self.label = label
@ -172,7 +179,7 @@ class SetInputTarget(Message):
class SetInputValue(Message):
__id__ = 18
def __init__(self, id, value: str, mask: int):
def __init__(self, id, value, mask):
self.id = id
self.value = value
self.mask = mask
@ -181,7 +188,7 @@ class SetInputValue(Message):
class SetInputChecked(Message):
__id__ = 19
def __init__(self, id, checked: bool):
def __init__(self, id, checked):
self.id = id
self.checked = checked
@ -194,10 +201,10 @@ class MouseMove(Message):
self.y = y
class MouseClick(Message):
class MouseClickDepricated(Message):
__id__ = 21
def __init__(self, id, hesitation_time, label: str):
def __init__(self, id, hesitation_time, label):
self.id = id
self.hesitation_time = hesitation_time
self.label = label
@ -206,7 +213,7 @@ class MouseClick(Message):
class ConsoleLog(Message):
__id__ = 22
def __init__(self, level: str, value: str):
def __init__(self, level, value):
self.level = level
self.value = value
@ -214,9 +221,7 @@ class ConsoleLog(Message):
class PageLoadTiming(Message):
__id__ = 23
def __init__(self, request_start, response_start, response_end, dom_content_loaded_event_start,
dom_content_loaded_event_end, load_event_start, load_event_end,
first_paint, first_contentful_paint):
def __init__(self, request_start, response_start, response_end, dom_content_loaded_event_start, dom_content_loaded_event_end, load_event_start, load_event_end, first_paint, first_contentful_paint):
self.request_start = request_start
self.response_start = response_start
self.response_end = response_end
@ -236,20 +241,20 @@ class PageRenderTiming(Message):
self.visually_complete = visually_complete
self.time_to_interactive = time_to_interactive
class JSException(Message):
__id__ = 25
def __init__(self, name: str, message: str, payload: str):
def __init__(self, name, message, payload):
self.name = name
self.message = message
self.payload = payload
class RawErrorEvent(Message):
class IntegrationEvent(Message):
__id__ = 26
def __init__(self, timestamp, source: str, name: str, message: str,
payload: str):
def __init__(self, timestamp, source, name, message, payload):
self.timestamp = timestamp
self.source = source
self.name = name
@ -260,7 +265,7 @@ class RawErrorEvent(Message):
class RawCustomEvent(Message):
__id__ = 27
def __init__(self, name: str, payload: str):
def __init__(self, name, payload):
self.name = name
self.payload = payload
@ -268,44 +273,29 @@ class RawCustomEvent(Message):
class UserID(Message):
__id__ = 28
def __init__(self, id: str):
def __init__(self, id):
self.id = id
class UserAnonymousID(Message):
__id__ = 29
def __init__(self, id: str):
def __init__(self, id):
self.id = id
class Metadata(Message):
__id__ = 30
def __init__(self, key: str, value: str):
def __init__(self, key, value):
self.key = key
self.value = value
class PerformanceTrack(Message):
__id__ = 49
def __init__(self, frames: int, ticks: int, total_js_heap_size,
used_js_heap_size):
self.frames = frames
self.ticks = ticks
self.total_js_heap_size = total_js_heap_size
self.used_js_heap_size = used_js_heap_size
class PageEvent(Message):
__id__ = 31
def __init__(self, message_id, timestamp, url: str, referrer: str,
loaded: bool, request_start, response_start, response_end,
dom_content_loaded_event_start, dom_content_loaded_event_end,
load_event_start, load_event_end, first_paint, first_contentful_paint,
speed_index, visually_complete, time_to_interactive):
def __init__(self, message_id, timestamp, url, referrer, loaded, request_start, response_start, response_end, dom_content_loaded_event_start, dom_content_loaded_event_end, load_event_start, load_event_end, first_paint, first_contentful_paint, speed_index, visually_complete, time_to_interactive):
self.message_id = message_id
self.timestamp = timestamp
self.url = url
@ -328,7 +318,7 @@ class PageEvent(Message):
class InputEvent(Message):
__id__ = 32
def __init__(self, message_id, timestamp, value: str, value_masked: bool, label: str):
def __init__(self, message_id, timestamp, value, value_masked, label):
self.message_id = message_id
self.timestamp = timestamp
self.value = value
@ -339,18 +329,18 @@ class InputEvent(Message):
class ClickEvent(Message):
__id__ = 33
def __init__(self, message_id, timestamp, hesitation_time, label: str):
def __init__(self, message_id, timestamp, hesitation_time, label, selector):
self.message_id = message_id
self.timestamp = timestamp
self.hesitation_time = hesitation_time
self.label = label
self.selector = selector
class ErrorEvent(Message):
__id__ = 34
def __init__(self, message_id, timestamp, source: str, name: str, message: str,
payload: str):
def __init__(self, message_id, timestamp, source, name, message, payload):
self.message_id = message_id
self.timestamp = timestamp
self.source = source
@ -362,8 +352,7 @@ class ErrorEvent(Message):
class ResourceEvent(Message):
__id__ = 35
def __init__(self, message_id, timestamp, duration, ttfb, header_size, encoded_body_size,
decoded_body_size, url: str, type: str, success: bool, method: str, status):
def __init__(self, message_id, timestamp, duration, ttfb, header_size, encoded_body_size, decoded_body_size, url, type, success, method, status):
self.message_id = message_id
self.timestamp = timestamp
self.duration = duration
@ -381,7 +370,7 @@ class ResourceEvent(Message):
class CustomEvent(Message):
__id__ = 36
def __init__(self, message_id, timestamp, name: str, payload: str):
def __init__(self, message_id, timestamp, name, payload):
self.message_id = message_id
self.timestamp = timestamp
self.name = name
@ -391,7 +380,7 @@ class CustomEvent(Message):
class CSSInsertRule(Message):
__id__ = 37
def __init__(self, id, rule: str, index):
def __init__(self, id, rule, index):
self.id = id
self.rule = rule
self.index = index
@ -408,8 +397,7 @@ class CSSDeleteRule(Message):
class Fetch(Message):
__id__ = 39
def __init__(self, method: str, url: str, request: str, response: str, status,
timestamp, duration):
def __init__(self, method, url, request, response, status, timestamp, duration):
self.method = method
self.url = url
self.request = request
@ -422,7 +410,7 @@ class Fetch(Message):
class Profiler(Message):
__id__ = 40
def __init__(self, name: str, duration, args: str, result: str):
def __init__(self, name, duration, args, result):
self.name = name
self.duration = duration
self.args = args
@ -432,7 +420,7 @@ class Profiler(Message):
class OTable(Message):
__id__ = 41
def __init__(self, key: str, value: str):
def __init__(self, key, value):
self.key = key
self.value = value
@ -440,14 +428,14 @@ class OTable(Message):
class StateAction(Message):
__id__ = 42
def __init__(self, type: str):
def __init__(self, type):
self.type = type
class StateActionEvent(Message):
__id__ = 43
def __init__(self, message_id, timestamp, type: str):
def __init__(self, message_id, timestamp, type):
self.message_id = message_id
self.timestamp = timestamp
self.type = type
@ -456,7 +444,7 @@ class StateActionEvent(Message):
class Redux(Message):
__id__ = 44
def __init__(self, action: str, state: str, duration):
def __init__(self, action, state, duration):
self.action = action
self.state = state
self.duration = duration
@ -465,7 +453,7 @@ class Redux(Message):
class Vuex(Message):
__id__ = 45
def __init__(self, mutation: str, state: str):
def __init__(self, mutation, state):
self.mutation = mutation
self.state = state
@ -473,7 +461,7 @@ class Vuex(Message):
class MobX(Message):
__id__ = 46
def __init__(self, type: str, payload: str):
def __init__(self, type, payload):
self.type = type
self.payload = payload
@ -481,7 +469,7 @@ class MobX(Message):
class NgRx(Message):
__id__ = 47
def __init__(self, action: str, state: str, duration):
def __init__(self, action, state, duration):
self.action = action
self.state = state
self.duration = duration
@ -490,8 +478,7 @@ class NgRx(Message):
class GraphQL(Message):
__id__ = 48
def __init__(self, operation_kind: str, operation_name: str,
variables: str, response: str):
def __init__(self, operation_kind, operation_name, variables, response):
self.operation_kind = operation_kind
self.operation_name = operation_name
self.variables = variables
@ -501,8 +488,7 @@ class GraphQL(Message):
class PerformanceTrack(Message):
__id__ = 49
def __init__(self, frames: int, ticks: int,
total_js_heap_size, used_js_heap_size):
def __init__(self, frames, ticks, total_js_heap_size, used_js_heap_size):
self.frames = frames
self.ticks = ticks
self.total_js_heap_size = total_js_heap_size
@ -512,13 +498,30 @@ class PerformanceTrack(Message):
class GraphQLEvent(Message):
__id__ = 50
def __init__(self, message_id, timestamp, name: str):
def __init__(self, message_id, timestamp, operation_kind, operation_name, variables, response):
self.message_id = message_id
self.timestamp = timestamp
self.name = name
self.operation_kind = operation_kind
self.operation_name = operation_name
self.variables = variables
self.response = response
class DomDrop(Message):
class FetchEvent(Message):
__id__ = 51
def __init__(self, message_id, timestamp, method, url, request, response, status, duration):
self.message_id = message_id
self.timestamp = timestamp
self.method = method
self.url = url
self.request = request
self.response = response
self.status = status
self.duration = duration
class DOMDrop(Message):
__id__ = 52
def __init__(self, timestamp):
@ -528,8 +531,7 @@ class DomDrop(Message):
class ResourceTiming(Message):
__id__ = 53
def __init__(self, timestamp, duration, ttfb, header_size, encoded_body_size,
decoded_body_size, url, initiator):
def __init__(self, timestamp, duration, ttfb, header_size, encoded_body_size, decoded_body_size, url, initiator):
self.timestamp = timestamp
self.duration = duration
self.ttfb = ttfb
@ -543,7 +545,7 @@ class ResourceTiming(Message):
class ConnectionInformation(Message):
__id__ = 54
def __init__(self, downlink, type: str):
def __init__(self, downlink, type):
self.downlink = downlink
self.type = type
@ -551,19 +553,14 @@ class ConnectionInformation(Message):
class SetPageVisibility(Message):
__id__ = 55
def __init__(self, hidden: bool):
def __init__(self, hidden):
self.hidden = hidden
class PerformanceTrackAggr(Message):
__id__ = 56
def __init__(self, timestamp_start, timestamp_end, min_fps, avg_fps,
max_fps, min_cpu, avg_cpu, max_cpu,
min_total_js_heap_size, avg_total_js_heap_size,
max_total_js_heap_size, min_used_js_heap_size,
avg_used_js_heap_size, max_used_js_heap_size
):
def __init__(self, timestamp_start, timestamp_end, min_fps, avg_fps, max_fps, min_cpu, avg_cpu, max_cpu, min_total_js_heap_size, avg_total_js_heap_size, max_total_js_heap_size, min_used_js_heap_size, avg_used_js_heap_size, max_used_js_heap_size):
self.timestamp_start = timestamp_start
self.timestamp_end = timestamp_end
self.min_fps = min_fps
@ -583,8 +580,7 @@ class PerformanceTrackAggr(Message):
class LongTask(Message):
__id__ = 59
def __init__(self, timestamp, duration, context, container_type, container_src: str,
container_id: str, container_name: str):
def __init__(self, timestamp, duration, context, container_type, container_src, container_id, container_name):
self.timestamp = timestamp
self.duration = duration
self.context = context
@ -594,20 +590,20 @@ class LongTask(Message):
self.container_name = container_name
class SetNodeURLBasedAttribute(Message):
class SetNodeAttributeURLBased(Message):
__id__ = 60
def __init__(self, id, name: str, value: str, base_url: str):
def __init__(self, id, name, value, base_url):
self.id = id
self.name = name
self.value = value
self.base_url = base_url
class SetStyleData(Message):
class SetCSSDataURLBased(Message):
__id__ = 61
def __init__(self, id, data: str, base_url: str):
def __init__(self, id, data, base_url):
self.id = id
self.data = data
self.base_url = base_url
@ -616,8 +612,7 @@ class SetStyleData(Message):
class IssueEvent(Message):
__id__ = 62
def __init__(self, message_id, timestamp, type: str, context_string: str,
context: str, payload: str):
def __init__(self, message_id, timestamp, type, context_string, context, payload):
self.message_id = message_id
self.timestamp = timestamp
self.type = type
@ -629,7 +624,7 @@ class IssueEvent(Message):
class TechnicalInfo(Message):
__id__ = 63
def __init__(self, type: str, value: str):
def __init__(self, type, value):
self.type = type
self.value = value
@ -637,7 +632,7 @@ class TechnicalInfo(Message):
class CustomIssue(Message):
__id__ = 64
def __init__(self, name: str, payload: str):
def __init__(self, name, payload):
self.name = name
self.payload = payload
@ -645,13 +640,58 @@ class CustomIssue(Message):
class PageClose(Message):
__id__ = 65
def __init__(self, ):
class AssetCache(Message):
__id__ = 66
def __init__(self, url):
self.url = url
class CSSInsertRuleURLBased(Message):
__id__ = 67
def __init__(self, id, rule, index, base_url):
self.id = id
self.rule = rule
self.index = index
self.base_url = base_url
class MouseClick(Message):
__id__ = 69
def __init__(self, id, hesitation_time, label, selector):
self.id = id
self.hesitation_time = hesitation_time
self.label = label
self.selector = selector
class CreateIFrameDocument(Message):
__id__ = 70
def __init__(self, frame_id, id):
self.frame_id = frame_id
self.id = id
class IOSBatchMeta(Message):
__id__ = 107
def __init__(self, timestamp, length, first_index):
self.timestamp = timestamp
self.length = length
self.first_index = first_index
class IOSSessionStart(Message):
__id__ = 90
def __init__(self, timestamp, project_id, tracker_version: str,
rev_id: str, user_uuid: str, user_os: str, user_os_version: str,
user_device: str, user_device_type: str, user_country: str):
def __init__(self, timestamp, project_id, tracker_version, rev_id, user_uuid, user_os, user_os_version, user_device, user_device_type, user_country):
self.timestamp = timestamp
self.project_id = project_id
self.tracker_version = tracker_version
@ -674,17 +714,27 @@ class IOSSessionEnd(Message):
class IOSMetadata(Message):
__id__ = 92
def __init__(self, timestamp, length, key: str, value: str):
def __init__(self, timestamp, length, key, value):
self.timestamp = timestamp
self.length = length
self.key = key
self.value = value
class IOSCustomEvent(Message):
__id__ = 93
def __init__(self, timestamp, length, name, payload):
self.timestamp = timestamp
self.length = length
self.name = name
self.payload = payload
class IOSUserID(Message):
__id__ = 94
def __init__(self, timestamp, length, value: str):
def __init__(self, timestamp, length, value):
self.timestamp = timestamp
self.length = length
self.value = value
@ -693,26 +743,91 @@ class IOSUserID(Message):
class IOSUserAnonymousID(Message):
__id__ = 95
def __init__(self, timestamp, length, value: str):
def __init__(self, timestamp, length, value):
self.timestamp = timestamp
self.length = length
self.value = value
class IOSScreenLeave(Message):
__id__ = 99
class IOSScreenChanges(Message):
__id__ = 96
def __init__(self, timestamp, length, title: str, view_name: str):
def __init__(self, timestamp, length, x, y, width, height):
self.timestamp = timestamp
self.length = length
self.x = x
self.y = y
self.width = width
self.height = height
class IOSCrash(Message):
__id__ = 97
def __init__(self, timestamp, length, name, reason, stacktrace):
self.timestamp = timestamp
self.length = length
self.name = name
self.reason = reason
self.stacktrace = stacktrace
class IOSScreenEnter(Message):
__id__ = 98
def __init__(self, timestamp, length, title, view_name):
self.timestamp = timestamp
self.length = length
self.title = title
self.view_name = view_name
class IOSScreenLeave(Message):
__id__ = 99
def __init__(self, timestamp, length, title, view_name):
self.timestamp = timestamp
self.length = length
self.title = title
self.view_name = view_name
class IOSClickEvent(Message):
__id__ = 100
def __init__(self, timestamp, length, label, x, y):
self.timestamp = timestamp
self.length = length
self.label = label
self.x = x
self.y = y
class IOSInputEvent(Message):
__id__ = 101
def __init__(self, timestamp, length, value, value_masked, label):
self.timestamp = timestamp
self.length = length
self.value = value
self.value_masked = value_masked
self.label = label
class IOSPerformanceEvent(Message):
__id__ = 102
def __init__(self, timestamp, length, name, value):
self.timestamp = timestamp
self.length = length
self.name = name
self.value = value
class IOSLog(Message):
__id__ = 103
def __init__(self, timestamp, length, severity: str, content: str):
def __init__(self, timestamp, length, severity, content):
self.timestamp = timestamp
self.length = length
self.severity = severity
@ -722,20 +837,31 @@ class IOSLog(Message):
class IOSInternalError(Message):
__id__ = 104
def __init__(self, timestamp, length, content: str):
def __init__(self, timestamp, length, content):
self.timestamp = timestamp
self.length = length
self.content = content
class IOSNetworkCall(Message):
__id__ = 105
def __init__(self, timestamp, length, duration, headers, body, url, success, method, status):
self.timestamp = timestamp
self.length = length
self.duration = duration
self.headers = headers
self.body = body
self.url = url
self.success = success
self.method = method
self.status = status
class IOSPerformanceAggregated(Message):
__id__ = 110
def __init__(self, timestamp_start, timestamp_end, min_fps, avg_fps,
max_fps, min_cpu, avg_cpu, max_cpu,
min_memory, avg_memory, max_memory,
min_battery, avg_battery, max_battery
):
def __init__(self, timestamp_start, timestamp_end, min_fps, avg_fps, max_fps, min_cpu, avg_cpu, max_cpu, min_memory, avg_memory, max_memory, min_battery, avg_battery, max_battery):
self.timestamp_start = timestamp_start
self.timestamp_end = timestamp_end
self.min_fps = min_fps
@ -750,3 +876,16 @@ class IOSPerformanceAggregated(Message):
self.min_battery = min_battery
self.avg_battery = avg_battery
self.max_battery = max_battery
class IOSIssueEvent(Message):
__id__ = 111
def __init__(self, timestamp, type, context_string, context, payload):
self.timestamp = timestamp
self.type = type
self.context_string = context_string
self.context = context
self.payload = payload

View file

@ -0,0 +1,728 @@
# Auto-generated, do not edit
from msgcodec.codec import Codec
from msgcodec.messages import *
class MessageCodec(Codec):
def read_message_id(self, reader: io.BytesIO) -> int:
"""
Read and return the first byte where the message id is encoded
"""
id_ = self.read_uint(reader)
return id_
def encode(self, m: Message) -> bytes:
...
def decode(self, b: bytes) -> Message:
reader = io.BytesIO(b)
message_id = self.read_message_id(reader)
if message_id == 80:
return BatchMeta(
page_no=self.read_uint(reader),
first_index=self.read_uint(reader),
timestamp=self.read_int(reader)
)
if message_id == 0:
return Timestamp(
timestamp=self.read_uint(reader)
)
if message_id == 1:
return SessionStart(
timestamp=self.read_uint(reader),
project_id=self.read_uint(reader),
tracker_version=self.read_string(reader),
rev_id=self.read_string(reader),
user_uuid=self.read_string(reader),
user_agent=self.read_string(reader),
user_os=self.read_string(reader),
user_os_version=self.read_string(reader),
user_browser=self.read_string(reader),
user_browser_version=self.read_string(reader),
user_device=self.read_string(reader),
user_device_type=self.read_string(reader),
user_device_memory_size=self.read_uint(reader),
user_device_heap_size=self.read_uint(reader),
user_country=self.read_string(reader),
user_id=self.read_string(reader)
)
if message_id == 2:
return SessionDisconnect(
timestamp=self.read_uint(reader)
)
if message_id == 3:
return SessionEnd(
timestamp=self.read_uint(reader)
)
if message_id == 4:
return SetPageLocation(
url=self.read_string(reader),
referrer=self.read_string(reader),
navigation_start=self.read_uint(reader)
)
if message_id == 5:
return SetViewportSize(
width=self.read_uint(reader),
height=self.read_uint(reader)
)
if message_id == 6:
return SetViewportScroll(
x=self.read_int(reader),
y=self.read_int(reader)
)
if message_id == 7:
return CreateDocument(
)
if message_id == 8:
return CreateElementNode(
id=self.read_uint(reader),
parent_id=self.read_uint(reader),
index=self.read_uint(reader),
tag=self.read_string(reader),
svg=self.read_boolean(reader)
)
if message_id == 9:
return CreateTextNode(
id=self.read_uint(reader),
parent_id=self.read_uint(reader),
index=self.read_uint(reader)
)
if message_id == 10:
return MoveNode(
id=self.read_uint(reader),
parent_id=self.read_uint(reader),
index=self.read_uint(reader)
)
if message_id == 11:
return RemoveNode(
id=self.read_uint(reader)
)
if message_id == 12:
return SetNodeAttribute(
id=self.read_uint(reader),
name=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 13:
return RemoveNodeAttribute(
id=self.read_uint(reader),
name=self.read_string(reader)
)
if message_id == 14:
return SetNodeData(
id=self.read_uint(reader),
data=self.read_string(reader)
)
if message_id == 15:
return SetCSSData(
id=self.read_uint(reader),
data=self.read_string(reader)
)
if message_id == 16:
return SetNodeScroll(
id=self.read_uint(reader),
x=self.read_int(reader),
y=self.read_int(reader)
)
if message_id == 17:
return SetInputTarget(
id=self.read_uint(reader),
label=self.read_string(reader)
)
if message_id == 18:
return SetInputValue(
id=self.read_uint(reader),
value=self.read_string(reader),
mask=self.read_int(reader)
)
if message_id == 19:
return SetInputChecked(
id=self.read_uint(reader),
checked=self.read_boolean(reader)
)
if message_id == 20:
return MouseMove(
x=self.read_uint(reader),
y=self.read_uint(reader)
)
if message_id == 21:
return MouseClickDepricated(
id=self.read_uint(reader),
hesitation_time=self.read_uint(reader),
label=self.read_string(reader)
)
if message_id == 22:
return ConsoleLog(
level=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 23:
return PageLoadTiming(
request_start=self.read_uint(reader),
response_start=self.read_uint(reader),
response_end=self.read_uint(reader),
dom_content_loaded_event_start=self.read_uint(reader),
dom_content_loaded_event_end=self.read_uint(reader),
load_event_start=self.read_uint(reader),
load_event_end=self.read_uint(reader),
first_paint=self.read_uint(reader),
first_contentful_paint=self.read_uint(reader)
)
if message_id == 24:
return PageRenderTiming(
speed_index=self.read_uint(reader),
visually_complete=self.read_uint(reader),
time_to_interactive=self.read_uint(reader)
)
if message_id == 25:
return JSException(
name=self.read_string(reader),
message=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 26:
return IntegrationEvent(
timestamp=self.read_uint(reader),
source=self.read_string(reader),
name=self.read_string(reader),
message=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 27:
return RawCustomEvent(
name=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 28:
return UserID(
id=self.read_string(reader)
)
if message_id == 29:
return UserAnonymousID(
id=self.read_string(reader)
)
if message_id == 30:
return Metadata(
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 31:
return PageEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
url=self.read_string(reader),
referrer=self.read_string(reader),
loaded=self.read_boolean(reader),
request_start=self.read_uint(reader),
response_start=self.read_uint(reader),
response_end=self.read_uint(reader),
dom_content_loaded_event_start=self.read_uint(reader),
dom_content_loaded_event_end=self.read_uint(reader),
load_event_start=self.read_uint(reader),
load_event_end=self.read_uint(reader),
first_paint=self.read_uint(reader),
first_contentful_paint=self.read_uint(reader),
speed_index=self.read_uint(reader),
visually_complete=self.read_uint(reader),
time_to_interactive=self.read_uint(reader)
)
if message_id == 32:
return InputEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
value=self.read_string(reader),
value_masked=self.read_boolean(reader),
label=self.read_string(reader)
)
if message_id == 33:
return ClickEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
hesitation_time=self.read_uint(reader),
label=self.read_string(reader),
selector=self.read_string(reader)
)
if message_id == 34:
return ErrorEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
source=self.read_string(reader),
name=self.read_string(reader),
message=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 35:
return ResourceEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
duration=self.read_uint(reader),
ttfb=self.read_uint(reader),
header_size=self.read_uint(reader),
encoded_body_size=self.read_uint(reader),
decoded_body_size=self.read_uint(reader),
url=self.read_string(reader),
type=self.read_string(reader),
success=self.read_boolean(reader),
method=self.read_string(reader),
status=self.read_uint(reader)
)
if message_id == 36:
return CustomEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
name=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 37:
return CSSInsertRule(
id=self.read_uint(reader),
rule=self.read_string(reader),
index=self.read_uint(reader)
)
if message_id == 38:
return CSSDeleteRule(
id=self.read_uint(reader),
index=self.read_uint(reader)
)
if message_id == 39:
return Fetch(
method=self.read_string(reader),
url=self.read_string(reader),
request=self.read_string(reader),
response=self.read_string(reader),
status=self.read_uint(reader),
timestamp=self.read_uint(reader),
duration=self.read_uint(reader)
)
if message_id == 40:
return Profiler(
name=self.read_string(reader),
duration=self.read_uint(reader),
args=self.read_string(reader),
result=self.read_string(reader)
)
if message_id == 41:
return OTable(
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 42:
return StateAction(
type=self.read_string(reader)
)
if message_id == 43:
return StateActionEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
type=self.read_string(reader)
)
if message_id == 44:
return Redux(
action=self.read_string(reader),
state=self.read_string(reader),
duration=self.read_uint(reader)
)
if message_id == 45:
return Vuex(
mutation=self.read_string(reader),
state=self.read_string(reader)
)
if message_id == 46:
return MobX(
type=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 47:
return NgRx(
action=self.read_string(reader),
state=self.read_string(reader),
duration=self.read_uint(reader)
)
if message_id == 48:
return GraphQL(
operation_kind=self.read_string(reader),
operation_name=self.read_string(reader),
variables=self.read_string(reader),
response=self.read_string(reader)
)
if message_id == 49:
return PerformanceTrack(
frames=self.read_int(reader),
ticks=self.read_int(reader),
total_js_heap_size=self.read_uint(reader),
used_js_heap_size=self.read_uint(reader)
)
if message_id == 50:
return GraphQLEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
operation_kind=self.read_string(reader),
operation_name=self.read_string(reader),
variables=self.read_string(reader),
response=self.read_string(reader)
)
if message_id == 51:
return FetchEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
method=self.read_string(reader),
url=self.read_string(reader),
request=self.read_string(reader),
response=self.read_string(reader),
status=self.read_uint(reader),
duration=self.read_uint(reader)
)
if message_id == 52:
return DOMDrop(
timestamp=self.read_uint(reader)
)
if message_id == 53:
return ResourceTiming(
timestamp=self.read_uint(reader),
duration=self.read_uint(reader),
ttfb=self.read_uint(reader),
header_size=self.read_uint(reader),
encoded_body_size=self.read_uint(reader),
decoded_body_size=self.read_uint(reader),
url=self.read_string(reader),
initiator=self.read_string(reader)
)
if message_id == 54:
return ConnectionInformation(
downlink=self.read_uint(reader),
type=self.read_string(reader)
)
if message_id == 55:
return SetPageVisibility(
hidden=self.read_boolean(reader)
)
if message_id == 56:
return PerformanceTrackAggr(
timestamp_start=self.read_uint(reader),
timestamp_end=self.read_uint(reader),
min_fps=self.read_uint(reader),
avg_fps=self.read_uint(reader),
max_fps=self.read_uint(reader),
min_cpu=self.read_uint(reader),
avg_cpu=self.read_uint(reader),
max_cpu=self.read_uint(reader),
min_total_js_heap_size=self.read_uint(reader),
avg_total_js_heap_size=self.read_uint(reader),
max_total_js_heap_size=self.read_uint(reader),
min_used_js_heap_size=self.read_uint(reader),
avg_used_js_heap_size=self.read_uint(reader),
max_used_js_heap_size=self.read_uint(reader)
)
if message_id == 59:
return LongTask(
timestamp=self.read_uint(reader),
duration=self.read_uint(reader),
context=self.read_uint(reader),
container_type=self.read_uint(reader),
container_src=self.read_string(reader),
container_id=self.read_string(reader),
container_name=self.read_string(reader)
)
if message_id == 60:
return SetNodeAttributeURLBased(
id=self.read_uint(reader),
name=self.read_string(reader),
value=self.read_string(reader),
base_url=self.read_string(reader)
)
if message_id == 61:
return SetCSSDataURLBased(
id=self.read_uint(reader),
data=self.read_string(reader),
base_url=self.read_string(reader)
)
if message_id == 62:
return IssueEvent(
message_id=self.read_uint(reader),
timestamp=self.read_uint(reader),
type=self.read_string(reader),
context_string=self.read_string(reader),
context=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 63:
return TechnicalInfo(
type=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 64:
return CustomIssue(
name=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 65:
return PageClose(
)
if message_id == 66:
return AssetCache(
url=self.read_string(reader)
)
if message_id == 67:
return CSSInsertRuleURLBased(
id=self.read_uint(reader),
rule=self.read_string(reader),
index=self.read_uint(reader),
base_url=self.read_string(reader)
)
if message_id == 69:
return MouseClick(
id=self.read_uint(reader),
hesitation_time=self.read_uint(reader),
label=self.read_string(reader),
selector=self.read_string(reader)
)
if message_id == 70:
return CreateIFrameDocument(
frame_id=self.read_uint(reader),
id=self.read_uint(reader)
)
if message_id == 107:
return IOSBatchMeta(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
first_index=self.read_uint(reader)
)
if message_id == 90:
return IOSSessionStart(
timestamp=self.read_uint(reader),
project_id=self.read_uint(reader),
tracker_version=self.read_string(reader),
rev_id=self.read_string(reader),
user_uuid=self.read_string(reader),
user_os=self.read_string(reader),
user_os_version=self.read_string(reader),
user_device=self.read_string(reader),
user_device_type=self.read_string(reader),
user_country=self.read_string(reader)
)
if message_id == 91:
return IOSSessionEnd(
timestamp=self.read_uint(reader)
)
if message_id == 92:
return IOSMetadata(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
key=self.read_string(reader),
value=self.read_string(reader)
)
if message_id == 93:
return IOSCustomEvent(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
name=self.read_string(reader),
payload=self.read_string(reader)
)
if message_id == 94:
return IOSUserID(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
value=self.read_string(reader)
)
if message_id == 95:
return IOSUserAnonymousID(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
value=self.read_string(reader)
)
if message_id == 96:
return IOSScreenChanges(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
x=self.read_uint(reader),
y=self.read_uint(reader),
width=self.read_uint(reader),
height=self.read_uint(reader)
)
if message_id == 97:
return IOSCrash(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
name=self.read_string(reader),
reason=self.read_string(reader),
stacktrace=self.read_string(reader)
)
if message_id == 98:
return IOSScreenEnter(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
title=self.read_string(reader),
view_name=self.read_string(reader)
)
if message_id == 99:
return IOSScreenLeave(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
title=self.read_string(reader),
view_name=self.read_string(reader)
)
if message_id == 100:
return IOSClickEvent(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
label=self.read_string(reader),
x=self.read_uint(reader),
y=self.read_uint(reader)
)
if message_id == 101:
return IOSInputEvent(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
value=self.read_string(reader),
value_masked=self.read_boolean(reader),
label=self.read_string(reader)
)
if message_id == 102:
return IOSPerformanceEvent(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
name=self.read_string(reader),
value=self.read_uint(reader)
)
if message_id == 103:
return IOSLog(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
severity=self.read_string(reader),
content=self.read_string(reader)
)
if message_id == 104:
return IOSInternalError(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
content=self.read_string(reader)
)
if message_id == 105:
return IOSNetworkCall(
timestamp=self.read_uint(reader),
length=self.read_uint(reader),
duration=self.read_uint(reader),
headers=self.read_string(reader),
body=self.read_string(reader),
url=self.read_string(reader),
success=self.read_boolean(reader),
method=self.read_string(reader),
status=self.read_uint(reader)
)
if message_id == 110:
return IOSPerformanceAggregated(
timestamp_start=self.read_uint(reader),
timestamp_end=self.read_uint(reader),
min_fps=self.read_uint(reader),
avg_fps=self.read_uint(reader),
max_fps=self.read_uint(reader),
min_cpu=self.read_uint(reader),
avg_cpu=self.read_uint(reader),
max_cpu=self.read_uint(reader),
min_memory=self.read_uint(reader),
avg_memory=self.read_uint(reader),
max_memory=self.read_uint(reader),
min_battery=self.read_uint(reader),
avg_battery=self.read_uint(reader),
max_battery=self.read_uint(reader)
)
if message_id == 111:
return IOSIssueEvent(
timestamp=self.read_uint(reader),
type=self.read_string(reader),
context_string=self.read_string(reader),
context=self.read_string(reader),
payload=self.read_string(reader)
)

View file

@ -661,24 +661,24 @@ $$
);
CREATE UNIQUE INDEX IF NOT EXISTS autocomplete_unique_project_id_md5value_type_idx ON autocomplete (project_id, md5(value), type);
CREATE index IF NOT EXISTS autocomplete_project_id_idx ON autocomplete (project_id);
CREATE INDEX IF NOT EXISTS autocomplete_project_id_idx ON autocomplete (project_id);
CREATE INDEX IF NOT EXISTS autocomplete_type_idx ON public.autocomplete (type);
CREATE INDEX autocomplete_value_clickonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'CLICK';
CREATE INDEX autocomplete_value_customonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'CUSTOM';
CREATE INDEX autocomplete_value_graphqlonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'GRAPHQL';
CREATE INDEX autocomplete_value_inputonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'INPUT';
CREATE INDEX autocomplete_value_locationonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'LOCATION';
CREATE INDEX autocomplete_value_referreronly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'REFERRER';
CREATE INDEX autocomplete_value_requestonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'REQUEST';
CREATE INDEX autocomplete_value_revidonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'REVID';
CREATE INDEX autocomplete_value_stateactiononly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'STATEACTION';
CREATE INDEX autocomplete_value_useranonymousidonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERANONYMOUSID';
CREATE INDEX autocomplete_value_userbrowseronly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERBROWSER';
CREATE INDEX autocomplete_value_usercountryonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERCOUNTRY';
CREATE INDEX autocomplete_value_userdeviceonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERDEVICE';
CREATE INDEX autocomplete_value_useridonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERID';
CREATE INDEX autocomplete_value_userosonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USEROS';
CREATE INDEX IF NOT EXISTS autocomplete_value_clickonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'CLICK';
CREATE INDEX IF NOT EXISTS autocomplete_value_customonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'CUSTOM';
CREATE INDEX IF NOT EXISTS autocomplete_value_graphqlonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'GRAPHQL';
CREATE INDEX IF NOT EXISTS autocomplete_value_inputonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'INPUT';
CREATE INDEX IF NOT EXISTS autocomplete_value_locationonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'LOCATION';
CREATE INDEX IF NOT EXISTS autocomplete_value_referreronly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'REFERRER';
CREATE INDEX IF NOT EXISTS autocomplete_value_requestonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'REQUEST';
CREATE INDEX IF NOT EXISTS autocomplete_value_revidonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'REVID';
CREATE INDEX IF NOT EXISTS autocomplete_value_stateactiononly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'STATEACTION';
CREATE INDEX IF NOT EXISTS autocomplete_value_useranonymousidonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERANONYMOUSID';
CREATE INDEX IF NOT EXISTS autocomplete_value_userbrowseronly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERBROWSER';
CREATE INDEX IF NOT EXISTS autocomplete_value_usercountryonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERCOUNTRY';
CREATE INDEX IF NOT EXISTS autocomplete_value_userdeviceonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERDEVICE';
CREATE INDEX IF NOT EXISTS autocomplete_value_useridonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USERID';
CREATE INDEX IF NOT EXISTS autocomplete_value_userosonly_gin_idx ON public.autocomplete USING GIN (value gin_trgm_ops) WHERE type = 'USEROS';
BEGIN
IF NOT EXISTS(SELECT *

View file

@ -112,9 +112,9 @@
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
},
"node_modules/@types/node": {
"version": "18.0.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz",
"integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ=="
"version": "18.6.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.1.tgz",
"integrity": "sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg=="
},
"node_modules/accepts": {
"version": "1.3.8",
@ -1179,9 +1179,9 @@
"integrity": "sha512-vt+kDhq/M2ayberEtJcIN/hxXy1Pk+59g2FV/ZQceeaTyCtCucjL2Q7FXlFjtWn4n15KCr1NE2lNNFhp0lEThw=="
},
"@types/node": {
"version": "18.0.3",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.0.3.tgz",
"integrity": "sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ=="
"version": "18.6.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.6.1.tgz",
"integrity": "sha512-z+2vB6yDt1fNwKOeGbckpmirO+VBDuQqecXkgeIqDlaOtmKn6hPR/viQ8cxCfqLU4fTlvM3+YjM367TukWdxpg=="
},
"accepts": {
"version": "1.3.8",

View file

@ -91,6 +91,7 @@ const extractPayloadFromRequest = async function (req, res) {
return helper.extractPayloadFromRequest(req);
}
filters.filter = helper.objectToObjectOfArrays(filters.filter);
filters.filter = helper.transformFilters(filters.filter);
debug && console.log("payload/filters:" + JSON.stringify(filters))
return Object.keys(filters).length > 0 ? filters : undefined;
}

View file

@ -31,7 +31,7 @@ const LiveSessionPure = lazy(() => import('Components/Session/LiveSession'));
const OnboardingPure = lazy(() => import('Components/Onboarding/Onboarding'));
const ClientPure = lazy(() => import('Components/Client/Client'));
const AssistPure = lazy(() => import('Components/Assist'));
const BugFinderPure = lazy(() => import('Components/BugFinder/BugFinder'));
const BugFinderPure = lazy(() => import('Components/Overview'));
const DashboardPure = lazy(() => import('Components/Dashboard/NewDashboard'));
const ErrorsPure = lazy(() => import('Components/Errors/Errors'));
const FunnelDetailsPure = lazy(() => import('Components/Funnels/FunnelDetails'));

View file

@ -24,7 +24,7 @@ function SessionList(props: Props) {
return (
<div style={{ width: '50vw' }}>
<div className="border-r shadow h-screen" style={{ backgroundColor: '#FAFAFA', zIndex: 999, width: '100%', minWidth: '700px' }}>
<div className="border-r shadow h-screen overflow-y-auto" style={{ backgroundColor: '#FAFAFA', zIndex: 999, width: '100%', minWidth: '700px' }}>
<div className="p-4">
<div className="text-2xl">
{props.userId}'s <span className="color-gray-medium">Live Sessions</span>{' '}

View file

@ -26,7 +26,7 @@ function SessionListHeader({ activeTab, count, applyFilter, filter }) {
}, [label]);
const { startDate, endDate, rangeValue } = filter;
const period = new Record({ start: startDate, end: endDate, rangeName: rangeValue });
const period = new Record({ start: startDate, end: endDate, rangeName: rangeValue, timezoneOffset: getTimeZoneOffset() });
const onDateChange = (e) => {
const dateValues = e.toJSON();
@ -36,10 +36,12 @@ function SessionListHeader({ activeTab, count, applyFilter, filter }) {
};
React.useEffect(() => {
const dateValues = period.toJSON();
dateValues.startDate = moment(dateValues.startDate).startOf('day').utcOffset(getTimeZoneOffset(), true).valueOf();
dateValues.endDate = moment(dateValues.endDate).endOf('day').utcOffset(getTimeZoneOffset(), true).valueOf();
applyFilter(dateValues);
if (label) {
const dateValues = period.toJSON();
dateValues.startDate = moment(dateValues.startDate).startOf('day').utcOffset(getTimeZoneOffset(), true).valueOf();
dateValues.endDate = moment(dateValues.endDate).endOf('day').utcOffset(getTimeZoneOffset(), true).valueOf();
applyFilter(dateValues);
}
}, [label]);
return (

View file

@ -35,9 +35,9 @@ export default class IntegrationForm extends React.PureComponent {
onChangeSelect = ({ value }) => {
const { sites, list, name } = this.props;
const site = sites.find(s => s.id === value);
const site = sites.find(s => s.id === value.value);
this.setState({ currentSiteId: site.id })
this.init(value);
this.init(value.value);
}
init = (siteId) => {

View file

@ -153,6 +153,7 @@ function UserForm(props: Props) {
));
}
export default connect(state => ({
export default connect((state: any) => ({
isEnterprise: state.getIn([ 'user', 'account', 'edition' ]) === 'ee',
isSmtp: state.getIn([ 'user', 'account', 'smtp' ]),
}))(UserForm);

View file

@ -0,0 +1,28 @@
import React from 'react';
import withPageTitle from 'HOCs/withPageTitle';
import NoSessionsMessage from 'Shared/NoSessionsMessage';
import MainSearchBar from 'Shared/MainSearchBar';
import SessionSearch from 'Shared/SessionSearch';
import SessionListContainer from 'Shared/SessionListContainer/SessionListContainer';
function Overview() {
return (
<div className="page-margin container-90 flex relative">
<div className="flex-1 flex">
<div className={'w-full mx-auto'} style={{ maxWidth: '1300px' }}>
<NoSessionsMessage />
<div className="mb-5">
<MainSearchBar />
<SessionSearch />
<div className="my-4" />
<SessionListContainer />
</div>
</div>
</div>
</div>
);
}
export default withPageTitle('Sessions - OpenReplay')(Overview);

View file

@ -0,0 +1 @@
export { default } from './Overview';

View file

@ -1,4 +1,4 @@
import React, { useEffect } from 'react';
import React, { Fragment, useEffect } from 'react';
import { connect } from 'react-redux';
import { NoContent, Loader, Pagination } from 'UI';
import { List } from 'immutable';

View file

@ -104,7 +104,7 @@ export default function<Value extends ValueObject>({ placeholder='Select', name
const opacity = state.isDisabled ? 0.5 : 1;
const transition = 'opacity 300ms';
return { ...provided, opacity, transition };
return { ...provided, opacity, transition, fontWeight: 'bold' };
},
input: (provided: any) => ({
...provided,

View file

@ -39,7 +39,7 @@ function SelectDateRange(props: Props) {
};
const isCustomRange = period.rangeName === CUSTOM_RANGE;
const customRange = isCustomRange ? period.rangeFormatted(undefined, timezone) : '';
const customRange = isCustomRange ? period.rangeFormatted() : '';
return (
<div className="relative">
<Select
@ -75,7 +75,7 @@ function SelectDateRange(props: Props) {
width: '770px',
}}
>
<DateRangePopup onApply={onApplyDateRange} onCancel={() => setIsCustom(false)} selectedDateRange={period.range} />
<DateRangePopup timezone={timezone} onApply={onApplyDateRange} onCancel={() => setIsCustom(false)} selectedDateRange={period.range} />
</div>
</OutsideClickDetectingDiv>
)}

View file

@ -1,44 +1,42 @@
import React, { useState, useEffect } from 'react'
import {
Link,
Icon,
} from 'UI';
import React, { useState, useEffect } from 'react';
import { Link, Icon } from 'UI';
import { session as sessionRoute, liveSession as liveSessionRoute } from 'App/routes';
const PLAY_ICON_NAMES = {
notPlayed: 'play-fill',
played: 'play-circle-light',
hovered: 'play-hover'
}
hovered: 'play-hover',
};
const getDefaultIconName = (isViewed) => !isViewed ? PLAY_ICON_NAMES.notPlayed : PLAY_ICON_NAMES.played
const getDefaultIconName = (isViewed: any) => (!isViewed ? PLAY_ICON_NAMES.notPlayed : PLAY_ICON_NAMES.played);
interface Props {
isAssist: boolean;
viewed: boolean;
sessionId: string;
onClick?: () => void;
queryParams: any;
}
export default function PlayLink(props: Props) {
const { isAssist, viewed, sessionId, onClick = null } = props
const defaultIconName = getDefaultIconName(viewed)
const { isAssist, viewed, sessionId, onClick = null, queryParams } = props;
const defaultIconName = getDefaultIconName(viewed);
const [isHovered, toggleHover] = useState(false)
const [iconName, setIconName] = useState(defaultIconName)
const [isHovered, toggleHover] = useState(false);
const [iconName, setIconName] = useState(defaultIconName);
useEffect(() => {
if (isHovered) setIconName(PLAY_ICON_NAMES.hovered)
else setIconName(getDefaultIconName(viewed))
}, [isHovered, viewed])
if (isHovered) setIconName(PLAY_ICON_NAMES.hovered);
else setIconName(getDefaultIconName(viewed));
}, [isHovered, viewed]);
return (
<Link
onClick={onClick ? onClick : () => {}}
to={ isAssist ? liveSessionRoute(sessionId) : sessionRoute(sessionId) }
to={isAssist ? liveSessionRoute(sessionId, queryParams) : sessionRoute(sessionId)}
onMouseEnter={() => toggleHover(true)}
onMouseLeave={() => toggleHover(false)}
>
<Icon name={iconName} size={38} color={isAssist ? "tealx" : "teal"} />
<Icon name={iconName} size={38} color={isAssist ? 'tealx' : 'teal'} />
</Link>
)
}
);
}

View file

@ -1,192 +1,191 @@
import React from 'react'
import React, { useEffect } from 'react';
import cn from 'classnames';
import {
CountryFlag,
Avatar,
TextEllipsis,
Label,
Icon,
} from 'UI';
import { CountryFlag, Avatar, TextEllipsis, Label, Icon } from 'UI';
import { useStore } from 'App/mstore';
import { observer } from 'mobx-react-lite';
import { durationFormatted, formatTimeOrDate } from 'App/date';
import stl from './sessionItem.module.css';
import Counter from './Counter'
import Counter from './Counter';
import { withRouter, RouteComponentProps } from 'react-router-dom';
import SessionMetaList from './SessionMetaList';
import PlayLink from './PlayLink';
import ErrorBars from './ErrorBars';
import { assist as assistRoute, liveSession, sessions as sessionsRoute, isRoute } from "App/routes";
import { assist as assistRoute, liveSession, sessions as sessionsRoute, isRoute } from 'App/routes';
import { capitalize } from 'App/utils';
const ASSIST_ROUTE = assistRoute();
const ASSIST_LIVE_SESSION = liveSession()
const ASSIST_LIVE_SESSION = liveSession();
const SESSIONS_ROUTE = sessionsRoute();
interface Props {
session: {
sessionId: string;
userBrowser: string;
userOs: string;
userId: string;
userAnonymousId: string;
userDisplayName: string;
userCountry: string;
startedAt: number;
duration: string;
eventsCount: number;
errorsCount: number;
pagesCount: number;
viewed: boolean;
favorite: boolean;
userDeviceType: string;
userUuid: string;
userNumericHash: number;
live: boolean;
metadata: Record<string, any>;
userSessionsCount: number;
issueTypes: [];
active: boolean;
},
onUserClick?: (userId: string, userAnonymousId: string) => void;
hasUserFilter?: boolean;
disableUser?: boolean;
metaList?: Array<any>;
// showActive?: boolean;
lastPlayedSessionId?: string;
live?: boolean;
onClick?: any
session: {
sessionId: string;
userBrowser: string;
userOs: string;
userId: string;
userAnonymousId: string;
userDisplayName: string;
userCountry: string;
startedAt: number;
duration: string;
eventsCount: number;
errorsCount: number;
pagesCount: number;
viewed: boolean;
favorite: boolean;
userDeviceType: string;
userUuid: string;
userNumericHash: number;
live: boolean;
metadata: Record<string, any>;
userSessionsCount: number;
issueTypes: [];
active: boolean;
};
onUserClick?: (userId: string, userAnonymousId: string) => void;
hasUserFilter?: boolean;
disableUser?: boolean;
metaList?: Array<any>;
// showActive?: boolean;
lastPlayedSessionId?: string;
live?: boolean;
onClick?: any;
}
function SessionItem(props: RouteComponentProps & Props) {
const { settingsStore } = useStore();
const { timezone } = settingsStore.sessionSettings;
const { settingsStore } = useStore();
const { timezone } = settingsStore.sessionSettings;
const [isIframe, setIsIframe] = React.useState(false);
const {
session,
onUserClick = () => null,
hasUserFilter = false,
disableUser = false,
metaList = [],
lastPlayedSessionId,
onClick = null,
} = props;
const {
session,
onUserClick = () => null,
hasUserFilter = false,
disableUser = false,
metaList = [],
lastPlayedSessionId,
onClick = null,
} = props;
const {
sessionId,
userBrowser,
userOs,
userId,
userAnonymousId,
userDisplayName,
userCountry,
startedAt,
duration,
eventsCount,
viewed,
userDeviceType,
userNumericHash,
live,
metadata,
issueTypes,
active,
} = session;
const {
sessionId,
userBrowser,
userOs,
userId,
userAnonymousId,
userDisplayName,
userCountry,
startedAt,
duration,
eventsCount,
viewed,
userDeviceType,
userNumericHash,
live,
metadata,
issueTypes,
active,
} = session;
const location = props.location;
const location = props.location;
const queryParams = Object.fromEntries(new URLSearchParams(location.search));
const formattedDuration = durationFormatted(duration);
const hasUserId = userId || userAnonymousId;
const isSessions = isRoute(SESSIONS_ROUTE, location.pathname);
const isAssist = isRoute(ASSIST_ROUTE, location.pathname) || isRoute(ASSIST_LIVE_SESSION, location.pathname);
const isLastPlayed = lastPlayedSessionId === sessionId;
const formattedDuration = durationFormatted(duration);
const hasUserId = userId || userAnonymousId;
const isSessions = isRoute(SESSIONS_ROUTE, location.pathname);
const isAssist = isRoute(ASSIST_ROUTE, location.pathname) || isRoute(ASSIST_LIVE_SESSION, location.pathname);
const isLastPlayed = lastPlayedSessionId === sessionId;
const _metaList = Object.keys(metadata).filter(i => metaList.includes(i)).map(key => {
const value = metadata[key];
return { label: key, value };
});
const _metaList = Object.keys(metadata)
.filter((i) => metaList.includes(i))
.map((key) => {
const value = metadata[key];
return { label: key, value };
});
return (
<div className={ cn(stl.sessionItem, "flex flex-col p-2") } id="session-item" onClick={(e) => e.stopPropagation()}>
<div className="flex items-start">
<div className={ cn('flex items-center w-full')}>
<div className="flex items-center pr-2 shrink-0" style={{ width: "40%"}}>
<div><Avatar isActive={active} seed={ userNumericHash } isAssist={isAssist} /></div>
<div className="flex flex-col overflow-hidden color-gray-medium ml-3 justify-between items-center shrink-0">
<div
className={cn('text-lg', {'color-teal cursor-pointer': !disableUser && hasUserId, [stl.userName]: !disableUser && hasUserId, 'color-gray-medium' : disableUser || !hasUserId})}
onClick={() => (!disableUser && !hasUserFilter) && onUserClick(userId, userAnonymousId)}
>
<TextEllipsis text={userDisplayName} maxWidth="200px" popupProps={{ inverted: true, size: 'tiny' }} />
return (
<div className={cn(stl.sessionItem, 'flex flex-col p-2')} id="session-item" onClick={(e) => e.stopPropagation()}>
<div className="flex items-start">
<div className={cn('flex items-center w-full')}>
<div className="flex items-center pr-2 shrink-0" style={{ width: '40%' }}>
<div>
<Avatar isActive={active} seed={userNumericHash} isAssist={isAssist} />
</div>
<div className="flex flex-col overflow-hidden color-gray-medium ml-3 justify-between items-center shrink-0">
<div
className={cn('text-lg', {
'color-teal cursor-pointer': !disableUser && hasUserId,
[stl.userName]: !disableUser && hasUserId,
'color-gray-medium': disableUser || !hasUserId,
})}
onClick={() => !disableUser && !hasUserFilter && onUserClick(userId, userAnonymousId)}
>
<TextEllipsis text={userDisplayName} maxWidth="200px" popupProps={{ inverted: true, size: 'tiny' }} />
</div>
</div>
</div>
<div style={{ width: '20%' }} className="px-2 flex flex-col justify-between">
<div>
<TextEllipsis text={formatTimeOrDate(startedAt, timezone)} popupProps={{ inverted: true, size: 'tiny' }} />
</div>
<div className="flex items-center color-gray-medium py-1">
{!isAssist && (
<>
<div className="color-gray-medium">
<span className="mr-1">{eventsCount}</span>
<span>{eventsCount === 0 || eventsCount > 1 ? 'Events' : 'Event'}</span>
</div>
<Icon name="circle-fill" size={3} className="mx-4" />
</>
)}
<div>{live ? <Counter startTime={startedAt} /> : formattedDuration}</div>
</div>
</div>
<div style={{ width: '30%' }} className="px-2 flex flex-col justify-between">
<div style={{ height: '21px' }}>
<CountryFlag country={userCountry} style={{ paddingTop: '4px' }} label />
</div>
<div className="color-gray-medium flex items-center py-1">
<span className="capitalize" style={{ maxWidth: '70px' }}>
<TextEllipsis text={capitalize(userBrowser)} popupProps={{ inverted: true, size: 'tiny' }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px' }}>
<TextEllipsis text={capitalize(userOs)} popupProps={{ inverted: true, size: 'tiny' }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px' }}>
<TextEllipsis text={capitalize(userDeviceType)} popupProps={{ inverted: true, size: 'tiny' }} />
</span>
</div>
</div>
{isSessions && (
<div style={{ width: '10%' }} className="self-center px-2 flex items-center">
<ErrorBars count={issueTypes.length} />
</div>
)}
</div>
</div>
</div>
<div style={{ width: "20%" }} className="px-2 flex flex-col justify-between">
<div>
<TextEllipsis text={formatTimeOrDate(startedAt, timezone)} popupProps={{ inverted: true, size: 'tiny' }} />
</div>
<div className="flex items-center color-gray-medium py-1">
{!isAssist && (
<>
<div className="color-gray-medium">
<span className="mr-1">{ eventsCount }</span>
<span>{ eventsCount === 0 || eventsCount > 1 ? 'Events' : 'Event' }</span>
</div>
<Icon name="circle-fill" size={3} className="mx-4" />
</>
)}
<div>{ live ? <Counter startTime={startedAt} /> : formattedDuration }</div>
</div>
</div>
<div style={{ width: "30%" }} className="px-2 flex flex-col justify-between">
<div style={{ height: '21px'}}>
<CountryFlag country={ userCountry } style={{ paddingTop: '4px' }} label />
</div>
<div className="color-gray-medium flex items-center py-1">
<span className="capitalize" style={{ maxWidth: '70px'}}>
<TextEllipsis text={ capitalize(userBrowser) } popupProps={{ inverted: true, size: "tiny" }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px'}}>
<TextEllipsis text={ capitalize(userOs) } popupProps={{ inverted: true, size: "tiny" }} />
</span>
<Icon name="circle-fill" size={3} className="mx-4" />
<span className="capitalize" style={{ maxWidth: '70px'}}>
<TextEllipsis text={ capitalize(userDeviceType) } popupProps={{ inverted: true, size: "tiny" }} />
</span>
</div>
</div>
{ isSessions && (
<div style={{ width: "10%"}} className="self-center px-2 flex items-center">
<ErrorBars count={issueTypes.length} />
</div>
)}
</div>
<div className="flex items-center">
<div className={ stl.playLink } id="play-button" data-viewed={ viewed }>
{ isSessions && (
<div className="mr-4 flex-shrink-0 w-24">
{ isLastPlayed && (
<Label className="bg-gray-lightest p-1 px-2 rounded-lg">
<span className="color-gray-medium text-xs" style={{ whiteSpace: 'nowrap'}}>LAST PLAYED</span>
</Label>
)}
<div className="flex items-center">
<div className={stl.playLink} id="play-button" data-viewed={viewed}>
{isSessions && (
<div className="mr-4 flex-shrink-0 w-24">
{isLastPlayed && (
<Label className="bg-gray-lightest p-1 px-2 rounded-lg">
<span className="color-gray-medium text-xs" style={{ whiteSpace: 'nowrap' }}>
LAST PLAYED
</span>
</Label>
)}
</div>
)}
<PlayLink isAssist={isAssist} sessionId={sessionId} viewed={viewed} onClick={onClick} queryParams={queryParams} />
</div>
</div>
)}
<PlayLink
isAssist={isAssist}
sessionId={sessionId}
viewed={viewed}
onClick={onClick}
/>
</div>
</div>
{_metaList.length > 0 && <SessionMetaList className="mt-4" metaList={_metaList} />}
</div>
{ _metaList.length > 0 && (
<SessionMetaList className="mt-4" metaList={_metaList} />
)}
</div>
)
);
}
export default withRouter<Props>(observer<Props>(SessionItem))
export default withRouter<Props>(observer<Props>(SessionItem));

View file

@ -0,0 +1,17 @@
import React from 'react';
import SessionList from './components/SessionList';
import SessionHeader from './components/SessionHeader';
interface Props {}
function SessionListContainer(props: Props) {
return (
<div className="widget-wrapper">
<SessionHeader />
<div className="p-4">
<SessionList />
</div>
</div>
);
}
export default SessionListContainer;

View file

@ -0,0 +1,20 @@
import React from 'react';
import { connect } from 'react-redux';
function NoContentMessage({ activeTab }: any) {
return <div>{getNoContentMessage(activeTab)}</div>;
}
export default connect((state: any) => ({
activeTab: state.getIn(['search', 'activeTab']),
}))(NoContentMessage);
function getNoContentMessage(activeTab: any) {
let str = 'No recordings found';
if (activeTab.type !== 'all') {
str += ' with ' + activeTab.name;
return str;
}
return str + '!';
}

View file

@ -0,0 +1,48 @@
import React from 'react';
import { numberWithCommas } from 'App/utils';
import { applyFilter } from 'Duck/search';
import Period from 'Types/app/period';
import SelectDateRange from 'Shared/SelectDateRange';
import SessionTags from '../SessionTags';
import { connect } from 'react-redux';
import SessionSort from '../SessionSort';
interface Props {
listCount: number;
filter: any;
applyFilter: (filter: any) => void;
}
function SessionHeader(props: Props) {
const { listCount, filter: { startDate, endDate, rangeValue } } = props;
const period = Period({ start: startDate, end: endDate, rangeName: rangeValue });
const onDateChange = (e: any) => {
const dateValues = e.toJSON();
props.applyFilter(dateValues);
};
return (
<div className="flex items-center p-4 justify-between">
<div className="flex items-center">
<div className="mr-3 text-lg">
<span className="font-bold">Sessions</span> <span className="color-gray-medium ml-2">{listCount}</span>
</div>
<SessionTags />
</div>
<div className="flex items-center">
<SelectDateRange period={period} onChange={onDateChange} right={true} />
<div className="mx-2" />
<SessionSort />
</div>
</div>
);
}
export default connect(
(state: any) => ({
filter: state.getIn(['search', 'instance']),
listCount: numberWithCommas(state.getIn(['sessions', 'total'])),
}),
{ applyFilter }
)(SessionHeader);

View file

@ -0,0 +1 @@
export { default } from './SessionHeader';

View file

@ -0,0 +1,103 @@
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { FilterKey } from 'Types/filter/filterType';
import SessionItem from 'Shared/SessionItem';
import { NoContent, Loader, Pagination } from 'UI';
import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG';
import NoContentMessage from '../NoContentMessage';
import { fetchSessions, addFilterByKeyAndValue, updateCurrentPage, setScrollPosition } from 'Duck/search';
interface Props {
loading: boolean;
list: any;
currentPage: number;
total: number;
filters: any;
lastPlayedSessionId: string;
metaList: any;
scrollY: number;
addFilterByKeyAndValue: (key: string, value: any, operator?: string) => void;
updateCurrentPage: (page: number) => void;
setScrollPosition: (scrollPosition: number) => void;
fetchSessions: () => void;
}
function SessionList(props: Props) {
const { loading, list, currentPage, total, filters, lastPlayedSessionId, metaList } = props;
const _filterKeys = filters.map((i: any) => i.key);
const hasUserFilter = _filterKeys.includes(FilterKey.USERID) || _filterKeys.includes(FilterKey.USERANONYMOUSID);
useEffect(() => {
const { scrollY } = props;
window.scrollTo(0, scrollY);
if (total === 0) {
props.fetchSessions()
}
return () => {
props.setScrollPosition(window.scrollY);
};
}, []);
const onUserClick = (userId: any) => {
if (userId) {
props.addFilterByKeyAndValue(FilterKey.USERID, userId);
} else {
props.addFilterByKeyAndValue(FilterKey.USERID, '', 'isUndefined');
}
};
return (
<Loader loading={loading}>
<NoContent
title={
<div className="flex items-center justify-center flex-col">
<AnimatedSVG name={ICONS.NO_RESULTS} size={170} />
<div className="mt-2" />
<NoContentMessage />
</div>
}
subtext={<div>Please try changing your search parameters.</div>}
show={!loading && list.size === 0}
>
{list.map((session: any) => (
<React.Fragment key={session.sessionId}>
<SessionItem
session={session}
hasUserFilter={hasUserFilter}
onUserClick={onUserClick}
metaList={metaList}
lastPlayedSessionId={lastPlayedSessionId}
/>
<div className="border-b" />
</React.Fragment>
))}
</NoContent>
{total > 0 && (
<div className="w-full flex items-center justify-center py-6">
<Pagination
page={currentPage}
totalPages={Math.ceil(total / 10)}
onPageChange={(page) => props.updateCurrentPage(page)}
limit={10}
debounceRequest={1000}
/>
</div>
)}
</Loader>
);
}
export default connect(
(state: any) => ({
list: state.getIn(['sessions', 'list']),
filters: state.getIn(['search', 'instance', 'filters']),
lastPlayedSessionId: state.getIn(['sessions', 'lastPlayedSessionId']),
metaList: state.getIn(['customFields', 'list']).map((i: any) => i.key),
loading: state.getIn(['sessions', 'loading']),
currentPage: state.getIn(['search', 'currentPage']) || 1,
total: state.getIn(['sessions', 'total']) || 0,
scrollY: state.getIn(['search', 'scrollY']),
}),
{ updateCurrentPage, addFilterByKeyAndValue, setScrollPosition, fetchSessions }
)(SessionList);

View file

@ -0,0 +1 @@
export { default } from './SessionList';

View file

@ -0,0 +1,42 @@
import React from 'react';
import { connect } from 'react-redux';
import Select from 'Shared/Select';
import { sort } from 'Duck/sessions';
import { applyFilter } from 'Duck/search';
const sortOptionsMap = {
'startTs-desc': 'Newest',
'startTs-asc': 'Oldest',
'eventsCount-asc': 'Events Ascending',
'eventsCount-desc': 'Events Descending',
};
const sortOptions = Object.entries(sortOptionsMap).map(([value, label]) => ({ value, label }));
interface Props {
filter: any;
options: any;
applyFilter: (filter: any) => void;
sort: (sort: string, sign: number) => void;
}
function SessionSort(props: Props) {
const { sort, order } = props.filter;
const onSort = ({ value }: any) => {
value = value.value;
const [sort, order] = value.split('-');
const sign = order === 'desc' ? -1 : 1;
props.applyFilter({ order, sort });
props.sort(sort, sign);
};
const defaultOption = `${sort}-${order}`;
return <Select name="sortSessions" plain right options={sortOptions} onChange={onSort} defaultValue={defaultOption} />;
}
export default connect(
(state: any) => ({
filter: state.getIn(['search', 'instance']),
}),
{ sort, applyFilter }
)(SessionSort);

View file

@ -0,0 +1 @@
export { default } from './SessionSort';

View file

@ -0,0 +1,23 @@
.dropdown {
display: flex !important;
padding: 4px 6px;
border-radius: 3px;
color: $gray-darkest;
font-weight: 500;
&:hover {
background-color: $gray-light;
}
}
.dropdownTrigger {
padding: 4px 8px;
border-radius: 3px;
&:hover {
background-color: $gray-light;
}
}
.dropdownIcon {
margin-top: 2px;
margin-left: 3px;
}

View file

@ -0,0 +1,66 @@
import React from 'react';
import { setActiveTab } from 'Duck/search';
import { connect } from 'react-redux';
import { issues_types } from 'Types/session/issue';
import { Icon } from 'UI';
import cn from 'classnames';
interface Props {
setActiveTab: typeof setActiveTab;
activeTab: any;
tags: any;
total: number;
}
function SessionTags(props: Props) {
const { activeTab, tags, total } = props;
const disable = activeTab.type === 'all' && total === 0;
return (
<div className="flex items-center">
{tags &&
tags.map((tag: any, index: any) => (
<div key={index}>
<TagItem
onClick={() => props.setActiveTab(tag)}
label={tag.name}
isActive={activeTab.type === tag.type}
icon={tag.icon}
disabled={disable && tag.type !== 'all'}
/>
</div>
))}
</div>
);
}
export default connect(
(state: any) => {
const isEnterprise = state.getIn(['user', 'account', 'edition']) === 'ee';
return {
activeTab: state.getIn(['search', 'activeTab']),
tags: issues_types.filter((tag: any) => (isEnterprise ? tag.type !== 'bookmark' : tag.type !== 'vault')),
total: state.getIn(['sessions', 'total']) || 0,
};
},
{
setActiveTab,
}
)(SessionTags);
function TagItem({ isActive, onClick, label, icon = '', disabled = false }: any) {
return (
<div>
<button
onClick={onClick}
className={cn('transition group rounded ml-2 px-2 py-1 flex items-center uppercase text-sm hover:bg-teal hover:text-white', {
'bg-teal text-white': isActive,
'bg-active-blue color-teal': !isActive,
'disabled': disabled,
})}
>
{icon && <Icon name={icon} color="teal" size="14" className={cn('group-hover:fill-white mr-2', { 'fill-white': isActive })} />}
<span className="leading-none font-bold">{label}</span>
</button>
</div>
);
}

View file

@ -0,0 +1 @@
export { default } from './SessionTags';

View file

@ -1,30 +0,0 @@
import React from 'react';
import { Icon } from 'UI';
import styles from './noContent.module.css';
export default ({
title = <div>No data available.</div>,
subtext,
icon,
iconSize = 100,
size,
show = true,
children = null,
empty = false,
image = null,
style = {},
}) => (!show ? children :
<div className={ `${ styles.wrapper } ${ size && styles[ size ] }` } style={style}>
{
icon && <Icon name={icon} size={iconSize} />
}
{ title && <div className={ styles.title }>{ title }</div> }
{
subtext &&
<div className={ styles.subtext }>{ subtext }</div>
}
{
image && <div className="mt-4 flex justify-center">{ image } </div>
}
</div>
);

View file

@ -0,0 +1,29 @@
import React from 'react';
import { Icon } from 'UI';
import styles from './noContent.module.css';
interface Props {
title?: any;
subtext?: any;
icon?: string;
iconSize?: number;
size?: number;
show?: boolean;
children?: any;
image?: any;
style?: any;
}
export default function NoContent(props: Props) {
const { title = '', subtext = '', icon, iconSize, size, show, children, image, style } = props;
return !show ? (
children
) : (
<div className={`${styles.wrapper} ${size && styles[size]}`} style={style}>
{icon && <Icon name={icon} size={iconSize} />}
{title && <div className={styles.title}>{title}</div>}
{subtext && <div className={styles.subtext}>{subtext}</div>}
{image && <div className="mt-4 flex justify-center">{image} </div>}
</div>
);
}

View file

@ -45,15 +45,3 @@
height: 166px;
margin-bottom: 20px;
}
.empty-state {
display: block;
margin: auto;
background-image: svg-load(empty-state.svg, fill=#CCC);
background-repeat: no-repeat;
background-size: contain;
background-position: center center;
width: 166px;
height: 166px;
margin-bottom: 20px;
}

View file

@ -13,7 +13,7 @@ export const durationFormatted = (duration: Duration):string => {
duration = duration.toFormat('h\'h\'m\'m');
} else if (duration.as('months') < 1) { // show in days and hours
duration = duration.toFormat('d\'d\'h\'h');
} else { //
} else {
duration = duration.toFormat('m\'m\'s\'s\'');
}
@ -133,4 +133,4 @@ export const countDaysFrom = (timestamp: number): number => {
const date = DateTime.fromMillis(timestamp);
const d = new Date();
return Math.round(Math.abs(d.getTime() - date.toJSDate().getTime()) / (1000 * 3600 * 24));
}
}

View file

@ -2,6 +2,7 @@ import origMoment from "moment";
import { extendMoment } from "moment-range";
export const moment = extendMoment(origMoment);
import { DateTime } from "luxon";
import { TIMEZONE } from 'App/constants/storageKeys';
export const CUSTOM_RANGE = "CUSTOM_RANGE";
@ -42,39 +43,42 @@ export function getDateRangeLabel(value) {
}
export function getDateRangeFromValue(value) {
const tz = JSON.parse(localStorage.getItem(TIMEZONE));
const offset = tz ? tz.label.slice(-6) : 0;
switch (value) {
case DATE_RANGE_VALUES.LAST_30_MINUTES:
return moment.range(
moment().startOf("hour").subtract(30, "minutes"),
moment().startOf("hour")
moment().utcOffset(offset, true).startOf("hour").subtract(30, "minutes"),
moment().utcOffset(offset, true).startOf("hour")
);
case DATE_RANGE_VALUES.YESTERDAY:
return moment.range(
moment().utcOffset(offset, true).subtract(1, "days").startOf("day"),
moment().utcOffset(offset, true).subtract(1, "days").endOf("day")
);
case DATE_RANGE_VALUES.TODAY:
return moment.range(moment().startOf("day"), moment().endOf("day"));
case DATE_RANGE_VALUES.YESTERDAY:
return moment.range(
moment().subtract(1, "days").startOf("day"),
moment().subtract(1, "days").endOf("day")
);
return moment.range(moment().utcOffset(offset, true).startOf("day"), moment().utcOffset(offset, true).endOf("day"));
case DATE_RANGE_VALUES.LAST_24_HOURS:
return moment.range(moment().subtract(24, "hours"), moment());
return moment.range(moment().utcOffset(offset, true).subtract(24, "hours"), moment().utcOffset(offset, true));
case DATE_RANGE_VALUES.LAST_7_DAYS:
return moment.range(
moment().subtract(7, "days").startOf("day"),
moment().endOf("day")
moment().utcOffset(offset, true).subtract(7, "days").startOf("day"),
moment().utcOffset(offset, true).endOf("day")
);
case DATE_RANGE_VALUES.LAST_30_DAYS:
return moment.range(
moment().subtract(30, "days").startOf("day"),
moment().endOf("day")
moment().utcOffset(offset, true).subtract(30, "days").startOf("day"),
moment().utcOffset(offset, true).endOf("day")
);
case DATE_RANGE_VALUES.THIS_MONTH:
return moment().range("month");
return moment().utcOffset(offset, true).range("month");
case DATE_RANGE_VALUES.LAST_MONTH:
return moment().subtract(1, "months").range("month");
return moment().utcOffset(offset, true).subtract(1, "months").range("month");
case DATE_RANGE_VALUES.THIS_YEAR:
return moment().range("year");
return moment().utcOffset(offset, true).range("year");
case DATE_RANGE_VALUES.CUSTOM_RANGE:
return moment.range(moment(), moment());
return moment.range(moment().utcOffset(offset, true), moment().utcOffset(offset, true));
}
return null;
}

View file

@ -137,13 +137,13 @@ export const reduceThenFetchResource =
const filter = getState().getIn(['search', 'instance']).toData();
const activeTab = getState().getIn(['search', 'activeTab']);
if (activeTab.type !== 'all' && activeTab.type !== 'bookmark') {
if (activeTab.type !== 'all' && activeTab.type !== 'bookmark' && activeTab.type !== 'vault') {
const tmpFilter = filtersMap[FilterKey.ISSUE];
tmpFilter.value = [activeTab.type];
filter.filters = filter.filters.concat(tmpFilter);
}
if (activeTab.type === 'bookmark') {
if (activeTab.type === 'bookmark' || activeTab.type === 'vault') {
filter.bookmarked = true;
}

View file

@ -9,9 +9,11 @@ import type {
RawCssInsertRule,
} from './raw'
import RawMessageReader from './RawMessageReader'
import type { RawMessageReaderI } from './RawMessageReader'
import { resolveURL, resolveCSS } from './urlResolve'
interface RawMessageReaderI {
readMessage(): RawMessage | null
}
const resolveMsg = {
"set_node_attribute_url_based": (msg: RawSetNodeAttributeURLBased): RawSetNodeAttribute =>

View file

@ -3,9 +3,6 @@
import PrimitiveReader from './PrimitiveReader'
import type { RawMessage } from './raw'
export interface RawMessageReaderI {
readMessage(): RawMessage | null
}
export default class RawMessageReader extends PrimitiveReader {
readMessage(): RawMessage | null {

View file

@ -2,7 +2,8 @@
import type { Timed } from './timed'
import type { RawMessage } from './raw'
import type { RawBatchMeta,
import type {
RawBatchMeta,
RawTimestamp,
RawSessionDisconnect,
RawSetPageLocation,
@ -60,7 +61,8 @@ import type { RawBatchMeta,
RawIosClickEvent,
RawIosPerformanceEvent,
RawIosLog,
RawIosNetworkCall, } from './raw'
RawIosNetworkCall,
} from './raw'
export type Message = RawMessage & Timed

View file

@ -1,7 +1,7 @@
// Auto-generated, do not edit
export const TP_MAP = {
80: "batch_meta",
80: "batch_meta",
0: "timestamp",
2: "session_disconnect",
4: "set_page_location",

View file

@ -86,7 +86,7 @@ export const sessions = params => queried('/sessions', params);
export const assist = params => queried('/assist', params);
export const session = (sessionId = ':sessionId', hash) => hashed(`/session/${ sessionId }`, hash);
export const liveSession = (sessionId = ':sessionId', hash) => hashed(`/assist/${ sessionId }`, hash);
export const liveSession = (sessionId = ':sessionId', params, hash) => hashed(queried(`/assist/${ sessionId }`, params), hash);
// export const liveSession = (sessionId = ':sessionId', hash) => hashed(`/live/session/${ sessionId }`, hash);
export const errors = params => queried('/errors', params);

View file

@ -1,4 +1,4 @@
import { createStore, applyMiddleware } from 'redux';
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import { Map } from 'immutable';
import indexReducer from './duck';
@ -9,13 +9,16 @@ const storage = new LocalStorage({
jwt: String,
});
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ && window.env.NODE_ENV === "development"
? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ : compose;
const storageState = storage.state();
const initialState = Map({
jwt: storageState.jwt,
// TODO: store user
});
const store = createStore(indexReducer, initialState, applyMiddleware(thunk, apiMiddleware));
const store = createStore(indexReducer, initialState, composeEnhancers(applyMiddleware(thunk, apiMiddleware)));
store.subscribe(() => {
const state = store.getState();
storage.sync({

View file

@ -11,4 +11,8 @@
input.no-focus:focus {
outline: none !important;
border: solid thin transparent !important;
}
.widget-wrapper {
@apply rounded border bg-white;
}

View file

@ -26,43 +26,43 @@ const RANGE_LABELS = {
[THIS_YEAR]: "This Year",
};
function getRange(rangeName) {
function getRange(rangeName, offset) {
switch (rangeName) {
case TODAY:
return moment.range(moment().startOf("day"), moment().endOf("day"));
case YESTERDAY:
return moment.range(
moment().subtract(1, "days").startOf("day"),
moment().subtract(1, "days").endOf("day")
moment().utcOffset(offset).subtract(1, "days").startOf("day"),
moment().utcOffset(offset).subtract(1, "days").endOf("day")
);
case LAST_24_HOURS:
return moment.range(
// moment().startOf("hour").subtract(24, "hours"),
// moment().startOf("hour")
moment().subtract(24, 'hours'),
moment(),
moment().utcOffset(offset).subtract(24, 'hours'),
moment().utcOffset(offset),
);
case LAST_30_MINUTES:
return moment.range(
moment().startOf("hour").subtract(30, "minutes"),
moment().startOf("hour")
moment().utcOffset(offset).startOf("hour").subtract(30, "minutes"),
moment().utcOffset(offset).startOf("hour")
);
case LAST_7_DAYS:
return moment.range(
moment().subtract(7, "days").startOf("day"),
moment().endOf("day")
moment().utcOffset(offset).subtract(7, "days").startOf("day"),
moment().utcOffset(offset).endOf("day")
);
case LAST_30_DAYS:
return moment.range(
moment().subtract(30, "days").startOf("day"),
moment().endOf("day")
moment().utcOffset(offset).subtract(30, "days").startOf("day"),
moment().utcOffset(offset).endOf("day")
);
case THIS_MONTH:
return moment().range("month");
return moment().utcOffset(offset).range("month");
case LAST_MONTH:
return moment().subtract(1, "months").range("month");
return moment().utcOffset(offset).subtract(1, "months").range("month");
case THIS_YEAR:
return moment().range("year");
return moment().utcOffset(offset).range("year");
default:
return moment.range();
}
@ -77,10 +77,11 @@ export default Record(
},
{
fromJS: (period) => {
const offset = period.timezoneOffset || 0
if (!period.rangeName || period.rangeName === CUSTOM_RANGE) {
const range = moment.range(
moment(period.start || 0),
moment(period.end || 0)
moment(period.start || 0).utcOffset(offset),
moment(period.end || 0).utcOffset(offset)
);
return {
...period,
@ -89,7 +90,7 @@ export default Record(
end: range.end.unix() * 1000,
};
}
const range = getRange(period.rangeName);
const range = getRange(period.rangeName, offset);
return {
...period,
range,
@ -97,14 +98,6 @@ export default Record(
end: range.end.unix() * 1000,
};
},
// fromFilter: filter => {
// const range = getRange(filter.rangeName);
// return {
// start: range.start.unix() * 1000,
// end: range.end.unix() * 1000,
// rangeName: filter.rangeName,
// }
// },
methods: {
toJSON() {
return {

View file

@ -3,15 +3,18 @@ import { List } from 'immutable';
import Watchdog from 'Types/watchdog'
export const issues_types = List([
{ 'type': 'js_exception', 'visible': true, 'order': 0, 'name': 'Errors', 'icon': 'funnel/exclamation-circle' },
{ 'type': 'bad_request', 'visible': true, 'order': 1, 'name': 'Bad Requests', 'icon': 'funnel/file-medical-alt' },
{ 'type': 'missing_resource', 'visible': true, 'order': 2, 'name': 'Missing Images', 'icon': 'funnel/image' },
{ 'type': 'click_rage', 'visible': true, 'order': 3, 'name': 'Click Rage', 'icon': 'funnel/emoji-angry' },
{ 'type': 'dead_click', 'visible': true, 'order': 4, 'name': 'Dead Clicks', 'icon': 'funnel/dizzy' },
{ 'type': 'memory', 'visible': true, 'order': 5, 'name': 'High Memory', 'icon': 'funnel/sd-card' },
{ 'type': 'cpu', 'visible': true, 'order': 6, 'name': 'High CPU', 'icon': 'funnel/cpu' },
{ 'type': 'crash', 'visible': true, 'order': 7, 'name': 'Crashes', 'icon': 'funnel/file-earmark-break' },
{ 'type': 'custom', 'visible': false, 'order': 8, 'name': 'Custom', 'icon': 'funnel/exclamation-circle' }
{ 'type': 'all', 'visible': true, 'order': 0, 'name': 'All', 'icon': '' },
{ 'type': 'js_exception', 'visible': true, 'order': 1, 'name': 'Errors', 'icon': 'funnel/exclamation-circle' },
{ 'type': 'click_rage', 'visible': true, 'order': 2, 'name': 'Click Rage', 'icon': 'funnel/emoji-angry' },
{ 'type': 'crash', 'visible': true, 'order': 3, 'name': 'Crashes', 'icon': 'funnel/file-earmark-break' },
{ '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' },
// { 'type': 'bad_request', 'visible': true, 'order': 1, 'name': 'Bad Requests', 'icon': 'funnel/file-medical-alt' },
// { 'type': 'missing_resource', 'visible': true, 'order': 2, 'name': 'Missing Images', 'icon': 'funnel/image' },
// { 'type': 'dead_click', 'visible': true, 'order': 4, 'name': 'Dead Clicks', 'icon': 'funnel/dizzy' },
// { 'type': 'cpu', 'visible': true, 'order': 6, 'name': 'High CPU', 'icon': 'funnel/cpu' },
// { 'type': 'custom', 'visible': false, 'order': 8, 'name': 'Custom', 'icon': 'funnel/exclamation-circle' }
]).map(Watchdog)
export const issues_types_map = {}

View file

@ -1,29 +0,0 @@
require('dotenv').config()
// TODO: (the problem is during the build time the frontend is isolated)
//const trackerInfo = require('../tracker/tracker/package.json');
const oss = {
name: 'oss',
PRODUCTION: true,
SENTRY_ENABLED: false,
SENTRY_URL: "",
CAPTCHA_ENABLED: process.env.CAPTCHA_ENABLED === 'true',
CAPTCHA_SITE_KEY: process.env.CAPTCHA_SITE_KEY,
ORIGIN: () => 'window.location.origin',
API_EDP: () => 'window.location.origin + "/api"',
ASSETS_HOST: () => 'window.location.origin + "/assets"',
VERSION: '1.7.0',
SOURCEMAP: true,
MINIO_ENDPOINT: process.env.MINIO_ENDPOINT,
MINIO_PORT: process.env.MINIO_PORT,
MINIO_USE_SSL: process.env.MINIO_USE_SSL,
MINIO_ACCESS_KEY: process.env.MINIO_ACCESS_KEY,
MINIO_SECRET_KEY: process.env.MINIO_SECRET_KEY,
ICE_SERVERS: process.env.ICE_SERVERS,
TRACKER_VERSION: '3.5.15' // trackerInfo.version,
}
module.exports = {
oss,
};

16
mobs/README.md Normal file
View file

@ -0,0 +1,16 @@
# Message Object Binary Schema and Code Generator from Templates
To generate all necessary files for the project:
```sh
ruby run.rb
```
In order generated .go file to fit the go formatting style:
```sh
gofmt -w ../backend/pkg/messages/messages.go
```
(Otherwise there will be changes in stage)

172
mobs/ios_messages.rb Normal file
View file

@ -0,0 +1,172 @@
message 107, 'IOSBatchMeta', :replayer => false do
uint 'Timestamp'
uint 'Length'
uint 'FirstIndex'
end
message 90, 'IOSSessionStart', :replayer => true do
uint 'Timestamp'
# uint 'Length'
uint 'ProjectID'
string 'TrackerVersion'
string 'RevID'
string 'UserUUID'
# string 'UserAgent'
string 'UserOS'
string 'UserOSVersion'
# string 'UserBrowser'
# string 'UserBrowserVersion'
string 'UserDevice'
string 'UserDeviceType'
# uint 'UserDeviceMemorySize'
# uint 'UserDeviceHeapSize'
string 'UserCountry'
end
message 91, 'IOSSessionEnd' do
uint 'Timestamp'
end
message 92, 'IOSMetadata' do
uint 'Timestamp'
uint 'Length'
string 'Key'
string 'Value'
end
message 93, 'IOSCustomEvent', :seq_index => true, :replayer => true do
uint 'Timestamp'
uint 'Length'
string 'Name'
string 'Payload'
end
message 94, 'IOSUserID' do
uint 'Timestamp'
uint 'Length'
string 'Value'
end
message 95, 'IOSUserAnonymousID' do
uint 'Timestamp'
uint 'Length'
string 'Value'
end
message 96, 'IOSScreenChanges', :replayer => true do
uint 'Timestamp'
uint 'Length'
uint 'X'
uint 'Y'
uint 'Width'
uint 'Height'
end
message 97, 'IOSCrash', :seq_index => true do
uint 'Timestamp'
uint 'Length'
string 'Name'
string 'Reason'
string 'Stacktrace'
end
message 98, 'IOSScreenEnter', :seq_index => true do
uint 'Timestamp'
uint 'Length'
string 'Title'
string 'ViewName'
end
message 99, 'IOSScreenLeave' do
uint 'Timestamp'
uint 'Length'
string 'Title'
string 'ViewName'
end
message 100, 'IOSClickEvent', :seq_index => true, :replayer => true do
uint 'Timestamp'
uint 'Length'
string 'Label'
uint 'X'
uint 'Y'
end
message 101, 'IOSInputEvent', :seq_index => true do
uint 'Timestamp'
uint 'Length'
string 'Value'
boolean 'ValueMasked'
string 'Label'
end
=begin
Name/Value may be :
"physicalMemory": Total memory in bytes
"processorCount": Total processors in device
?"activeProcessorCount": Number of currently used processors
"systemUptime": Elapsed time (in seconds) since last boot
?"isLowPowerModeEnabled": Possible values (1 or 0)
2/3!"thermalState": Possible values (0:nominal 1:fair 2:serious 3:critical)
!"batteryLevel": Possible values (0 .. 100)
"batteryState": Possible values (0:unknown 1:unplugged 2:charging 3:full)
"orientation": Possible values (0unknown 1:portrait 2:portraitUpsideDown 3:landscapeLeft 4:landscapeRight 5:faceUp 6:faceDown)
"mainThreadCPU": Possible values (0 .. 100)
"memoryUsage": Used memory in bytes
=end
message 102, 'IOSPerformanceEvent', :replayer => true, :seq_index => true do
uint 'Timestamp'
uint 'Length'
string 'Name'
uint 'Value'
end
message 103, 'IOSLog', :replayer => true do
uint 'Timestamp'
uint 'Length'
string 'Severity' # Possible values ("info", "error")
string 'Content'
end
message 104, 'IOSInternalError' do
uint 'Timestamp'
uint 'Length'
string 'Content'
end
message 105, 'IOSNetworkCall', :replayer => true, :seq_index => true do
uint 'Timestamp'
uint 'Length'
uint 'Duration'
string 'Headers'
string 'Body'
string 'URL'
boolean 'Success'
string 'Method'
uint 'Status'
end
message 110, 'IOSPerformanceAggregated', :swift => false do
uint 'TimestampStart'
uint 'TimestampEnd'
uint 'MinFPS'
uint 'AvgFPS'
uint 'MaxFPS'
uint 'MinCPU'
uint 'AvgCPU'
uint 'MaxCPU'
uint 'MinMemory'
uint 'AvgMemory'
uint 'MaxMemory'
uint 'MinBattery'
uint 'AvgBattery'
uint 'MaxBattery'
end
message 111, 'IOSIssueEvent', :seq_index => true do
uint 'Timestamp'
string 'Type'
string 'ContextString'
string 'Context'
string 'Payload'
end

409
mobs/messages.rb Normal file
View file

@ -0,0 +1,409 @@
# Special one for Batch Meta. Message id could define the version
message 80, 'BatchMeta', :replayer => false do
uint 'PageNo'
uint 'FirstIndex'
int 'Timestamp'
end
message 0, 'Timestamp' do
uint 'Timestamp'
end
message 1, 'SessionStart', :js => false, :replayer => false do
uint 'Timestamp'
uint 'ProjectID'
string 'TrackerVersion'
string 'RevID'
string 'UserUUID'
string 'UserAgent'
string 'UserOS'
string 'UserOSVersion'
string 'UserBrowser'
string 'UserBrowserVersion'
string 'UserDevice'
string 'UserDeviceType'
uint 'UserDeviceMemorySize'
uint 'UserDeviceHeapSize'
string 'UserCountry'
string 'UserID'
end
# Depricated (not used) since OpenReplay tracker 3.0.0
message 2, 'SessionDisconnect', :js => false do
uint 'Timestamp'
end
message 3, 'SessionEnd', :js => false, :replayer => false do
uint 'Timestamp'
end
message 4, 'SetPageLocation' do
string 'URL'
string 'Referrer'
uint 'NavigationStart'
end
message 5, 'SetViewportSize' do
uint 'Width'
uint 'Height'
end
message 6, 'SetViewportScroll' do
int 'X'
int 'Y'
end
message 7, 'CreateDocument' do
end
message 8, 'CreateElementNode' do
uint 'ID'
uint 'ParentID'
uint 'index'
string 'Tag'
boolean 'SVG'
end
message 9, 'CreateTextNode' do
uint 'ID'
uint 'ParentID'
uint 'Index'
end
message 10, 'MoveNode' do
uint 'ID'
uint 'ParentID'
uint 'Index'
end
message 11, 'RemoveNode' do
uint 'ID'
end
message 12, 'SetNodeAttribute' do
uint 'ID'
string 'Name'
string 'Value'
end
message 13, 'RemoveNodeAttribute' do
uint 'ID'
string 'Name'
end
message 14, 'SetNodeData' do
uint 'ID'
string 'Data'
end
# Depricated starting from 5.5.11 in favor of SetStyleData
message 15, 'SetCSSData', :js => false do
uint 'ID'
string 'Data'
end
message 16, 'SetNodeScroll' do
uint 'ID'
int 'X'
int 'Y'
end
message 17, 'SetInputTarget', :replayer => false do
uint 'ID'
string 'Label'
end
message 18, 'SetInputValue' do
uint 'ID'
string 'Value'
int 'Mask'
end
message 19, 'SetInputChecked' do
uint 'ID'
boolean 'Checked'
end
message 20, 'MouseMove' do
uint 'X'
uint 'Y'
end
# Depricated since OpenReplay 1.2.0
message 21, 'MouseClickDepricated', :js => false, :replayer => false do
uint 'ID'
uint 'HesitationTime'
string 'Label'
end
message 22, 'ConsoleLog' do
string 'Level'
string 'Value'
end
message 23, 'PageLoadTiming', :replayer => false do
uint 'RequestStart'
uint 'ResponseStart'
uint 'ResponseEnd'
uint 'DomContentLoadedEventStart'
uint 'DomContentLoadedEventEnd'
uint 'LoadEventStart'
uint 'LoadEventEnd'
uint 'FirstPaint'
uint 'FirstContentfulPaint'
end
message 24, 'PageRenderTiming', :replayer => false do
uint 'SpeedIndex'
uint 'VisuallyComplete'
uint 'TimeToInteractive'
end
message 25, 'JSException', :replayer => false do
string 'Name'
string 'Message'
string 'Payload'
end
message 26, 'IntegrationEvent', :js => false, :replayer => false do
uint 'Timestamp'
string 'Source'
string 'Name'
string 'Message'
string 'Payload'
end
message 27, 'RawCustomEvent', :replayer => false do
string 'Name'
string 'Payload'
end
message 28, 'UserID', :replayer => false do
string 'ID'
end
message 29, 'UserAnonymousID', :replayer => false do
string 'ID'
end
message 30, 'Metadata', :replayer => false do
string 'Key'
string 'Value'
end
message 31, 'PageEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
string 'URL'
string 'Referrer'
boolean 'Loaded'
uint 'RequestStart'
uint 'ResponseStart'
uint 'ResponseEnd'
uint 'DomContentLoadedEventStart'
uint 'DomContentLoadedEventEnd'
uint 'LoadEventStart'
uint 'LoadEventEnd'
uint 'FirstPaint'
uint 'FirstContentfulPaint'
uint 'SpeedIndex'
uint 'VisuallyComplete'
uint 'TimeToInteractive'
end
message 32, 'InputEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
string 'Value'
boolean 'ValueMasked'
string 'Label'
end
message 33, 'ClickEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
uint 'HesitationTime'
string 'Label'
string 'Selector'
end
message 34, 'ErrorEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
string 'Source'
string 'Name'
string 'Message'
string 'Payload'
end
message 35, 'ResourceEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
uint 'Duration'
uint 'TTFB'
uint 'HeaderSize'
uint 'EncodedBodySize'
uint 'DecodedBodySize'
string 'URL'
string 'Type'
boolean 'Success'
string 'Method'
uint 'Status'
end
message 36, 'CustomEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
string 'Name'
string 'Payload'
end
message 37, 'CSSInsertRule' do
uint 'ID'
string 'Rule'
uint 'Index'
end
message 38, 'CSSDeleteRule' do
uint 'ID'
uint 'Index'
end
message 39, 'Fetch' do
string 'Method'
string 'URL'
string 'Request'
string 'Response'
uint 'Status'
uint 'Timestamp'
uint 'Duration'
end
message 40, 'Profiler' do
string 'Name'
uint 'Duration'
string 'Args'
string 'Result'
end
message 41, 'OTable' do
string 'Key'
string 'Value'
end
message 42, 'StateAction', :replayer => false do
string 'Type'
end
message 43, 'StateActionEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
string 'Type'
end
message 44, 'Redux' do
string 'Action'
string 'State'
uint 'Duration'
end
message 45, 'Vuex' do
string 'Mutation'
string 'State'
end
message 46, 'MobX' do
string 'Type'
string 'Payload'
end
message 47, 'NgRx' do
string 'Action'
string 'State'
uint 'Duration'
end
message 48, 'GraphQL' do
string 'OperationKind'
string 'OperationName'
string 'Variables'
string 'Response'
end
message 49, 'PerformanceTrack' do
int 'Frames'
int 'Ticks'
uint 'TotalJSHeapSize'
uint 'UsedJSHeapSize'
end
message 50, 'GraphQLEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
string 'OperationKind'
string 'OperationName'
string 'Variables'
string 'Response'
end
message 51, 'FetchEvent', :js => false, :replayer => false do
uint 'MessageID'
uint 'Timestamp'
string 'Method'
string 'URL'
string 'Request'
string 'Response'
uint 'Status'
uint 'Duration'
end
message 52, 'DOMDrop', :js => false, :replayer => false do
uint 'Timestamp'
end
message 53, 'ResourceTiming', :replayer => false do
uint 'Timestamp'
uint 'Duration'
uint 'TTFB'
uint 'HeaderSize'
uint 'EncodedBodySize'
uint 'DecodedBodySize'
string 'URL'
string 'Initiator'
end
message 54, 'ConnectionInformation' do
uint 'Downlink'
string 'Type'
end
message 55, 'SetPageVisibility' do
boolean 'hidden'
end
message 56, 'PerformanceTrackAggr', :js => false, :replayer => false do
uint 'TimestampStart'
uint 'TimestampEnd'
uint 'MinFPS'
uint 'AvgFPS'
uint 'MaxFPS'
uint 'MinCPU'
uint 'AvgCPU'
uint 'MaxCPU'
uint 'MinTotalJSHeapSize'
uint 'AvgTotalJSHeapSize'
uint 'MaxTotalJSHeapSize'
uint 'MinUsedJSHeapSize'
uint 'AvgUsedJSHeapSize'
uint 'MaxUsedJSHeapSize'
end
message 59, 'LongTask' do
uint 'Timestamp'
uint 'Duration'
uint 'Context'
uint 'ContainerType'
string 'ContainerSrc'
string 'ContainerId'
string 'ContainerName'
end
message 60, 'SetNodeAttributeURLBased', :replayer => false do
uint 'ID'
string 'Name'
string 'Value'
string 'BaseURL'
end
# Might replace SetCSSData (although BaseURL is useless after rewriting)
message 61, 'SetCSSDataURLBased', :replayer => false do
uint 'ID'
string 'Data'
string 'BaseURL'
end
message 62, 'IssueEvent', :replayer => false, :js => false do
uint 'MessageID'
uint 'Timestamp'
string 'Type'
string 'ContextString'
string 'Context'
string 'Payload'
end
message 63, 'TechnicalInfo', :replayer => false do
string 'Type'
string 'Value'
end
message 64, 'CustomIssue', :replayer => false do
string 'Name'
string 'Payload'
end
# Since 5.6.6; only for websocket (might be probably replaced with ws.close())
# Depricated
message 65, 'PageClose', :replayer => false do
end
message 66, 'AssetCache', :replayer => false, :js => false do
string 'URL'
end
message 67, 'CSSInsertRuleURLBased', :replayer => false do
uint 'ID'
string 'Rule'
uint 'Index'
string 'BaseURL'
end
message 69, 'MouseClick' do
uint 'ID'
uint 'HesitationTime'
string 'Label'
string 'Selector'
end
# Since 3.4.0
message 70, 'CreateIFrameDocument' do
uint 'FrameID'
uint 'ID'
end

View file

@ -0,0 +1,124 @@
package messages
import (
"errors"
"io"
)
func ReadByte(reader io.Reader) (byte, error) {
p := make([]byte, 1)
_, err := io.ReadFull(reader, p)
if err != nil {
return 0, err
}
return p[0], nil
}
func SkipBytes(reader io.ReadSeeker) error {
n, err := ReadUint(reader)
if err != nil {
return err
}
_, err := reader.Seek(n, io.SeekCurrent);
return err
}
func ReadData(reader io.Reader) ([]byte, error) {
n, err := ReadUint(reader)
if err != nil {
return nil, err
}
p := make([]byte, n)
_, err := io.ReadFull(reader, p)
if err != nil {
return nil, err
}
return p, nil
}
func ReadUint(reader io.Reader) (uint64, error) {
var x uint64
var s uint
i := 0
for {
b, err := ReadByte(reader)
if err != nil {
return x, err
}
if b < 0x80 {
if i > 9 || i == 9 && b > 1 {
return x, errors.New("overflow")
}
return x | uint64(b)<<s, nil
}
x |= uint64(b&0x7f) << s
s += 7
i++
}
}
func ReadInt(reader io.Reader) (int64, error) {
ux, err := ReadUint(reader)
x := int64(ux >> 1)
if err != nil {
return x, err
}
if ux&1 != 0 {
x = ^x
}
return x, err
}
func ReadBoolean(reader io.Reader) (bool, error) {
p := make([]byte, 1)
_, err := io.ReadFull(reader, p)
if err != nil {
return false, err
}
return p[0] == 1, nil
}
func ReadString(reader io.Reader) (string, error) {
l, err := ReadUint(reader)
if err != nil {
return "", err
}
buf := make([]byte, l)
_, err = io.ReadFull(reader, buf)
if err != nil {
return "", err
}
return string(buf), nil
}
func WriteUint(v uint64, buf []byte, p int) int {
for v >= 0x80 {
buf[p] = byte(v) | 0x80
v >>= 7
p++
}
buf[p] = byte(v)
return p + 1
}
func WriteInt(v int64, buf []byte, p int) int {
uv := uint64(v) << 1
if v < 0 {
uv = ^uv
}
return WriteUint(uv, buf, p)
}
func WriteBoolean(v bool, buf []byte, p int) int {
if v {
buf[p] = 1
} else {
buf[p] = 0
}
return p + 1
}
func WriteString(str string, buf []byte, p int) int {
p = WriteUint(uint64(len(str)), buf, p)
return p + copy(buf[p:], str)
}

View file

@ -0,0 +1,62 @@
import io
class Codec:
"""
Implements encode/decode primitives
"""
@staticmethod
def read_boolean(reader: io.BytesIO):
b = reader.read(1)
return b == 1
@staticmethod
def read_uint(reader: io.BytesIO):
"""
The ending "big" doesn't play any role here,
since we're dealing with data per one byte
"""
x = 0 # the result
s = 0 # the shift (our result is big-ending)
i = 0 # n of byte (max 9 for uint64)
while True:
b = reader.read(1)
num = int.from_bytes(b, "big", signed=False)
# print(i, x)
if num < 0x80:
if i > 9 | i == 9 & num > 1:
raise OverflowError()
return int(x | num << s)
x |= (num & 0x7f) << s
s += 7
i += 1
@staticmethod
def read_int(reader: io.BytesIO) -> int:
"""
ux, err := ReadUint(reader)
x := int64(ux >> 1)
if err != nil {
return x, err
}
if ux&1 != 0 {
x = ^x
}
return x, err
"""
ux = Codec.read_uint(reader)
x = int(ux >> 1)
if ux & 1 != 0:
x = - x - 1
return x
@staticmethod
def read_string(reader: io.BytesIO) -> str:
length = Codec.read_uint(reader)
s = reader.read(length)
try:
return s.decode("utf-8", errors="replace").replace("\x00", "\uFFFD")
except UnicodeDecodeError:
return None

View file

@ -0,0 +1,60 @@
extension Data {
func readByte(offset: inout Int) -> UInt8 {
if offset >= self.count {
fatalError(">>> Error reading Byte")
}
let b = self[offset]
offset += 1
return b
}
func readUint(offset: inout Int) -> UInt64 {
var x: UInt64 = 0
var s: Int = 0
var i: Int = 0
while true {
let b = readByte(offset: &offset)
if b < 0x80 {
if i > 9 || i == 9 && b > 1 {
fatalError(">>> Error reading UInt")
}
return x | UInt64(b)<<s
}
x |= UInt64(b&0x7f) << s
s += 7
i += 1
}
}
func readInt(offset: inout Int) -> Int64 {
let ux = readUint(offset: &offset)
var x = Int64(ux >> 1)
if ux&1 != 0 {
x = ~x
}
return x
}
func readBoolean(offset: inout Int) -> Bool {
return readByte(offset: &offset) == 1
}
mutating func writeUint(_ input: UInt64) {
var v = input
while v >= 0x80 {
append(UInt8(v.littleEndian & 0x7F) | 0x80) // v.littleEndian ?
v >>= 7
}
append(UInt8(v))
}
mutating func writeInt(_ v: Int64) {
var uv = UInt64(v) << 1
if v < 0 {
uv = ~uv
}
writeUint(uv)
}
mutating func writeBoolean(_ v: Bool) {
if v {
append(1)
} else {
append(0)
}
}
}

136
mobs/run.rb Normal file
View file

@ -0,0 +1,136 @@
require 'erb'
# TODO: change method names to correct (CapitalCase and camelCase, not CamalCase and firstLower)
class String
def camel_case
return self if self !~ /_/ && self =~ /[A-Z]+.*/
split('_').map{|e| e.capitalize}.join.upperize
end
def camel_case_lower
self.split('_').inject([]){ |buffer,e| buffer.push(buffer.empty? ? e : e.capitalize) }.join.upperize
end
def upperize
self.sub('Id', 'ID').sub('Url', 'URL')
end
def first_lower
self.sub(/^[A-Z]+/) {|f| f.downcase }
end
def underscore
self.gsub(/::/, '/').
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
gsub(/([a-z\d])([A-Z])/,'\1_\2').
tr("-", "_").
downcase
end
end
class Attribute
attr_reader :name, :type
def initialize(name:, type:)
@name = name
@type = type
end
def type_js
case @type
when :int
"number"
when :uint
"number"
when :json
# TODO
# raise "Unexpected attribute type: data type attribute #{@name} found in JS template"
"string"
when :data
raise "Unexpected attribute type: data type attribute #{@name} found in JS template"
else
@type
end
end
def type_go
case @type
when :int
'int64'
when :uint
'uint64'
when :string
'string'
when :data
'[]byte'
when :boolean
'bool'
when :json
'interface{}'
end
end
def lengh_encoded
case @type
when :string, :data
true
else
false
end
end
end
$context = :web
class Message
attr_reader :id, :name, :js, :replayer, :swift, :seq_index, :attributes, :context
def initialize(name:, id:, js: $context == :web, replayer: $context == :web, swift: $context == :ios, seq_index: false, &block)
@id = id
@name = name
@js = js
@replayer = replayer
@swift = swift
@seq_index = seq_index
@context = $context
@attributes = []
instance_eval &block
end
%i(int uint boolean string data).each do |type|
define_method type do |name, opts = {}|
opts.merge!(
name: name,
type: type,
)
@attributes << Attribute.new(opts)
end
end
end
$ids = []
$messages = []
def message(id, name, opts = {}, &block)
raise "id duplicated #{name}" if $ids.include? id
raise "id is too big #{name}" if id > 120
$ids << id
opts[:id] = id
opts[:name] = name
msg = Message.new(opts, &block)
$messages << msg
end
require './messages.rb'
$context = :ios
require './ios_messages.rb'
Dir["templates/*.erb"].each do |tpl|
e = ERB.new(File.read(tpl))
path = tpl.split '/'
t = '../' + path[1].gsub('~', '/')
t = t[0..-5]
File.write(t, e.result)
puts tpl + ' --> ' + t
end

View file

@ -0,0 +1,10 @@
// Auto-generated, do not edit
package messages
func IsReplayerType(id int) bool {
return <%= $messages.select { |msg| msg.replayer }.map{ |msg| "#{msg.id} == id" }.join(' || ') %>
}
func IsIOSType(id int) bool {
return <%= $messages.select { |msg| msg.context == :ios }.map{ |msg| "#{msg.id} == id"}.join(' || ') %>
}

View file

@ -0,0 +1,12 @@
// Auto-generated, do not edit
package messages
func GetTimestamp(message Message) uint64 {
switch msg := message.(type) {
<% $messages.select { |msg| msg.swift }.each do |msg| %>
case *<%= msg.name %>:
return msg.Timestamp
<% end %>
}
return uint64(message.Meta().Timestamp)
}

View file

@ -0,0 +1,22 @@
// Auto-generated, do not edit
package messages
<% $messages.each do |msg| %>
type <%= msg.name %> struct {
message
<%= msg.attributes.map { |attr|
" #{attr.name} #{attr.type_go}" }.join "\n" %>
}
func (msg *<%= msg.name %>) Encode() []byte {
buf := make([]byte, <%= msg.attributes.count * 10 + 1 %><%= msg.attributes.map { |attr| "+len(msg.#{attr.name})" if attr.lengh_encoded }.compact.join %>)
buf[0] = <%= msg.id %>
p := 1
<%= msg.attributes.map { |attr|
" p = Write#{attr.type.to_s.camel_case}(msg.#{attr.name}, buf, p)" }.join "\n" %>
return buf[:p]
}
func (msg *<%= msg.name %>) TypeID() int {
return <%= msg.id %>
}
<% end %>

View file

@ -0,0 +1,26 @@
// Auto-generated, do not edit
package messages
import (
"fmt"
"io"
)
func ReadMessage(reader io.Reader) (Message, error) {
t, err := ReadUint(reader)
if err != nil {
return nil, err
}
switch t {
<% $messages.each do |msg| %>
case <%= msg.id %>:
msg := &<%= msg.name %>{}
<%= msg.attributes.map { |attr|
" if msg.#{attr.name}, err = Read#{attr.type.to_s.camel_case}(reader); err != nil {
return nil, err
}" }.join "\n" %>
return msg, nil
<% end %>
}
return nil, fmt.Errorf("Unknown message code: %v", t)
}

View file

@ -0,0 +1,16 @@
# Auto-generated, do not edit
from abc import ABC
class Message(ABC):
pass
<% $messages.each do |msg| %>
class <%= msg.name %>(Message):
__id__ = <%= msg.id %>
def __init__(self, <%= msg.attributes.map { |attr| "#{attr.name.underscore}" }.join ", " %>):
<%= msg.attributes.map { |attr| "self.#{attr.name.underscore} = #{attr.name.underscore}" }.join "\n "
%>
<% end %>

View file

@ -0,0 +1,29 @@
# Auto-generated, do not edit
from msgcodec.codec import Codec
from msgcodec.messages import *
class MessageCodec(Codec):
def read_message_id(self, reader: io.BytesIO) -> int:
"""
Read and return the first byte where the message id is encoded
"""
id_ = self.read_uint(reader)
return id_
def encode(self, m: Message) -> bytes:
...
def decode(self, b: bytes) -> Message:
reader = io.BytesIO(b)
message_id = self.read_message_id(reader)
<% $messages.each do |msg| %>
if message_id == <%= msg.id %>:
return <%= msg.name %>(
<%= msg.attributes.map { |attr|
"#{attr.name.underscore}=self.read_#{attr.type.to_s}(reader)" }
.join ",\n "
%>
)
<% end %>

View file

@ -0,0 +1,35 @@
// Auto-generated, do not edit
import PrimitiveReader from './PrimitiveReader'
import type { RawMessage } from './raw'
export default class RawMessageReader extends PrimitiveReader {
readMessage(): RawMessage | null {
const p = this.p
const resetPointer = () => {
this.p = p
return null
}
const tp = this.readUint()
if (tp === null) { return resetPointer() }
switch (tp) {
<% $messages.select { |msg| msg.js || msg.replayer }.each do |msg| %>
case <%= msg.id %>: {
<%= msg.attributes.map { |attr|
" const #{attr.name.first_lower} = this.read#{attr.type.to_s.camel_case}(); if (#{attr.name.first_lower} === null) { return resetPointer() }" }.join "\n" %>
return {
tp: "<%= msg.name.underscore %>",
<%= msg.attributes.map { |attr|
" #{attr.name.first_lower}," }.join "\n" %>
};
}
<% end %>
default:
throw new Error(`Unrecognizable message type: ${ tp }; Pointer at the position ${this.p} of ${this.buf.length}`)
return null;
}
}
}

View file

@ -0,0 +1,13 @@
// Auto-generated, do not edit
import type { Timed } from './timed'
import type { RawMessage } from './raw'
import type {
<%= $messages.select { |msg| msg.js || msg.replayer }.map { |msg| " Raw#{msg.name.underscore.camel_case}," }.join "\n" %>
} from './raw'
export type Message = RawMessage & Timed
<% $messages.select { |msg| msg.js || msg.replayer }.each do |msg| %>
export type <%= msg.name.underscore.camel_case %> = Raw<%= msg.name.underscore.camel_case %> & Timed
<% end %>

View file

@ -0,0 +1,14 @@
// Auto-generated, do not edit
export const TP_MAP = {
<%= $messages.select { |msg| msg.js || msg.replayer }.map { |msg| " #{msg.id}: \"#{msg.name.underscore}\"," }.join "\n" %>
}
<% $messages.select { |msg| msg.js || msg.replayer }.each do |msg| %>
export interface Raw<%= msg.name.underscore.camel_case %> {
tp: "<%= msg.name.underscore %>",
<%= msg.attributes.map { |attr| " #{attr.name.first_lower}: #{attr.type_js}," }.join "\n" %>
}
<% end %>
export type RawMessage = <%= $messages.select { |msg| msg.js || msg.replayer }.map { |msg| "Raw#{msg.name.underscore.camel_case}" }.join " | " %>;

View file

@ -0,0 +1,36 @@
// Auto-generated, do not edit
import UIKit
enum ASMessageType: UInt64 {
<%= $messages.map { |msg| " case #{msg.name.first_lower} = #{msg.id}" }.join "\n" %>
}
<% $messages.each do |msg| %>
class AS<%= msg.name.to_s.camel_case %>: ASMessage {
<%= msg.attributes[2..-1].map { |attr| " let #{attr.property}: #{attr.type_swift}" }.join "\n" %>
init(<%= msg.attributes[2..-1].map { |attr| "#{attr.property}: #{attr.type_swift}" }.join ", " %>) {
<%= msg.attributes[2..-1].map { |attr| " self.#{attr.property} = #{attr.property}" }.join "\n" %>
super.init(messageType: .<%= "#{msg.name.first_lower}" %>)
}
override init?(genericMessage: GenericMessage) {
<% if msg.attributes.length > 2 %> do {
var offset = 0
<%= msg.attributes[2..-1].map { |attr| " self.#{attr.property} = try genericMessage.body.read#{attr.type_swift_read}(offset: &offset)" }.join "\n" %>
super.init(genericMessage: genericMessage)
} catch {
return nil
}
<% else %>
super.init(genericMessage: genericMessage)
<% end %>}
override func contentData() -> Data {
return Data(values: UInt64(<%= "#{msg.id}"%>), timestamp<% if msg.attributes.length > 2 %>, Data(values: <%= msg.attributes[2..-1].map { |attr| attr.property }.join ", "%>)<% end %>)
}
override var description: String {
return "-->> <%= msg.name.to_s.camel_case %>(<%= "#{msg.id}"%>): timestamp:\(timestamp) <%= msg.attributes[2..-1].map { |attr| "#{attr.property}:\\(#{attr.property})" }.join " "%>";
}
}
<% end %>

View file

@ -0,0 +1,31 @@
// Auto-generated, do not edit
import type { Writer, Message }from "./types.js";
export default Message
function bindNew<C extends { new(...args: A): T }, A extends any[], T>(
Class: C & { new(...args: A): T }
): C & ((...args: A) => T) {
function _Class(...args: A) {
return new Class(...args);
}
_Class.prototype = Class.prototype;
return <C & ((...args: A) => T)>_Class;
}
export const classes: Map<number, Function> = new Map();
<% $messages.select { |msg| msg.js }.each do |msg| %>
class _<%= msg.name %> implements Message {
readonly _id: number = <%= msg.id %>;
constructor(
<%= msg.attributes.map { |attr| "public #{attr.name.first_lower}: #{attr.type_js}" }.join ",\n " %>
) {}
encode(writer: Writer): boolean {
return writer.uint(<%= msg.id %>)<%= " &&" if msg.attributes.length() > 0 %>
<%= msg.attributes.map { |attr| "writer.#{attr.type}(this.#{attr.name.first_lower})" }.join " &&\n " %>;
}
}
export const <%= msg.name %> = bindNew(_<%= msg.name %>);
classes.set(<%= msg.id %>, <%= msg.name %>);
<% end %>

View file

@ -0,0 +1,3 @@
FROM alpine
# Fix busybox vulnerability
RUN apk upgrade busybox --no-cache --repository=http://dl-cdn.alpinelinux.org/alpine/edge/main

View file

@ -2,39 +2,104 @@
This file documents all notable changes to [ingress-nginx](https://github.com/kubernetes/ingress-nginx) Helm Chart. The release numbering uses [semantic versioning](http://semver.org).
### 4.2.0
- Support for Kubernetes v1.19.0 was removed
- "[8810](https://github.com/kubernetes/ingress-nginx/pull/8810) Prepare for v1.3.0"
- "[8808](https://github.com/kubernetes/ingress-nginx/pull/8808) revert arch var name"
- "[8805](https://github.com/kubernetes/ingress-nginx/pull/8805) Bump k8s.io/klog/v2 from 2.60.1 to 2.70.1"
- "[8803](https://github.com/kubernetes/ingress-nginx/pull/8803) Update to nginx base with alpine v3.16"
- "[8802](https://github.com/kubernetes/ingress-nginx/pull/8802) chore: start v1.3.0 release process"
- "[8798](https://github.com/kubernetes/ingress-nginx/pull/8798) Add v1.24.0 to test matrix"
- "[8796](https://github.com/kubernetes/ingress-nginx/pull/8796) fix: add MAC_OS variable for static-check"
- "[8793](https://github.com/kubernetes/ingress-nginx/pull/8793) changed to alpine-v3.16"
- "[8781](https://github.com/kubernetes/ingress-nginx/pull/8781) Bump github.com/stretchr/testify from 1.7.5 to 1.8.0"
- "[8778](https://github.com/kubernetes/ingress-nginx/pull/8778) chore: remove stable.txt from release process"
- "[8775](https://github.com/kubernetes/ingress-nginx/pull/8775) Remove stable"
- "[8773](https://github.com/kubernetes/ingress-nginx/pull/8773) Bump github/codeql-action from 2.1.14 to 2.1.15"
- "[8772](https://github.com/kubernetes/ingress-nginx/pull/8772) Bump ossf/scorecard-action from 1.1.1 to 1.1.2"
- "[8771](https://github.com/kubernetes/ingress-nginx/pull/8771) fix bullet md format"
- "[8770](https://github.com/kubernetes/ingress-nginx/pull/8770) Add condition for monitoring.coreos.com/v1 API"
- "[8769](https://github.com/kubernetes/ingress-nginx/pull/8769) Fix typos and add links to developer guide"
- "[8767](https://github.com/kubernetes/ingress-nginx/pull/8767) change v1.2.0 to v1.2.1 in deploy doc URLs"
- "[8765](https://github.com/kubernetes/ingress-nginx/pull/8765) Bump github/codeql-action from 1.0.26 to 2.1.14"
- "[8752](https://github.com/kubernetes/ingress-nginx/pull/8752) Bump github.com/spf13/cobra from 1.4.0 to 1.5.0"
- "[8751](https://github.com/kubernetes/ingress-nginx/pull/8751) Bump github.com/stretchr/testify from 1.7.2 to 1.7.5"
- "[8750](https://github.com/kubernetes/ingress-nginx/pull/8750) added announcement"
- "[8740](https://github.com/kubernetes/ingress-nginx/pull/8740) change sha e2etestrunner and echoserver"
- "[8738](https://github.com/kubernetes/ingress-nginx/pull/8738) Update docs to make it easier for noobs to follow step by step"
- "[8737](https://github.com/kubernetes/ingress-nginx/pull/8737) updated baseimage sha"
- "[8736](https://github.com/kubernetes/ingress-nginx/pull/8736) set ld-musl-path"
- "[8733](https://github.com/kubernetes/ingress-nginx/pull/8733) feat: migrate leaderelection lock to leases"
- "[8726](https://github.com/kubernetes/ingress-nginx/pull/8726) prometheus metric: upstream_latency_seconds"
- "[8720](https://github.com/kubernetes/ingress-nginx/pull/8720) Ci pin deps"
- "[8719](https://github.com/kubernetes/ingress-nginx/pull/8719) Working OpenTelemetry sidecar (base nginx image)"
- "[8714](https://github.com/kubernetes/ingress-nginx/pull/8714) Create Openssf scorecard"
- "[8708](https://github.com/kubernetes/ingress-nginx/pull/8708) Bump github.com/prometheus/common from 0.34.0 to 0.35.0"
- "[8703](https://github.com/kubernetes/ingress-nginx/pull/8703) Bump actions/dependency-review-action from 1 to 2"
- "[8701](https://github.com/kubernetes/ingress-nginx/pull/8701) Fix several typos"
- "[8699](https://github.com/kubernetes/ingress-nginx/pull/8699) fix the gosec test and a make target for it"
- "[8698](https://github.com/kubernetes/ingress-nginx/pull/8698) Bump actions/upload-artifact from 2.3.1 to 3.1.0"
- "[8697](https://github.com/kubernetes/ingress-nginx/pull/8697) Bump actions/setup-go from 2.2.0 to 3.2.0"
- "[8695](https://github.com/kubernetes/ingress-nginx/pull/8695) Bump actions/download-artifact from 2 to 3"
- "[8694](https://github.com/kubernetes/ingress-nginx/pull/8694) Bump crazy-max/ghaction-docker-buildx from 1.6.2 to 3.3.1"
### 4.1.2
- "[8587](https://github.com/kubernetes/ingress-nginx/pull/8587) Add CAP_SYS_CHROOT to DS/PSP when needed"
- "[8458](https://github.com/kubernetes/ingress-nginx/pull/8458) Add portNamePreffix Helm chart parameter"
- "[8522](https://github.com/kubernetes/ingress-nginx/pull/8522) Add documentation for controller.service.loadBalancerIP in Helm chart"
### 4.1.0
- "[8481](https://github.com/kubernetes/ingress-nginx/pull/8481) Fix log creation in chroot script"
- "[8479](https://github.com/kubernetes/ingress-nginx/pull/8479) changed nginx base img tag to img built with alpine3.14.6"
- "[8478](https://github.com/kubernetes/ingress-nginx/pull/8478) update base images and protobuf gomod"
- "[8468](https://github.com/kubernetes/ingress-nginx/pull/8468) Fallback to ngx.var.scheme for redirectScheme with use-forward-headers when X-Forwarded-Proto is empty"
- "[8456](https://github.com/kubernetes/ingress-nginx/pull/8456) Implement object deep inspector"
- "[8455](https://github.com/kubernetes/ingress-nginx/pull/8455) Update dependencies"
- "[8454](https://github.com/kubernetes/ingress-nginx/pull/8454) Update index.md"
- "[8447](https://github.com/kubernetes/ingress-nginx/pull/8447) typo fixing"
- "[8446](https://github.com/kubernetes/ingress-nginx/pull/8446) Fix suggested annotation-value-word-blocklist"
- "[8444](https://github.com/kubernetes/ingress-nginx/pull/8444) replace deprecated topology key in example with current one"
- "[8443](https://github.com/kubernetes/ingress-nginx/pull/8443) Add dependency review enforcement"
- "[8434](https://github.com/kubernetes/ingress-nginx/pull/8434) added new auth-tls-match-cn annotation"
- "[8426](https://github.com/kubernetes/ingress-nginx/pull/8426) Bump github.com/prometheus/common from 0.32.1 to 0.33.0"
### 4.0.18
"[8291](https://github.com/kubernetes/ingress-nginx/pull/8291) remove git tag env from cloud build"
"[8286](https://github.com/kubernetes/ingress-nginx/pull/8286) Fix OpenTelemetry sidecar image build"
"[8277](https://github.com/kubernetes/ingress-nginx/pull/8277) Add OpenSSF Best practices badge"
"[8273](https://github.com/kubernetes/ingress-nginx/pull/8273) Issue#8241"
"[8267](https://github.com/kubernetes/ingress-nginx/pull/8267) Add fsGroup value to admission-webhooks/job-patch charts"
"[8262](https://github.com/kubernetes/ingress-nginx/pull/8262) Updated confusing error"
"[8256](https://github.com/kubernetes/ingress-nginx/pull/8256) fix: deny locations with invalid auth-url annotation"
"[8253](https://github.com/kubernetes/ingress-nginx/pull/8253) Add a certificate info metric"
"[8236](https://github.com/kubernetes/ingress-nginx/pull/8236) webhook: remove useless code."
"[8227](https://github.com/kubernetes/ingress-nginx/pull/8227) Update libraries in webhook image"
"[8225](https://github.com/kubernetes/ingress-nginx/pull/8225) fix inconsistent-label-cardinality for prometheus metrics: nginx_ingress_controller_requests"
"[8221](https://github.com/kubernetes/ingress-nginx/pull/8221) Do not validate ingresses with unknown ingress class in admission webhook endpoint"
"[8210](https://github.com/kubernetes/ingress-nginx/pull/8210) Bump github.com/prometheus/client_golang from 1.11.0 to 1.12.1"
"[8209](https://github.com/kubernetes/ingress-nginx/pull/8209) Bump google.golang.org/grpc from 1.43.0 to 1.44.0"
"[8204](https://github.com/kubernetes/ingress-nginx/pull/8204) Add Artifact Hub lint"
"[8203](https://github.com/kubernetes/ingress-nginx/pull/8203) Fix Indentation of example and link to cert-manager tutorial"
"[8201](https://github.com/kubernetes/ingress-nginx/pull/8201) feat(metrics): add path and method labels to requests countera"
"[8199](https://github.com/kubernetes/ingress-nginx/pull/8199) use functional options to reduce number of methods creating an EchoDeployment"
"[8196](https://github.com/kubernetes/ingress-nginx/pull/8196) docs: fix inconsistent controller annotation"
"[8191](https://github.com/kubernetes/ingress-nginx/pull/8191) Using Go install for misspell"
"[8186](https://github.com/kubernetes/ingress-nginx/pull/8186) prometheus+grafana using servicemonitor"
"[8185](https://github.com/kubernetes/ingress-nginx/pull/8185) Append elements on match, instead of removing for cors-annotations"
"[8179](https://github.com/kubernetes/ingress-nginx/pull/8179) Bump github.com/opencontainers/runc from 1.0.3 to 1.1.0"
"[8173](https://github.com/kubernetes/ingress-nginx/pull/8173) Adding annotations to the controller service account"
"[8163](https://github.com/kubernetes/ingress-nginx/pull/8163) Update the $req_id placeholder description"
"[8162](https://github.com/kubernetes/ingress-nginx/pull/8162) Versioned static manifests"
"[8159](https://github.com/kubernetes/ingress-nginx/pull/8159) Adding some geoip variables and default values"
"[8155](https://github.com/kubernetes/ingress-nginx/pull/8155) #7271 feat: avoid-pdb-creation-when-default-backend-disabled-and-replicas-gt-1"
"[8151](https://github.com/kubernetes/ingress-nginx/pull/8151) Automatically generate helm docs"
"[8143](https://github.com/kubernetes/ingress-nginx/pull/8143) Allow to configure delay before controller exits"
"[8136](https://github.com/kubernetes/ingress-nginx/pull/8136) add ingressClass option to helm chart - back compatibility with ingress.class annotations"
"[8126](https://github.com/kubernetes/ingress-nginx/pull/8126) Example for JWT"
- "[8291](https://github.com/kubernetes/ingress-nginx/pull/8291) remove git tag env from cloud build"
- "[8286](https://github.com/kubernetes/ingress-nginx/pull/8286) Fix OpenTelemetry sidecar image build"
- "[8277](https://github.com/kubernetes/ingress-nginx/pull/8277) Add OpenSSF Best practices badge"
- "[8273](https://github.com/kubernetes/ingress-nginx/pull/8273) Issue#8241"
- "[8267](https://github.com/kubernetes/ingress-nginx/pull/8267) Add fsGroup value to admission-webhooks/job-patch charts"
- "[8262](https://github.com/kubernetes/ingress-nginx/pull/8262) Updated confusing error"
- "[8256](https://github.com/kubernetes/ingress-nginx/pull/8256) fix: deny locations with invalid auth-url annotation"
- "[8253](https://github.com/kubernetes/ingress-nginx/pull/8253) Add a certificate info metric"
- "[8236](https://github.com/kubernetes/ingress-nginx/pull/8236) webhook: remove useless code."
- "[8227](https://github.com/kubernetes/ingress-nginx/pull/8227) Update libraries in webhook image"
- "[8225](https://github.com/kubernetes/ingress-nginx/pull/8225) fix inconsistent-label-cardinality for prometheus metrics: nginx_ingress_controller_requests"
- "[8221](https://github.com/kubernetes/ingress-nginx/pull/8221) Do not validate ingresses with unknown ingress class in admission webhook endpoint"
- "[8210](https://github.com/kubernetes/ingress-nginx/pull/8210) Bump github.com/prometheus/client_golang from 1.11.0 to 1.12.1"
- "[8209](https://github.com/kubernetes/ingress-nginx/pull/8209) Bump google.golang.org/grpc from 1.43.0 to 1.44.0"
- "[8204](https://github.com/kubernetes/ingress-nginx/pull/8204) Add Artifact Hub lint"
- "[8203](https://github.com/kubernetes/ingress-nginx/pull/8203) Fix Indentation of example and link to cert-manager tutorial"
- "[8201](https://github.com/kubernetes/ingress-nginx/pull/8201) feat(metrics): add path and method labels to requests countera"
- "[8199](https://github.com/kubernetes/ingress-nginx/pull/8199) use functional options to reduce number of methods creating an EchoDeployment"
- "[8196](https://github.com/kubernetes/ingress-nginx/pull/8196) docs: fix inconsistent controller annotation"
- "[8191](https://github.com/kubernetes/ingress-nginx/pull/8191) Using Go install for misspell"
- "[8186](https://github.com/kubernetes/ingress-nginx/pull/8186) prometheus+grafana using servicemonitor"
- "[8185](https://github.com/kubernetes/ingress-nginx/pull/8185) Append elements on match, instead of removing for cors-annotations"
- "[8179](https://github.com/kubernetes/ingress-nginx/pull/8179) Bump github.com/opencontainers/runc from 1.0.3 to 1.1.0"
- "[8173](https://github.com/kubernetes/ingress-nginx/pull/8173) Adding annotations to the controller service account"
- "[8163](https://github.com/kubernetes/ingress-nginx/pull/8163) Update the $req_id placeholder description"
- "[8162](https://github.com/kubernetes/ingress-nginx/pull/8162) Versioned static manifests"
- "[8159](https://github.com/kubernetes/ingress-nginx/pull/8159) Adding some geoip variables and default values"
- "[8155](https://github.com/kubernetes/ingress-nginx/pull/8155) #7271 feat: avoid-pdb-creation-when-default-backend-disabled-and-replicas-gt-1"
- "[8151](https://github.com/kubernetes/ingress-nginx/pull/8151) Automatically generate helm docs"
- "[8143](https://github.com/kubernetes/ingress-nginx/pull/8143) Allow to configure delay before controller exits"
- "[8136](https://github.com/kubernetes/ingress-nginx/pull/8136) add ingressClass option to helm chart - back compatibility with ingress.class annotations"
- "[8126](https://github.com/kubernetes/ingress-nginx/pull/8126) Example for JWT"
### 4.0.15
@ -119,11 +184,11 @@ This file documents all notable changes to [ingress-nginx](https://github.com/ku
- [7707] https://github.com/kubernetes/ingress-nginx/pull/7707 Release v1.0.2 of ingress-nginx
### 4.0.2
### 4.0.2
- [7681] https://github.com/kubernetes/ingress-nginx/pull/7681 Release v1.0.1 of ingress-nginx
### 4.0.1
### 4.0.1
- [7535] https://github.com/kubernetes/ingress-nginx/pull/7535 Release v1.0.0 ingress-nginx

View file

@ -1,13 +1,46 @@
annotations:
artifacthub.io/changes: |
- "#8253 Add a certificate info metric"
- "#8225 fix inconsistent-label-cardinality for prometheus metrics: nginx_ingress_controller_requests"
- "#8162 Versioned static manifests"
- "#8159 Adding some geoip variables and default values"
- "#8221 Do not validate ingresses with unknown ingress class in admission webhook endpoint"
- "[8810](https://github.com/kubernetes/ingress-nginx/pull/8810) Prepare for v1.3.0"
- "[8808](https://github.com/kubernetes/ingress-nginx/pull/8808) revert arch var name"
- "[8805](https://github.com/kubernetes/ingress-nginx/pull/8805) Bump k8s.io/klog/v2 from 2.60.1 to 2.70.1"
- "[8803](https://github.com/kubernetes/ingress-nginx/pull/8803) Update to nginx base with alpine v3.16"
- "[8802](https://github.com/kubernetes/ingress-nginx/pull/8802) chore: start v1.3.0 release process"
- "[8798](https://github.com/kubernetes/ingress-nginx/pull/8798) Add v1.24.0 to test matrix"
- "[8796](https://github.com/kubernetes/ingress-nginx/pull/8796) fix: add MAC_OS variable for static-check"
- "[8793](https://github.com/kubernetes/ingress-nginx/pull/8793) changed to alpine-v3.16"
- "[8781](https://github.com/kubernetes/ingress-nginx/pull/8781) Bump github.com/stretchr/testify from 1.7.5 to 1.8.0"
- "[8778](https://github.com/kubernetes/ingress-nginx/pull/8778) chore: remove stable.txt from release process"
- "[8775](https://github.com/kubernetes/ingress-nginx/pull/8775) Remove stable"
- "[8773](https://github.com/kubernetes/ingress-nginx/pull/8773) Bump github/codeql-action from 2.1.14 to 2.1.15"
- "[8772](https://github.com/kubernetes/ingress-nginx/pull/8772) Bump ossf/scorecard-action from 1.1.1 to 1.1.2"
- "[8771](https://github.com/kubernetes/ingress-nginx/pull/8771) fix bullet md format"
- "[8770](https://github.com/kubernetes/ingress-nginx/pull/8770) Add condition for monitoring.coreos.com/v1 API"
- "[8769](https://github.com/kubernetes/ingress-nginx/pull/8769) Fix typos and add links to developer guide"
- "[8767](https://github.com/kubernetes/ingress-nginx/pull/8767) change v1.2.0 to v1.2.1 in deploy doc URLs"
- "[8765](https://github.com/kubernetes/ingress-nginx/pull/8765) Bump github/codeql-action from 1.0.26 to 2.1.14"
- "[8752](https://github.com/kubernetes/ingress-nginx/pull/8752) Bump github.com/spf13/cobra from 1.4.0 to 1.5.0"
- "[8751](https://github.com/kubernetes/ingress-nginx/pull/8751) Bump github.com/stretchr/testify from 1.7.2 to 1.7.5"
- "[8750](https://github.com/kubernetes/ingress-nginx/pull/8750) added announcement"
- "[8740](https://github.com/kubernetes/ingress-nginx/pull/8740) change sha e2etestrunner and echoserver"
- "[8738](https://github.com/kubernetes/ingress-nginx/pull/8738) Update docs to make it easier for noobs to follow step by step"
- "[8737](https://github.com/kubernetes/ingress-nginx/pull/8737) updated baseimage sha"
- "[8736](https://github.com/kubernetes/ingress-nginx/pull/8736) set ld-musl-path"
- "[8733](https://github.com/kubernetes/ingress-nginx/pull/8733) feat: migrate leaderelection lock to leases"
- "[8726](https://github.com/kubernetes/ingress-nginx/pull/8726) prometheus metric: upstream_latency_seconds"
- "[8720](https://github.com/kubernetes/ingress-nginx/pull/8720) Ci pin deps"
- "[8719](https://github.com/kubernetes/ingress-nginx/pull/8719) Working OpenTelemetry sidecar (base nginx image)"
- "[8714](https://github.com/kubernetes/ingress-nginx/pull/8714) Create Openssf scorecard"
- "[8708](https://github.com/kubernetes/ingress-nginx/pull/8708) Bump github.com/prometheus/common from 0.34.0 to 0.35.0"
- "[8703](https://github.com/kubernetes/ingress-nginx/pull/8703) Bump actions/dependency-review-action from 1 to 2"
- "[8701](https://github.com/kubernetes/ingress-nginx/pull/8701) Fix several typos"
- "[8699](https://github.com/kubernetes/ingress-nginx/pull/8699) fix the gosec test and a make target for it"
- "[8698](https://github.com/kubernetes/ingress-nginx/pull/8698) Bump actions/upload-artifact from 2.3.1 to 3.1.0"
- "[8697](https://github.com/kubernetes/ingress-nginx/pull/8697) Bump actions/setup-go from 2.2.0 to 3.2.0"
- "[8695](https://github.com/kubernetes/ingress-nginx/pull/8695) Bump actions/download-artifact from 2 to 3"
- "[8694](https://github.com/kubernetes/ingress-nginx/pull/8694) Bump crazy-max/ghaction-docker-buildx from 1.6.2 to 3.3.1"
artifacthub.io/prerelease: "false"
apiVersion: v2
appVersion: 1.1.2
appVersion: 1.3.0
description: Ingress controller for Kubernetes using NGINX as a reverse proxy and
load balancer
home: https://github.com/kubernetes/ingress-nginx
@ -15,11 +48,13 @@ icon: https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Nginx_logo.svg/5
keywords:
- ingress
- nginx
kubeVersion: '>=1.19.0-0'
kubeVersion: '>=1.20.0-0'
maintainers:
- name: ChiefAlexander
- name: rikatz
- name: strongjz
- name: tao12345666333
name: ingress-nginx
sources:
- https://github.com/kubernetes/ingress-nginx
type: application
version: 4.0.18
version: 4.2.0

View file

@ -2,7 +2,7 @@
[ingress-nginx](https://github.com/kubernetes/ingress-nginx) Ingress controller for Kubernetes using NGINX as a reverse proxy and load balancer
![Version: 4.0.18](https://img.shields.io/badge/Version-4.0.18-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.1.2](https://img.shields.io/badge/AppVersion-1.1.2-informational?style=flat-square)
![Version: 4.2.0](https://img.shields.io/badge/Version-4.2.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.3.0](https://img.shields.io/badge/AppVersion-1.3.0-informational?style=flat-square)
To use, add `ingressClassName: nginx` spec field or the `kubernetes.io/ingress.class: nginx` annotation to your Ingress resources.
@ -111,7 +111,7 @@ controller:
### AWS L7 ELB with SSL Termination
Annotate the controller as shown in the [nginx-ingress l7 patch](https://github.com/kubernetes/ingress-nginx/blob/main/deploy/aws/l7/service-l7.yaml):
Annotate the controller as shown in the [nginx-ingress l7 patch](https://github.com/kubernetes/ingress-nginx/blob/ab3a789caae65eec4ad6e3b46b19750b481b6bce/deploy/aws/l7/service-l7.yaml):
```yaml
controller:
@ -128,7 +128,7 @@ controller:
### AWS route53-mapper
To configure the LoadBalancer service with the [route53-mapper addon](https://github.com/kubernetes/kops/tree/master/addons/route53-mapper), add the `domainName` annotation and `dns` label:
To configure the LoadBalancer service with the [route53-mapper addon](https://github.com/kubernetes/kops/blob/be63d4f1a7a46daaf1c4c482527328236850f111/addons/route53-mapper/README.md), add the `domainName` annotation and `dns` label:
```yaml
controller:
@ -231,7 +231,7 @@ As of version `1.26.0` of this chart, by simply not providing any clusterIP valu
## Requirements
Kubernetes: `>=1.19.0-0`
Kubernetes: `>=1.20.0-0`
## Values
@ -244,7 +244,8 @@ Kubernetes: `>=1.19.0-0`
| controller.admissionWebhooks.createSecretJob.resources | object | `{}` | |
| controller.admissionWebhooks.enabled | bool | `true` | |
| controller.admissionWebhooks.existingPsp | string | `""` | Use an existing PSP instead of creating one |
| controller.admissionWebhooks.failurePolicy | string | `"Fail"` | |
| controller.admissionWebhooks.extraEnvs | list | `[]` | Additional environment variables to set |
| controller.admissionWebhooks.failurePolicy | string | `"Fail"` | Admission Webhook failure policy to use |
| controller.admissionWebhooks.key | string | `"/usr/local/certificates/key"` | |
| controller.admissionWebhooks.labels | object | `{}` | Labels to be added to admission webhooks |
| controller.admissionWebhooks.namespaceSelector | object | `{}` | |
@ -254,7 +255,7 @@ Kubernetes: `>=1.19.0-0`
| controller.admissionWebhooks.patch.image.digest | string | `"sha256:64d8c73dca984af206adf9d6d7e46aa550362b1d7a01f3a0a91b20cc67868660"` | |
| controller.admissionWebhooks.patch.image.image | string | `"ingress-nginx/kube-webhook-certgen"` | |
| controller.admissionWebhooks.patch.image.pullPolicy | string | `"IfNotPresent"` | |
| controller.admissionWebhooks.patch.image.registry | string | `"k8s.gcr.io"` | |
| controller.admissionWebhooks.patch.image.registry | string | `"registry.k8s.io"` | |
| controller.admissionWebhooks.patch.image.tag | string | `"v1.1.1"` | |
| controller.admissionWebhooks.patch.labels | object | `{}` | Labels to be added to patch job resources |
| controller.admissionWebhooks.patch.nodeSelector."kubernetes.io/os" | string | `"linux"` | |
@ -306,12 +307,14 @@ Kubernetes: `>=1.19.0-0`
| controller.hostPort.ports.https | int | `443` | 'hostPort' https port |
| controller.hostname | object | `{}` | Optionally customize the pod hostname. |
| controller.image.allowPrivilegeEscalation | bool | `true` | |
| controller.image.digest | string | `"sha256:28b11ce69e57843de44e3db6413e98d09de0f6688e33d4bd384002a44f78405c"` | |
| controller.image.chroot | bool | `false` | |
| controller.image.digest | string | `"sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5"` | |
| controller.image.digestChroot | string | `"sha256:0fcb91216a22aae43b374fc2e6a03b8afe9e8c78cbf07a09d75636dc4ea3c191"` | |
| controller.image.image | string | `"ingress-nginx/controller"` | |
| controller.image.pullPolicy | string | `"IfNotPresent"` | |
| controller.image.registry | string | `"k8s.gcr.io"` | |
| controller.image.registry | string | `"registry.k8s.io"` | |
| controller.image.runAsUser | int | `101` | |
| controller.image.tag | string | `"v1.1.2"` | |
| controller.image.tag | string | `"v1.3.0"` | |
| controller.ingressClass | string | `"nginx"` | For backwards compatibility with ingress.class annotation, use ingressClass. Algorithm is as follows, first ingressClassName is considered, if not present, controller looks for ingress.class annotation |
| controller.ingressClassByName | bool | `false` | Process IngressClass per name (additionally as per spec.controller). |
| controller.ingressClassResource.controllerValue | string | `"k8s.io/ingress-nginx"` | Controller-value of the controller that is processing this ingressClass |
@ -399,6 +402,7 @@ Kubernetes: `>=1.19.0-0`
| controller.service.ipFamilies | list | `["IPv4"]` | List of IP families (e.g. IPv4, IPv6) assigned to the service. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. |
| controller.service.ipFamilyPolicy | string | `"SingleStack"` | Represents the dual-stack-ness requested or required by this Service. Possible values are SingleStack, PreferDualStack or RequireDualStack. The ipFamilies and clusterIPs fields depend on the value of this field. |
| controller.service.labels | object | `{}` | |
| controller.service.loadBalancerIP | string | `""` | Used by cloud providers to connect the resulting `LoadBalancer` to a pre-existing static IP according to https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer |
| controller.service.loadBalancerSourceRanges | list | `[]` | |
| controller.service.nodePorts.http | string | `""` | |
| controller.service.nodePorts.https | string | `""` | |
@ -409,6 +413,7 @@ Kubernetes: `>=1.19.0-0`
| controller.service.targetPorts.http | string | `"http"` | |
| controller.service.targetPorts.https | string | `"https"` | |
| controller.service.type | string | `"LoadBalancer"` | |
| controller.shareProcessNamespace | bool | `false` | |
| controller.sysctls | object | `{}` | See https://kubernetes.io/docs/tasks/administer-cluster/sysctl-cluster/ for notes on enabling and using sysctls |
| controller.tcp.annotations | object | `{}` | Annotations to be added to the tcp config configmap |
| controller.tcp.configMapNamespace | string | `""` | Allows customization of the tcp-services-configmap; defaults to $(POD_NAMESPACE) |
@ -437,7 +442,7 @@ Kubernetes: `>=1.19.0-0`
| defaultBackend.image.image | string | `"defaultbackend-amd64"` | |
| defaultBackend.image.pullPolicy | string | `"IfNotPresent"` | |
| defaultBackend.image.readOnlyRootFilesystem | bool | `true` | |
| defaultBackend.image.registry | string | `"k8s.gcr.io"` | |
| defaultBackend.image.registry | string | `"registry.k8s.io"` | |
| defaultBackend.image.runAsNonRoot | bool | `true` | |
| defaultBackend.image.runAsUser | int | `65534` | |
| defaultBackend.image.tag | string | `"1.5"` | |
@ -474,6 +479,7 @@ Kubernetes: `>=1.19.0-0`
| dhParam | string | `nil` | A base64-encoded Diffie-Hellman parameter. This can be generated with: `openssl dhparam 4096 2> /dev/null | base64` |
| imagePullSecrets | list | `[]` | Optional array of imagePullSecrets containing private registry credentials |
| podSecurityPolicy.enabled | bool | `false` | |
| portNamePrefix | string | `""` | Prefix for TCP and UDP ports names in ingress controller service |
| rbac.create | bool | `true` | |
| rbac.scope | bool | `false` | |
| revisionHistoryLimit | int | `10` | Rollback limit |
@ -481,6 +487,6 @@ Kubernetes: `>=1.19.0-0`
| serviceAccount.automountServiceAccountToken | bool | `true` | |
| serviceAccount.create | bool | `true` | |
| serviceAccount.name | string | `""` | |
| tcp | object | `{}` | TCP service key:value pairs |
| udp | object | `{}` | UDP service key:value pairs |
| tcp | object | `{}` | TCP service key-value pairs |
| udp | object | `{}` | UDP service key-value pairs |

View file

@ -110,7 +110,7 @@ controller:
### AWS L7 ELB with SSL Termination
Annotate the controller as shown in the [nginx-ingress l7 patch](https://github.com/kubernetes/ingress-nginx/blob/main/deploy/aws/l7/service-l7.yaml):
Annotate the controller as shown in the [nginx-ingress l7 patch](https://github.com/kubernetes/ingress-nginx/blob/ab3a789caae65eec4ad6e3b46b19750b481b6bce/deploy/aws/l7/service-l7.yaml):
```yaml
controller:
@ -127,7 +127,7 @@ controller:
### AWS route53-mapper
To configure the LoadBalancer service with the [route53-mapper addon](https://github.com/kubernetes/kops/tree/master/addons/route53-mapper), add the `domainName` annotation and `dns` label:
To configure the LoadBalancer service with the [route53-mapper addon](https://github.com/kubernetes/kops/blob/be63d4f1a7a46daaf1c4c482527328236850f111/addons/route53-mapper/README.md), add the `domainName` annotation and `dns` label:
```yaml
controller:

View file

@ -0,0 +1,18 @@
controller:
kind: DaemonSet
image:
repository: ingress-controller/controller
tag: 1.0.0-dev
digest: null
admissionWebhooks:
enabled: false
service:
type: ClusterIP
tcp:
9000: "default/test:8080"
udp:
9001: "default/test:8080"
portNamePrefix: "port"

View file

@ -0,0 +1,17 @@
controller:
image:
repository: ingress-controller/controller
tag: 1.0.0-dev
digest: null
admissionWebhooks:
enabled: false
service:
type: ClusterIP
tcp:
9000: "default/test:8080"
udp:
9001: "default/test:8080"
portNamePrefix: "port"

View file

@ -0,0 +1,12 @@
controller:
service:
type: ClusterIP
admissionWebhooks:
enabled: true
extraEnvs:
- name: FOO
value: foo
- name: TEST
value: test
patch:
enabled: true

View file

@ -43,11 +43,40 @@ capabilities:
- ALL
add:
- NET_BIND_SERVICE
{{- if .Values.controller.image.chroot }}
- SYS_CHROOT
{{- end }}
runAsUser: {{ .Values.controller.image.runAsUser }}
allowPrivilegeEscalation: {{ .Values.controller.image.allowPrivilegeEscalation }}
{{- end }}
{{- end -}}
{{/*
Get specific image
*/}}
{{- define "ingress-nginx.image" -}}
{{- if .chroot -}}
{{- printf "%s-chroot" .image -}}
{{- else -}}
{{- printf "%s" .image -}}
{{- end }}
{{- end -}}
{{/*
Get specific image digest
*/}}
{{- define "ingress-nginx.imageDigest" -}}
{{- if .chroot -}}
{{- if .digestChroot -}}
{{- printf "@%s" .digestChroot -}}
{{- end }}
{{- else -}}
{{ if .digest -}}
{{- printf "@%s" .digest -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create a default fully qualified controller name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).

View file

@ -56,6 +56,9 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- if .Values.controller.admissionWebhooks.extraEnvs }}
{{- toYaml .Values.controller.admissionWebhooks.extraEnvs | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
{{- if .Values.controller.admissionWebhooks.createSecretJob.resources }}

View file

@ -58,6 +58,9 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
{{- if .Values.controller.admissionWebhooks.extraEnvs }}
{{- toYaml .Values.controller.admissionWebhooks.extraEnvs | nindent 12 }}
{{- end }}
securityContext:
allowPrivilegeEscalation: false
{{- if .Values.controller.admissionWebhooks.patchWebhookJob.resources }}

View file

@ -29,6 +29,13 @@ rules:
verbs:
- list
- watch
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- list
- watch
{{- if and .Values.controller.scope.enabled .Values.controller.scope.namespace }}
- apiGroups:
- ""

View file

@ -67,11 +67,14 @@ spec:
- name: {{ $sysctl | quote }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
{{- if .Values.controller.shareProcessNamespace }}
shareProcessNamespace: {{ .Values.controller.shareProcessNamespace }}
{{- end }}
containers:
- name: {{ .Values.controller.containerName }}
{{- with .Values.controller.image }}
image: "{{- if .repository -}}{{ .repository }}{{ else }}{{ .registry }}/{{ .image }}{{- end -}}:{{ .tag }}{{- if (.digest) -}} @{{.digest}} {{- end -}}"
image: "{{- if .repository -}}{{ .repository }}{{ else }}{{ .registry }}/{{ include "ingress-nginx.image" . }}{{- end -}}:{{ .tag }}{{ include "ingress-nginx.imageDigest" . }}"
{{- end }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
{{- if .Values.controller.lifecycle }}
@ -79,14 +82,7 @@ spec:
{{- end }}
args:
{{- include "ingress-nginx.params" . | nindent 12 }}
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
runAsUser: {{ .Values.controller.image.runAsUser }}
allowPrivilegeEscalation: {{ .Values.controller.image.allowPrivilegeEscalation }}
securityContext: {{ include "controller.containerSecurityContext" . | nindent 12 }}
env:
- name: POD_NAME
valueFrom:
@ -128,7 +124,7 @@ spec:
protocol: TCP
{{- end }}
{{- range $key, $value := .Values.tcp }}
- name: {{ $key }}-tcp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-tcp
containerPort: {{ $key }}
protocol: TCP
{{- if $.Values.controller.hostPort.enabled }}
@ -136,7 +132,7 @@ spec:
{{- end }}
{{- end }}
{{- range $key, $value := .Values.udp }}
- name: {{ $key }}-udp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-udp
containerPort: {{ $key }}
protocol: UDP
{{- if $.Values.controller.hostPort.enabled }}

View file

@ -71,11 +71,14 @@ spec:
- name: {{ $sysctl | quote }}
value: {{ $value | quote }}
{{- end }}
{{- end }}
{{- if .Values.controller.shareProcessNamespace }}
shareProcessNamespace: {{ .Values.controller.shareProcessNamespace }}
{{- end }}
containers:
- name: {{ .Values.controller.containerName }}
{{- with .Values.controller.image }}
image: "{{- if .repository -}}{{ .repository }}{{ else }}{{ .registry }}/{{ .image }}{{- end -}}:{{ .tag }}{{- if (.digest) -}} @{{.digest}} {{- end -}}"
image: "{{- if .repository -}}{{ .repository }}{{ else }}{{ .registry }}/{{ include "ingress-nginx.image" . }}{{- end -}}:{{ .tag }}{{ include "ingress-nginx.imageDigest" . }}"
{{- end }}
imagePullPolicy: {{ .Values.controller.image.pullPolicy }}
{{- if .Values.controller.lifecycle }}
@ -125,7 +128,7 @@ spec:
protocol: TCP
{{- end }}
{{- range $key, $value := .Values.tcp }}
- name: {{ $key }}-tcp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-tcp
containerPort: {{ $key }}
protocol: TCP
{{- if $.Values.controller.hostPort.enabled }}
@ -133,7 +136,7 @@ spec:
{{- end }}
{{- end }}
{{- range $key, $value := .Values.udp }}
- name: {{ $key }}-udp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-udp
containerPort: {{ $key }}
protocol: UDP
{{- if $.Values.controller.hostPort.enabled }}

View file

@ -1,4 +1,4 @@
{{- if and .Values.controller.metrics.enabled .Values.controller.metrics.prometheusRule.enabled -}}
{{- if and ( .Values.controller.metrics.enabled ) ( .Values.controller.metrics.prometheusRule.enabled ) ( .Capabilities.APIVersions.Has "monitoring.coreos.com/v1" ) -}}
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:

View file

@ -12,6 +12,9 @@ metadata:
spec:
allowedCapabilities:
- NET_BIND_SERVICE
{{- if .Values.controller.image.chroot }}
- SYS_CHROOT
{{- end }}
{{- if .Values.controller.sysctls }}
allowedUnsafeSysctls:
{{- range $sysctl, $value := .Values.controller.sysctls }}

View file

@ -73,6 +73,21 @@ rules:
- configmaps
verbs:
- create
- apiGroups:
- coordination.k8s.io
resources:
- leases
resourceNames:
- {{ .Values.controller.electionID }}
verbs:
- get
- update
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- create
- apiGroups:
- ""
resources:

View file

@ -52,10 +52,10 @@ spec:
{{- end }}
{{- end }}
{{- range $key, $value := .Values.tcp }}
- name: {{ $key }}-tcp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-tcp
port: {{ $key }}
protocol: TCP
targetPort: {{ $key }}-tcp
targetPort: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-tcp
{{- if $.Values.controller.service.nodePorts.tcp }}
{{- if index $.Values.controller.service.nodePorts.tcp $key }}
nodePort: {{ index $.Values.controller.service.nodePorts.tcp $key }}
@ -63,10 +63,10 @@ spec:
{{- end }}
{{- end }}
{{- range $key, $value := .Values.udp }}
- name: {{ $key }}-udp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-udp
port: {{ $key }}
protocol: UDP
targetPort: {{ $key }}-udp
targetPort: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-udp
{{- if $.Values.controller.service.nodePorts.udp }}
{{- if index $.Values.controller.service.nodePorts.udp $key }}
nodePort: {{ index $.Values.controller.service.nodePorts.udp $key }}

View file

@ -37,12 +37,12 @@ spec:
{{- if .Values.controller.service.healthCheckNodePort }}
healthCheckNodePort: {{ .Values.controller.service.healthCheckNodePort }}
{{- end }}
{{- if semverCompare ">=1.20.0-0" .Capabilities.KubeVersion.Version -}}
{{- if semverCompare ">=1.21.0-0" .Capabilities.KubeVersion.Version -}}
{{- if .Values.controller.service.ipFamilyPolicy }}
ipFamilyPolicy: {{ .Values.controller.service.ipFamilyPolicy }}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.20.0-0" .Capabilities.KubeVersion.Version -}}
{{- if semverCompare ">=1.21.0-0" .Capabilities.KubeVersion.Version -}}
{{- if .Values.controller.service.ipFamilies }}
ipFamilies: {{ toYaml .Values.controller.service.ipFamilies | nindent 4 }}
{{- end }}
@ -74,10 +74,10 @@ spec:
{{- end }}
{{- end }}
{{- range $key, $value := .Values.tcp }}
- name: {{ $key }}-tcp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-tcp
port: {{ $key }}
protocol: TCP
targetPort: {{ $key }}-tcp
targetPort: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-tcp
{{- if $.Values.controller.service.nodePorts.tcp }}
{{- if index $.Values.controller.service.nodePorts.tcp $key }}
nodePort: {{ index $.Values.controller.service.nodePorts.tcp $key }}
@ -85,10 +85,10 @@ spec:
{{- end }}
{{- end }}
{{- range $key, $value := .Values.udp }}
- name: {{ $key }}-udp
- name: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-udp
port: {{ $key }}
protocol: UDP
targetPort: {{ $key }}-udp
targetPort: {{ if $.Values.portNamePrefix }}{{ $.Values.portNamePrefix }}-{{ end }}{{ $key }}-udp
{{- if $.Values.controller.service.nodePorts.udp }}
{{- if index $.Values.controller.service.nodePorts.udp $key }}
nodePort: {{ index $.Values.controller.service.nodePorts.udp $key }}

View file

@ -16,13 +16,16 @@ commonLabels: {}
controller:
name: controller
image:
registry: k8s.gcr.io
## Keep false as default for now!
chroot: false
registry: registry.k8s.io
image: ingress-nginx/controller
## for backwards compatibility consider setting the full image url via the repository value below
## use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
## repository:
tag: "v1.1.2"
digest: sha256:28b11ce69e57843de44e3db6413e98d09de0f6688e33d4bd384002a44f78405c
tag: "v1.3.0"
digest: sha256:d1707ca76d3b044ab8a28277a2466a02100ee9f58a86af1535a3edf9323ea1b5
digestChroot: sha256:0fcb91216a22aae43b374fc2e6a03b8afe9e8c78cbf07a09d75636dc4ea3c191
pullPolicy: IfNotPresent
# www-data -> uid 101
runAsUser: 101
@ -272,7 +275,7 @@ controller:
##
topologySpreadConstraints: []
# - maxSkew: 1
# topologyKey: failure-domain.beta.kubernetes.io/zone
# topologyKey: topology.kubernetes.io/zone
# whenUnsatisfiable: DoNotSchedule
# labelSelector:
# matchLabels:
@ -457,7 +460,8 @@ controller:
##
externalIPs: []
# loadBalancerIP: ""
# -- Used by cloud providers to connect the resulting `LoadBalancer` to a pre-existing static IP according to https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer
loadBalancerIP: ""
loadBalancerSourceRanges: []
enableHttp: true
@ -529,6 +533,10 @@ controller:
## Ref: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancer
# externalTrafficPolicy: ""
# shareProcessNamespace enables process namespace sharing within the pod.
# This can be used for example to signal log rotation using `kill -USR1` from a sidecar.
shareProcessNamespace: false
# -- Additional containers to be added to the controller pod.
# See https://github.com/lemonldap-ng-controller/lemonldap-ng-controller as example.
extraContainers: []
@ -572,7 +580,7 @@ controller:
extraModules: []
## Modules, which are mounted into the core nginx image
# - name: opentelemetry
# image: busybox
# image: registry.k8s.io/ingress-nginx/opentelemetry:v20220415-controller-v1.2.0-beta.0-2-g81c2afd97@sha256:ce61e2cf0b347dffebb2dcbf57c33891d2217c1bad9c0959c878e5be671ef941
#
# The image must contain a `/usr/local/bin/init_module.sh` executable, which
# will be executed as initContainers, to move its config files within the
@ -586,6 +594,15 @@ controller:
## These annotations will be added to the ValidatingWebhookConfiguration and
## the Jobs Spec of the admission webhooks.
enabled: true
# -- Additional environment variables to set
extraEnvs: []
# extraEnvs:
# - name: FOO
# valueFrom:
# secretKeyRef:
# key: FOO
# name: secret-resource
# -- Admission Webhook failure policy to use
failurePolicy: Fail
# timeoutSeconds: 10
port: 8443
@ -623,7 +640,7 @@ controller:
patch:
enabled: true
image:
registry: k8s.gcr.io
registry: registry.k8s.io
image: ingress-nginx/kube-webhook-certgen
## for backwards compatibility consider setting the full image url via the repository value below
## use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
@ -750,7 +767,7 @@ defaultBackend:
name: defaultbackend
image:
registry: k8s.gcr.io
registry: registry.k8s.io
image: defaultbackend-amd64
## for backwards compatibility consider setting the full image url via the repository value below
## use *either* current default registry/image or repository format or installing chart by providing the values.yaml will fail
@ -901,18 +918,22 @@ serviceAccount:
imagePullSecrets: []
# - name: secretName
# -- TCP service key:value pairs
# -- TCP service key-value pairs
## Ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/exposing-tcp-udp-services.md
##
tcp: {}
# 8080: "default/example-tcp-svc:9000"
# -- UDP service key:value pairs
# -- UDP service key-value pairs
## Ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/exposing-tcp-udp-services.md
##
udp: {}
# 53: "kube-system/kube-dns:53"
# -- Prefix for TCP and UDP ports names in ingress controller service
## Some cloud providers, like Yandex Cloud may have a requirements for a port name regex to support cloud load balancer integration
portNamePrefix: ""
# -- (string) A base64-encoded Diffie-Hellman parameter.
# This can be generated with: `openssl dhparam 4096 2> /dev/null | base64`
## Ref: https://github.com/kubernetes/ingress-nginx/tree/main/docs/examples/customization/ssl-dh-param

25
tracker/.husky/pre-commit Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
if git diff --cached --name-only | grep --quiet '^tracker/tracker/'
then
echo "tracker"
pwd
cd tracker/tracker
npm run lint-front
cd ../../
fi
if git diff --cached --name-only | grep --quiet '^tracker/tracker-assist/'
then
echo "tracker-assist"
cd tracker/tracker-assist
npm run lint-front
cd ../../
fi
exit 0

View file

@ -0,0 +1,8 @@
node_modules
npm-debug.log
lib
cjs
build
.cache
.eslintrc.cjs
src/common/messages.ts

View file

@ -0,0 +1,49 @@
/* eslint-disable */
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./tsconfig.json'],
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint', 'prettier'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'prettier',
],
rules: {
'no-empty': [
'error',
{
allowEmptyCatch: true,
},
],
'@typescript-eslint/camelcase': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/explicit-function-return-type': 'warn',
'@typescript-eslint/prefer-readonly': 'warn',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-unsafe-assignment': 'off',
'@typescript-eslint/no-unsafe-member-access': 'off',
'@typescript-eslint/no-unsafe-call': 'off',
'@typescript-eslint/restrict-plus-operands': 'warn',
'@typescript-eslint/no-unsafe-return': 'warn',
'no-useless-escape': 'warn',
'no-control-regex': 'warn',
'@typescript-eslint/restrict-template-expressions': 'warn',
'@typescript-eslint/no-useless-constructor': 'warn',
'@typescript-eslint/no-this-alias': 'off',
'@typescript-eslint/no-floating-promises': 'warn',
'@typescript-eslint/no-unsafe-argument': 'warn',
'no-unused-expressions': 'off',
'@typescript-eslint/no-unused-expressions': 'warn',
'@typescript-eslint/no-useless-constructor': 'warn',
'semi': ["error", "never"],
'quotes': ["error", "single"],
'comma-dangle': ["error", "always"]
},
};

Some files were not shown because too many files have changed in this diff Show more