diff --git a/api/chalicelib/core/metrics/custom_metrics.py b/api/chalicelib/core/metrics/custom_metrics.py index f5255017f..2eea08b46 100644 --- a/api/chalicelib/core/metrics/custom_metrics.py +++ b/api/chalicelib/core/metrics/custom_metrics.py @@ -55,8 +55,8 @@ def __get_sessions_list(project: schemas.ProjectContext, user_id, data: schemas. return sessions_search.search_sessions(data=data.series[0].filter, project=project, user_id=user_id) -def __get_heat_map_chart(project: schemas.ProjectContext, user_id, data: schemas.CardHeatMap, - include_mobs: bool = True): +def get_heat_map_chart(project: schemas.ProjectContext, user_id, data: schemas.CardHeatMap, + include_mobs: bool = True): if len(data.series) == 0: return None data.series[0].filter.filters += data.series[0].filter.events @@ -156,7 +156,7 @@ def get_chart(project: schemas.ProjectContext, data: schemas.CardSchema, user_id supported = { schemas.MetricType.TIMESERIES: __get_timeseries_chart, schemas.MetricType.TABLE: __get_table_chart, - schemas.MetricType.HEAT_MAP: __get_heat_map_chart, + schemas.MetricType.HEAT_MAP: get_heat_map_chart, schemas.MetricType.FUNNEL: __get_funnel_chart, schemas.MetricType.PATH_ANALYSIS: __get_path_analysis_chart } @@ -201,12 +201,12 @@ def get_issues(project: schemas.ProjectContext, user_id: int, data: schemas.Card return supported.get(data.metric_type, not_supported)() -def __get_global_card_info(data: schemas.CardSchema): +def get_global_card_info(data: schemas.CardSchema): r = {"hideExcess": data.hide_excess, "compareTo": data.compare_to, "rows": data.rows} return r -def __get_path_analysis_card_info(data: schemas.CardPathAnalysis): +def get_path_analysis_card_info(data: schemas.CardPathAnalysis): r = {"start_point": [s.model_dump() for s in data.start_point], "start_type": data.start_type, "excludes": [e.model_dump() for e in data.excludes], @@ -221,8 +221,8 @@ def create_card(project: schemas.ProjectContext, user_id, data: schemas.CardSche if data.session_id is not None: session_data = {"sessionId": data.session_id} else: - session_data = __get_heat_map_chart(project=project, user_id=user_id, - data=data, include_mobs=False) + session_data = get_heat_map_chart(project=project, user_id=user_id, + data=data, include_mobs=False) if session_data is not None: session_data = {"sessionId": session_data["sessionId"]} @@ -235,9 +235,9 @@ def create_card(project: schemas.ProjectContext, user_id, data: schemas.CardSche series_len = len(data.series) params = {"user_id": user_id, "project_id": project.project_id, **data.model_dump(), **_data, "default_config": json.dumps(data.default_config.model_dump()), "card_info": None} - params["card_info"] = __get_global_card_info(data=data) + params["card_info"] = get_global_card_info(data=data) if data.metric_type == schemas.MetricType.PATH_ANALYSIS: - params["card_info"] = {**params["card_info"], **__get_path_analysis_card_info(data=data)} + params["card_info"] = {**params["card_info"], **get_path_analysis_card_info(data=data)} params["card_info"] = json.dumps(params["card_info"]) query = """INSERT INTO metrics (project_id, user_id, name, is_public, @@ -299,9 +299,9 @@ def update_card(metric_id, user_id, project_id, data: schemas.CardSchema): d_series_ids.append(i) params["d_series_ids"] = tuple(d_series_ids) params["session_data"] = json.dumps(metric["data"]) - params["card_info"] = __get_global_card_info(data=data) + params["card_info"] = get_global_card_info(data=data) if data.metric_type == schemas.MetricType.PATH_ANALYSIS: - params["card_info"] = {**params["card_info"], **__get_path_analysis_card_info(data=data)} + params["card_info"] = {**params["card_info"], **get_path_analysis_card_info(data=data)} elif data.metric_type == schemas.MetricType.HEAT_MAP: if data.session_id is not None: params["session_data"] = json.dumps({"sessionId": data.session_id}) diff --git a/api/chalicelib/core/metrics/heatmaps_ch.py b/api/chalicelib/core/metrics/heatmaps_ch.py index 3b78ef551..93afb78cc 100644 --- a/api/chalicelib/core/metrics/heatmaps_ch.py +++ b/api/chalicelib/core/metrics/heatmaps_ch.py @@ -149,7 +149,7 @@ def get_selectors_by_url_and_session_id(project_id, session_id, data: schemas.Ge query_from = f"{exp_ch_helper.get_main_events_table(0)} AS main_events" with ch_client.ClickHouseClient() as cur: - query = cur.format(query=f"""SELECT main_events.selector AS selector, + query = cur.format(query=f"""SELECT CAST(`$properties`.selector AS String) AS selector, COUNT(1) AS count FROM {query_from} WHERE {" AND ".join(constraints)} diff --git a/api/chalicelib/core/metrics/modules/significance/significance_ch.py b/api/chalicelib/core/metrics/modules/significance/significance_ch.py index f309841c0..c547f9a6b 100644 --- a/api/chalicelib/core/metrics/modules/significance/significance_ch.py +++ b/api/chalicelib/core/metrics/modules/significance/significance_ch.py @@ -175,7 +175,7 @@ def get_simple_funnel(filter_d: schemas.CardSeriesFilterSchema, project: schemas value_key=e_k ) if not specific_condition else specific_condition) - full_args = {"eventTypes": tuple(event_types), **full_args, **values} + full_args = {"eventTypes": event_types, **full_args, **values} n_stages = len(n_stages_query) if n_stages == 0: return [] diff --git a/api/chalicelib/core/sessions/sessions_ch.py b/api/chalicelib/core/sessions/sessions_ch.py index 4ebc8723d..d6de1f6cf 100644 --- a/api/chalicelib/core/sessions/sessions_ch.py +++ b/api/chalicelib/core/sessions/sessions_ch.py @@ -381,7 +381,7 @@ def search_query_parts_ch(data: schemas.SessionsSearchPayloadSchema, error_statu filter_type = f.type f.value = helper.values_for_operator(value=f.value, op=f.operator) f_k = f"f_value{i}" - full_args = {**full_args, f_k: f.value, **sh.multi_values(f.value, value_key=f_k)} + full_args = {**full_args, f_k: sh.single_value(f.value), **sh.multi_values(f.value, value_key=f_k)} op = sh.get_sql_operator(f.operator) \ if filter_type not in [schemas.FilterType.EVENTS_COUNT] else f.operator.value is_any = sh.isAny_opreator(f.operator) diff --git a/api/chalicelib/utils/sql_helper.py b/api/chalicelib/utils/sql_helper.py index 23c0078c4..1de16c70f 100644 --- a/api/chalicelib/utils/sql_helper.py +++ b/api/chalicelib/utils/sql_helper.py @@ -64,3 +64,12 @@ def isAny_opreator(op: schemas.SearchEventOperator): def isUndefined_operator(op: schemas.SearchEventOperator): return op in [schemas.SearchEventOperator.IS_UNDEFINED] + + +def single_value(values): + if values is not None and isinstance(values, list): + for i, v in enumerate(values): + if isinstance(v, Enum): + values[i] = v.value + return values + diff --git a/api/schemas/transformers_validators.py b/api/schemas/transformers_validators.py index e50371aa4..106f8747c 100644 --- a/api/schemas/transformers_validators.py +++ b/api/schemas/transformers_validators.py @@ -38,6 +38,9 @@ def force_is_event(events_enum: list[Type[Enum]]): def fn(value: list): if value is not None and isinstance(value, list): for v in value: + if v.get("type") is None: + v["isEvent"] = False + continue r = False for en in events_enum: if en.has_value(v["type"]) or en.has_value(v["type"].lower()): diff --git a/backend/pkg/messages/filters.go b/backend/pkg/messages/filters.go index f74dbc124..094586abf 100644 --- a/backend/pkg/messages/filters.go +++ b/backend/pkg/messages/filters.go @@ -10,5 +10,5 @@ func IsMobileType(id int) bool { } func IsDOMType(id int) bool { - return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id + return 0 == id || 4 == id || 5 == id || 6 == id || 7 == id || 8 == id || 9 == id || 10 == id || 11 == id || 12 == id || 13 == id || 14 == id || 15 == id || 16 == id || 18 == id || 19 == id || 20 == id || 34 == id || 35 == id || 37 == id || 38 == id || 49 == id || 50 == id || 51 == id || 43 == id || 52 == id || 54 == id || 55 == id || 57 == id || 58 == id || 59 == id || 60 == id || 61 == id || 67 == id || 68 == id || 69 == id || 70 == id || 71 == id || 72 == id || 73 == id || 74 == id || 75 == id || 76 == id || 77 == id || 113 == id || 114 == id || 117 == id || 118 == id || 119 == id || 122 == id || 93 == id || 96 == id || 100 == id || 101 == id || 102 == id || 103 == id || 104 == id || 105 == id || 106 == id || 111 == id } diff --git a/backend/pkg/messages/messages.go b/backend/pkg/messages/messages.go index 37f32b8a0..d4f184d48 100644 --- a/backend/pkg/messages/messages.go +++ b/backend/pkg/messages/messages.go @@ -35,6 +35,8 @@ const ( MsgPageEventDeprecated = 31 MsgInputEvent = 32 MsgPageEvent = 33 + MsgStringDictGlobal = 34 + MsgSetNodeAttributeDictGlobal = 35 MsgCSSInsertRule = 37 MsgCSSDeleteRule = 38 MsgFetch = 39 @@ -1015,6 +1017,54 @@ func (msg *PageEvent) TypeID() int { return 33 } +type StringDictGlobal struct { + message + Key uint64 + Value string +} + +func (msg *StringDictGlobal) Encode() []byte { + buf := make([]byte, 21+len(msg.Value)) + buf[0] = 34 + p := 1 + p = WriteUint(msg.Key, buf, p) + p = WriteString(msg.Value, buf, p) + return buf[:p] +} + +func (msg *StringDictGlobal) Decode() Message { + return msg +} + +func (msg *StringDictGlobal) TypeID() int { + return 34 +} + +type SetNodeAttributeDictGlobal struct { + message + ID uint64 + Name uint64 + Value uint64 +} + +func (msg *SetNodeAttributeDictGlobal) Encode() []byte { + buf := make([]byte, 31) + buf[0] = 35 + p := 1 + p = WriteUint(msg.ID, buf, p) + p = WriteUint(msg.Name, buf, p) + p = WriteUint(msg.Value, buf, p) + return buf[:p] +} + +func (msg *SetNodeAttributeDictGlobal) Decode() Message { + return msg +} + +func (msg *SetNodeAttributeDictGlobal) TypeID() int { + return 35 +} + type CSSInsertRule struct { message ID uint64 diff --git a/backend/pkg/messages/read-message.go b/backend/pkg/messages/read-message.go index 37920bfa0..f0051a042 100644 --- a/backend/pkg/messages/read-message.go +++ b/backend/pkg/messages/read-message.go @@ -606,6 +606,33 @@ func DecodePageEvent(reader BytesReader) (Message, error) { return msg, err } +func DecodeStringDictGlobal(reader BytesReader) (Message, error) { + var err error = nil + msg := &StringDictGlobal{} + if msg.Key, err = reader.ReadUint(); err != nil { + return nil, err + } + if msg.Value, err = reader.ReadString(); err != nil { + return nil, err + } + return msg, err +} + +func DecodeSetNodeAttributeDictGlobal(reader BytesReader) (Message, error) { + var err error = nil + msg := &SetNodeAttributeDictGlobal{} + if msg.ID, err = reader.ReadUint(); err != nil { + return nil, err + } + if msg.Name, err = reader.ReadUint(); err != nil { + return nil, err + } + if msg.Value, err = reader.ReadUint(); err != nil { + return nil, err + } + return msg, err +} + func DecodeCSSInsertRule(reader BytesReader) (Message, error) { var err error = nil msg := &CSSInsertRule{} @@ -2123,6 +2150,10 @@ func ReadMessage(t uint64, reader BytesReader) (Message, error) { return DecodeInputEvent(reader) case 33: return DecodePageEvent(reader) + case 34: + return DecodeStringDictGlobal(reader) + case 35: + return DecodeSetNodeAttributeDictGlobal(reader) case 37: return DecodeCSSInsertRule(reader) case 38: diff --git a/ee/api/.gitignore b/ee/api/.gitignore index ae8b4fca0..1df9cf0e0 100644 --- a/ee/api/.gitignore +++ b/ee/api/.gitignore @@ -222,7 +222,7 @@ Pipfile.lock /chalicelib/core/sessions/performance_event.py /chalicelib/core/sessions/sessions_viewed.py /chalicelib/core/sessions/unprocessed_sessions.py -/chalicelib/core/significance.py +/chalicelib/core/metrics/modules /chalicelib/core/socket_ios.py /chalicelib/core/sourcemaps.py /chalicelib/core/sourcemaps_parser.py diff --git a/ee/api/chalicelib/core/autocomplete/autocomplete_ch.py b/ee/api/chalicelib/core/autocomplete/autocomplete_ch.py index a3ad1d836..a779ec602 100644 --- a/ee/api/chalicelib/core/autocomplete/autocomplete_ch.py +++ b/ee/api/chalicelib/core/autocomplete/autocomplete_ch.py @@ -266,16 +266,16 @@ def __search_metadata(project_id, value, key=None, source=None): TYPE_TO_COLUMN = { - schemas.EventType.CLICK: "label", - schemas.EventType.INPUT: "label", - schemas.EventType.LOCATION: "url_path", - schemas.EventType.CUSTOM: "name", - schemas.FetchFilterType.FETCH_URL: "url_path", - schemas.GraphqlFilterType.GRAPHQL_NAME: "name", - schemas.EventType.STATE_ACTION: "name", + schemas.EventType.CLICK: "`$properties`.label", + schemas.EventType.INPUT: "`$properties`.label", + schemas.EventType.LOCATION: "`$properties`.url_path", + schemas.EventType.CUSTOM: "`$properties`.name", + schemas.FetchFilterType.FETCH_URL: "`$properties`.url_path", + schemas.GraphqlFilterType.GRAPHQL_NAME: "`$properties`.name", + schemas.EventType.STATE_ACTION: "`$properties`.name", # For ERROR, sessions search is happening over name OR message, # for simplicity top 10 is using name only - schemas.EventType.ERROR: "name", + schemas.EventType.ERROR: "`$properties`.name", schemas.FilterType.USER_COUNTRY: "user_country", schemas.FilterType.USER_CITY: "user_city", schemas.FilterType.USER_STATE: "user_state", @@ -325,9 +325,9 @@ def get_top_values(project_id, event_type, event_key=None): query = f"""WITH raw AS (SELECT DISTINCT {colname} AS c_value, COUNT(1) OVER (PARTITION BY c_value) AS row_count, COUNT(1) OVER () AS total_count - FROM experimental.events + FROM product_analytics.events WHERE project_id = %(project_id)s - AND event_type = '{event_type}' + AND `$event_name` = '{event_type}' AND isNotNull(c_value) AND notEmpty(c_value) ORDER BY row_count DESC diff --git a/ee/api/chalicelib/core/metrics/custom_metrics_ee.py b/ee/api/chalicelib/core/metrics/custom_metrics_ee.py index a450fd736..ca9cfd04f 100644 --- a/ee/api/chalicelib/core/metrics/custom_metrics_ee.py +++ b/ee/api/chalicelib/core/metrics/custom_metrics_ee.py @@ -1,9 +1,7 @@ -import json -import logging - from decouple import config -from chalicelib.utils.storage import extra + from chalicelib.core.sessions import sessions_mobs, sessions_favorite +from chalicelib.utils.storage import extra from .custom_metrics import * @@ -14,8 +12,8 @@ def create_card(project: schemas.ProjectContext, user_id, data: schemas.CardSche if data.session_id is not None: session_data = {"sessionId": data.session_id} else: - session_data = __get_heat_map_chart(project=project, user_id=user_id, - data=data, include_mobs=False) + session_data = get_heat_map_chart(project=project, user_id=user_id, + data=data, include_mobs=False) if session_data is not None: session_data = {"sessionId": session_data["sessionId"]} @@ -42,8 +40,10 @@ def create_card(project: schemas.ProjectContext, user_id, data: schemas.CardSche series_len = len(data.series) params = {"user_id": user_id, "project_id": project.project_id, **data.model_dump(), **_data, "default_config": json.dumps(data.default_config.model_dump()), "card_info": None} + params["card_info"] = get_global_card_info(data=data) if data.metric_type == schemas.MetricType.PATH_ANALYSIS: - params["card_info"] = json.dumps(__get_path_analysis_card_info(data=data)) + params["card_info"] = {**params["card_info"], **get_path_analysis_card_info(data=data)} + params["card_info"] = json.dumps(params["card_info"]) query = """INSERT INTO metrics (project_id, user_id, name, is_public, view_type, metric_type, metric_of, metric_value, diff --git a/ee/api/chalicelib/utils/exp_ch_helper.py b/ee/api/chalicelib/utils/exp_ch_helper.py index 282351908..1e19bed2c 100644 --- a/ee/api/chalicelib/utils/exp_ch_helper.py +++ b/ee/api/chalicelib/utils/exp_ch_helper.py @@ -13,9 +13,10 @@ if config("EXP_7D_MV", cast=bool, default=True): def get_main_events_table(timestamp=0, platform="web"): if platform == "web": - return "experimental.events_l7d_mv" \ - if config("EXP_7D_MV", cast=bool, default=True) \ - and timestamp and timestamp >= TimeUTC.now(delta_days=-7) else "experimental.events" + return "product_analytics.events" + # return "experimental.events_l7d_mv" \ + # if config("EXP_7D_MV", cast=bool, default=True) \ + # and timestamp and timestamp >= TimeUTC.now(delta_days=-7) else "experimental.events" else: return "experimental.ios_events" diff --git a/ee/api/clean-dev.sh b/ee/api/clean-dev.sh index ba6628328..e1c4b83cc 100755 --- a/ee/api/clean-dev.sh +++ b/ee/api/clean-dev.sh @@ -43,7 +43,7 @@ rm -rf ./chalicelib/core/sessions/sessions_search.py rm -rf ./chalicelib/core/sessions/performance_event.py rm -rf ./chalicelib/core/sessions/sessions_viewed.py rm -rf ./chalicelib/core/sessions/unprocessed_sessions.py -rm -rf ./chalicelib/core/significance.py +rm -rf ./chalicelib/core/metrics/modules rm -rf ./chalicelib/core/socket_ios.py rm -rf ./chalicelib/core/sourcemaps.py rm -rf ./chalicelib/core/sourcemaps_parser.py diff --git a/ee/api/routers/subs/metrics.py b/ee/api/routers/subs/metrics.py index 2cf14c885..bbeeaadc1 100644 --- a/ee/api/routers/subs/metrics.py +++ b/ee/api/routers/subs/metrics.py @@ -1,7 +1,7 @@ from typing import Union import schemas -from chalicelib.core.metrics import dashboards, custom_metrics +from chalicelib.core.metrics import custom_metrics, dashboards from fastapi import Body, Depends from or_dependencies import OR_context, OR_scope from routers.base import get_routers @@ -87,7 +87,7 @@ def try_card(projectId: int, data: schemas.CardSchema = Body(...), @app.post('/{projectId}/cards/try/sessions', tags=["cards"]) def try_card_sessions(projectId: int, data: schemas.CardSessionsSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - data = custom_metrics.get_sessions(project_id=projectId, user_id=context.user_id, data=data) + data = custom_metrics.get_sessions(project=context.project, user_id=context.user_id, data=data) return {"data": data} @@ -130,7 +130,7 @@ def get_card(projectId: int, metric_id: Union[int, str], context: schemas.Curren def get_card_sessions(projectId: int, metric_id: int, data: schemas.CardSessionsSchema = Body(...), context: schemas.CurrentContext = Depends(OR_context)): - data = custom_metrics.get_sessions_by_card_id(project_id=projectId, user_id=context.user_id, metric_id=metric_id, + data = custom_metrics.get_sessions_by_card_id(project=context.project, user_id=context.user_id, metric_id=metric_id, data=data) if data is None: return {"errors": ["custom metric not found"]} diff --git a/ee/scripts/schema/db/init_dbs/clickhouse/1.22.0/1.22.0.sql b/ee/scripts/schema/db/init_dbs/clickhouse/1.22.0/1.22.0.sql index 67231a79f..27aadcf39 100644 --- a/ee/scripts/schema/db/init_dbs/clickhouse/1.22.0/1.22.0.sql +++ b/ee/scripts/schema/db/init_dbs/clickhouse/1.22.0/1.22.0.sql @@ -334,3 +334,6 @@ CREATE TABLE IF NOT EXISTS product_analytics.all_properties _timestamp DateTime DEFAULT now() ) ENGINE = ReplacingMergeTree(_timestamp) ORDER BY (project_id, property_name, is_event_property); + + +DROP TABLE IF EXISTS experimental.events_l7d_mv; \ No newline at end of file diff --git a/ee/scripts/schema/db/init_dbs/clickhouse/create/init_schema.sql b/ee/scripts/schema/db/init_dbs/clickhouse/create/init_schema.sql index 413595d79..1fd1a79e7 100644 --- a/ee/scripts/schema/db/init_dbs/clickhouse/create/init_schema.sql +++ b/ee/scripts/schema/db/init_dbs/clickhouse/create/init_schema.sql @@ -191,78 +191,6 @@ CREATE TABLE IF NOT EXISTS experimental.issues ORDER BY (project_id, issue_id, type) TTL _timestamp + INTERVAL 3 MONTH; -CREATE MATERIALIZED VIEW IF NOT EXISTS experimental.events_l7d_mv - ENGINE = ReplacingMergeTree(_timestamp) - PARTITION BY toYYYYMMDD(datetime) - ORDER BY (project_id, datetime, event_type, session_id, message_id) - TTL datetime + INTERVAL 7 DAY - POPULATE -AS -SELECT session_id, - project_id, - event_type, - datetime, - label, - hesitation_time, - name, - payload, - level, - source, - message, - error_id, - duration, - context, - url, - url_host, - url_path, - url_hostpath, - 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_time, - speed_index, - visually_complete, - time_to_interactive, - ttfb, - ttlb, - response_time, - dom_building_time, - dom_content_loaded_event_time, - load_event_time, - 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, - method, - status, - success, - request_body, - response_body, - issue_type, - issue_id, - error_tags_keys, - error_tags_values, - transfer_size, - selector, - normalized_x, - normalized_y, - message_id, - _timestamp -FROM experimental.events -WHERE datetime >= now() - INTERVAL 7 DAY; CREATE MATERIALIZED VIEW IF NOT EXISTS experimental.sessions_l7d_mv diff --git a/ee/scripts/schema/db/rollback_dbs/clickhouse/1.22.0/1.22.0.sql b/ee/scripts/schema/db/rollback_dbs/clickhouse/1.22.0/1.22.0.sql index c60511f00..5c7f64a56 100644 --- a/ee/scripts/schema/db/rollback_dbs/clickhouse/1.22.0/1.22.0.sql +++ b/ee/scripts/schema/db/rollback_dbs/clickhouse/1.22.0/1.22.0.sql @@ -1 +1,75 @@ CREATE OR REPLACE FUNCTION openreplay_version AS() -> 'v1.21.0-ee'; + + +CREATE MATERIALIZED VIEW IF NOT EXISTS experimental.events_l7d_mv + ENGINE = ReplacingMergeTree(_timestamp) + PARTITION BY toYYYYMMDD(datetime) + ORDER BY (project_id, datetime, event_type, session_id, message_id) + TTL datetime + INTERVAL 7 DAY + POPULATE +AS +SELECT session_id, + project_id, + event_type, + datetime, + label, + hesitation_time, + name, + payload, + level, + source, + message, + error_id, + duration, + context, + url, + url_host, + url_path, + url_hostpath, + 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_time, + speed_index, + visually_complete, + time_to_interactive, + ttfb, + ttlb, + response_time, + dom_building_time, + dom_content_loaded_event_time, + load_event_time, + 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, + method, + status, + success, + request_body, + response_body, + issue_type, + issue_id, + error_tags_keys, + error_tags_values, + transfer_size, + selector, + normalized_x, + normalized_y, + message_id, + _timestamp +FROM experimental.events +WHERE datetime >= now() - INTERVAL 7 DAY; \ No newline at end of file diff --git a/frontend/app/PrivateRoutes.tsx b/frontend/app/PrivateRoutes.tsx index 5ddcf8ee4..b9d2cb247 100644 --- a/frontend/app/PrivateRoutes.tsx +++ b/frontend/app/PrivateRoutes.tsx @@ -18,11 +18,6 @@ const components: any = { AssistPure: lazy(() => import('Components/Assist/AssistRouter')), SessionsOverviewPure: lazy(() => import('Components/Overview')), DashboardPure: lazy(() => import('Components/Dashboard/NewDashboard')), - FunnelDetailsPure: lazy(() => import('Components/Funnels/FunnelDetails')), - FunnelIssueDetails: lazy( - () => import('Components/Funnels/FunnelIssueDetails') - ), - FunnelPagePure: lazy(() => import('Components/Funnels/FunnelPage')), MultiviewPure: lazy(() => import('Components/Session_/Multiview/Multiview')), UsabilityTestingPure: lazy( () => import('Components/UsabilityTesting/UsabilityTesting') @@ -47,9 +42,6 @@ const enhancedComponents: any = { Assist: withSiteIdUpdater(components.AssistPure), Client: withSiteIdUpdater(components.ClientPure), Onboarding: withSiteIdUpdater(components.OnboardingPure), - FunnelPage: withSiteIdUpdater(components.FunnelPagePure), - FunnelsDetails: withSiteIdUpdater(components.FunnelDetailsPure), - FunnelIssue: withSiteIdUpdater(components.FunnelIssueDetails), Multiview: withSiteIdUpdater(components.MultiviewPure), UsabilityTesting: withSiteIdUpdater(components.UsabilityTestingPure), UsabilityTestEdit: withSiteIdUpdater(components.UsabilityTestEditPure), @@ -85,9 +77,6 @@ const FFLAG_READ_PATH = routes.fflagRead(); const NOTES_PATH = routes.notes(); const BOOKMARKS_PATH = routes.bookmarks(); const RECORDINGS_PATH = routes.recordings(); -const FUNNEL_PATH = routes.funnels(); -const FUNNEL_CREATE_PATH = routes.funnelsCreate(); -const FUNNEL_ISSUE_PATH = routes.funnelIssue(); const SESSION_PATH = routes.session(); const CLIENT_PATH = routes.client(); const ONBOARDING_PATH = routes.onboarding(); @@ -246,24 +235,6 @@ function PrivateRoutes() { path={withSiteId(HIGHLIGHTS_PATH, siteIdList)} component={enhancedComponents.Highlights} /> - - - - {isEnterprise && modules.includes(MODULES.OFFLINE_RECORDINGS) - ? : null + {isEnterprise && !modules.includes(MODULES.OFFLINE_RECORDINGS) + ? : null } - {isEnterprise && ( - )} - + + + ); } diff --git a/frontend/app/components/Assist/ChatControls/ChatControls.tsx b/frontend/app/components/Assist/ChatControls/ChatControls.tsx index 959842961..610af6a37 100644 --- a/frontend/app/components/Assist/ChatControls/ChatControls.tsx +++ b/frontend/app/components/Assist/ChatControls/ChatControls.tsx @@ -1,10 +1,10 @@ import React, { useState } from 'react' import stl from './ChatControls.module.css' import cn from 'classnames' -import { Button, Icon } from 'UI' +import { Icon } from 'UI' +import { Button } from 'antd' import type { LocalStream } from 'Player'; - interface Props { stream: LocalStream | null, endCall: () => void, @@ -35,17 +35,15 @@ function ChatControls({ stream, endCall, videoEnabled, setVideoEnabled, isPresta return (
-
+
-
-
diff --git a/frontend/app/components/Assist/RecordingsList/EditRecordingModal.tsx b/frontend/app/components/Assist/RecordingsList/EditRecordingModal.tsx index 7be5b1dca..6c654d249 100644 --- a/frontend/app/components/Assist/RecordingsList/EditRecordingModal.tsx +++ b/frontend/app/components/Assist/RecordingsList/EditRecordingModal.tsx @@ -1,6 +1,7 @@ import { useObserver } from 'mobx-react-lite'; import React from 'react'; -import { Button, Modal, Form, Icon, Input } from 'UI'; +import { Modal, Form, Icon, Input } from 'UI'; +import { Button } from 'antd' interface Props { show: boolean; @@ -57,7 +58,7 @@ function EditRecordingModal(props: Props) {
{WIN_VARIANTS[windowType].text} -
diff --git a/frontend/app/components/Assist/components/AssistActions/AssistActions.tsx b/frontend/app/components/Assist/components/AssistActions/AssistActions.tsx index e595c9c6e..88317ac79 100644 --- a/frontend/app/components/Assist/components/AssistActions/AssistActions.tsx +++ b/frontend/app/components/Assist/components/AssistActions/AssistActions.tsx @@ -1,5 +1,5 @@ import React, { useState, useEffect } from 'react'; -import { Button, Tooltip } from 'UI'; +import { Button } from 'antd'; import cn from 'classnames'; import ChatWindow from '../../ChatWindow'; import { CallingState, ConnectionStatus, RemoteControlStatus, RequestLocalStream } from 'Player'; @@ -7,7 +7,7 @@ import type { LocalStream } from 'Player'; import { PlayerContext, ILivePlayerContext } from 'App/components/Session/playerContext'; import { observer } from 'mobx-react-lite'; import { toast } from 'react-toastify'; -import { confirm } from 'UI'; +import { confirm, Icon, Tooltip } from 'UI'; import stl from './AassistActions.module.css'; import ScreenRecorder from 'App/components/Session_/ScreenRecorder/ScreenRecorder'; import { audioContextManager } from 'App/utils/screenRecorder'; @@ -221,9 +221,10 @@ function AssistActions({ role="button" > @@ -246,8 +247,9 @@ function AssistActions({ role="button" >
diff --git a/frontend/app/components/Client/CustomFields/ListItem.js b/frontend/app/components/Client/CustomFields/ListItem.js index 9c38e12e9..00c484c6e 100644 --- a/frontend/app/components/Client/CustomFields/ListItem.js +++ b/frontend/app/components/Client/CustomFields/ListItem.js @@ -1,6 +1,7 @@ import React from 'react'; import cn from 'classnames'; -import { Button } from 'UI'; +import { Icon } from 'UI'; +import { Button } from 'antd'; import styles from './listItem.module.css'; const ListItem = ({ field, onEdit, disabled }) => { @@ -17,7 +18,7 @@ const ListItem = ({ field, onEdit, disabled }) => { > {field.key}
-
); diff --git a/frontend/app/components/Client/Integrations/IntegrationForm.tsx b/frontend/app/components/Client/Integrations/IntegrationForm.tsx index 250d5fc08..cdb589429 100644 --- a/frontend/app/components/Client/Integrations/IntegrationForm.tsx +++ b/frontend/app/components/Client/Integrations/IntegrationForm.tsx @@ -3,7 +3,8 @@ import React from 'react'; import { useStore } from 'App/mstore'; import { namedStore } from 'App/mstore/integrationsStore'; -import { Button, Checkbox, Form, Input, Loader } from 'UI'; +import { Checkbox, Form, Input, Loader } from 'UI'; +import { Button } from 'antd' import { toast } from 'react-toastify'; function IntegrationForm(props: any) { @@ -97,7 +98,7 @@ function IntegrationForm(props: any) { onClick={save} disabled={!config?.validate()} loading={loading} - variant="primary" + type="primary" className="float-left mr-2" > {config?.exists() ? 'Update' : 'Add'} diff --git a/frontend/app/components/Client/Integrations/SlackAddForm/SlackAddForm.js b/frontend/app/components/Client/Integrations/SlackAddForm/SlackAddForm.js index b8cdc1981..79feddbc3 100644 --- a/frontend/app/components/Client/Integrations/SlackAddForm/SlackAddForm.js +++ b/frontend/app/components/Client/Integrations/SlackAddForm/SlackAddForm.js @@ -1,6 +1,6 @@ import React from 'react'; -import { Form, Input, Button, Message } from 'UI'; -import { confirm } from 'UI'; +import { Form, Input, Message, confirm } from 'UI'; +import { Button } from 'antd' import { observer } from 'mobx-react-lite' import { useStore } from 'App/mstore' @@ -73,7 +73,7 @@ function SlackAddForm(props) { onClick={save} disabled={!instance.validate()} loading={saving} - variant="primary" + type="primary" className="float-left mr-2" > {instance.exists() ? 'Update' : 'Add'} diff --git a/frontend/app/components/Client/Integrations/SlackForm.tsx b/frontend/app/components/Client/Integrations/SlackForm.tsx index 43a720da4..4c7e97209 100644 --- a/frontend/app/components/Client/Integrations/SlackForm.tsx +++ b/frontend/app/components/Client/Integrations/SlackForm.tsx @@ -1,7 +1,8 @@ import React, { useEffect } from 'react'; import SlackChannelList from './SlackChannelList/SlackChannelList'; import SlackAddForm from './SlackAddForm'; -import { Button } from 'UI'; +import { Icon } from 'UI'; +import { Button } from 'antd'; import { observer } from 'mobx-react-lite' import { useStore } from 'App/mstore' @@ -34,7 +35,7 @@ const SlackForm = () => {

Slack

-
diff --git a/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx b/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx index 0f4b2fb1d..9341b08ef 100644 --- a/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx +++ b/frontend/app/components/Client/Integrations/Teams/TeamsAddForm.tsx @@ -2,8 +2,8 @@ import { observer } from 'mobx-react-lite'; import React from 'react'; import { useStore } from 'App/mstore'; -import { Button, Form, Input, Message } from 'UI'; -import { confirm } from 'UI'; +import { confirm, Form, Input, Message } from 'UI'; +import { Button } from 'antd' interface Props { onClose: () => void; @@ -83,7 +83,7 @@ function TeamsAddForm({ onClose }: Props) { onClick={save} disabled={!instance?.validate()} loading={saving} - variant="primary" + type="primary" className="float-left mr-2" > {instance?.exists() ? 'Update' : 'Add'} diff --git a/frontend/app/components/Client/Integrations/Teams/index.tsx b/frontend/app/components/Client/Integrations/Teams/index.tsx index b85a4f010..21ffec387 100644 --- a/frontend/app/components/Client/Integrations/Teams/index.tsx +++ b/frontend/app/components/Client/Integrations/Teams/index.tsx @@ -1,10 +1,11 @@ import React, { useEffect } from 'react'; -import TeamsChannelList from './TeamsChannelList'; import { useStore } from 'App/mstore'; import { observer } from 'mobx-react-lite'; +import { Icon } from 'UI'; +import { Button } from 'antd' +import TeamsChannelList from './TeamsChannelList'; import TeamsAddForm from './TeamsAddForm'; -import { Button } from 'UI'; const MSTeams = () => { const { integrationsStore } = useStore(); @@ -35,7 +36,7 @@ const MSTeams = () => {

Microsoft Teams

-
diff --git a/frontend/app/components/Client/Notifications/Notifications.tsx b/frontend/app/components/Client/Notifications/Notifications.tsx index 25941db52..0a2d12b23 100644 --- a/frontend/app/components/Client/Notifications/Notifications.tsx +++ b/frontend/app/components/Client/Notifications/Notifications.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import cn from 'classnames'; import stl from './notifications.module.css'; -import { Toggler } from 'UI'; +import { Switch } from 'antd' import { useStore } from "App/mstore"; import { observer } from 'mobx-react-lite' import withPageTitle from 'HOCs/withPageTitle'; @@ -25,12 +25,13 @@ function Notifications() {
Weekly project summary
Receive weekly report for each project on email.
- + + {weeklyReportStore.weeklyReport ? 'Yes' : 'No'} +
); diff --git a/frontend/app/components/Client/ProfileSettings/ChangePassword.tsx b/frontend/app/components/Client/ProfileSettings/ChangePassword.tsx index ce3eaeb38..207525f34 100644 --- a/frontend/app/components/Client/ProfileSettings/ChangePassword.tsx +++ b/frontend/app/components/Client/ProfileSettings/ChangePassword.tsx @@ -1,5 +1,6 @@ import React, { useState, useCallback } from 'react'; -import { Button, Message, Form, Input } from 'UI'; +import { Message, Form, Input } from 'UI'; +import { Button } from 'antd' import styles from './profileSettings.module.css'; import { validatePassword } from 'App/validate'; import { PASSWORD_POLICY } from 'App/constants'; @@ -121,7 +122,7 @@ const ChangePassword = () => { {PASSWORD_POLICY}
- +
); }; diff --git a/frontend/app/components/Client/ProfileSettings/Settings.js b/frontend/app/components/Client/ProfileSettings/Settings.js index 2852fd796..290f8b0f3 100644 --- a/frontend/app/components/Client/ProfileSettings/Settings.js +++ b/frontend/app/components/Client/ProfileSettings/Settings.js @@ -1,5 +1,6 @@ import React from 'react'; -import { Button, Input, Form } from 'UI'; +import { Input, Form } from 'UI'; +import { Button } from 'antd' import styles from './profileSettings.module.css'; import { observer } from 'mobx-react-lite'; import { useStore } from 'App/mstore'; @@ -61,7 +62,7 @@ function Settings() { /> - diff --git a/frontend/app/components/Client/ProfileSettings/TenantKey.js b/frontend/app/components/Client/ProfileSettings/TenantKey.js index 7cd4aece5..937e59b42 100644 --- a/frontend/app/components/Client/ProfileSettings/TenantKey.js +++ b/frontend/app/components/Client/ProfileSettings/TenantKey.js @@ -1,6 +1,7 @@ import React from 'react'; import copy from 'copy-to-clipboard'; -import { Form, Input, Button } from "UI"; +import { Form, Input } from "UI"; +import { Button } from 'antd'; import { observer } from 'mobx-react-lite'; import { useStore } from 'App/mstore'; @@ -29,8 +30,7 @@ function TenantKey() { value={ tenantKey } leadingButton={ diff --git a/frontend/app/components/Client/Roles/components/RoleForm/RoleForm.tsx b/frontend/app/components/Client/Roles/components/RoleForm/RoleForm.tsx index 835e677d0..d952f441a 100644 --- a/frontend/app/components/Client/Roles/components/RoleForm/RoleForm.tsx +++ b/frontend/app/components/Client/Roles/components/RoleForm/RoleForm.tsx @@ -2,10 +2,10 @@ import { observer } from 'mobx-react-lite'; import React, { useEffect, useRef } from 'react'; import { useStore } from 'App/mstore'; -import { Button, Checkbox, Form, Icon, Input } from 'UI'; +import { Checkbox, Form, Icon, Input } from 'UI'; import stl from './roleForm.module.css'; -import { Select } from 'antd'; +import { Select, Button } from 'antd'; import { SelectProps } from 'antd/es/select'; interface Props { @@ -220,7 +220,7 @@ const RoleForm = (props: Props) => { onClick={_save} disabled={!role.validate} loading={saving} - variant="primary" + type="primary" className="float-left mr-2" > {role.exists() ? 'Update' : 'Add'} @@ -228,7 +228,7 @@ const RoleForm = (props: Props) => { {role.exists() && } {role.exists() && ( - )} diff --git a/frontend/app/components/Client/Roles/components/RoleItem/RoleItem.tsx b/frontend/app/components/Client/Roles/components/RoleItem/RoleItem.tsx index c84d30966..429100e30 100644 --- a/frontend/app/components/Client/Roles/components/RoleItem/RoleItem.tsx +++ b/frontend/app/components/Client/Roles/components/RoleItem/RoleItem.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Icon, Link, Button } from 'UI'; +import { Icon, Link } from 'UI'; +import { Button } from 'antd' import stl from './roleItem.module.css'; import cn from 'classnames'; import { CLIENT_TABS, client as clientRoute } from 'App/routes'; @@ -46,7 +47,7 @@ function RoleItem({ role, editHandler, isAdmin, permissions, projects }: Props)
{isAdmin && !!editHandler && ( -
diff --git a/frontend/app/components/Client/Sites/AddProjectButton/AddProjectButton.tsx b/frontend/app/components/Client/Sites/AddProjectButton/AddProjectButton.tsx index ea8ca522a..b0e8fd52f 100644 --- a/frontend/app/components/Client/Sites/AddProjectButton/AddProjectButton.tsx +++ b/frontend/app/components/Client/Sites/AddProjectButton/AddProjectButton.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Tooltip, Button } from 'UI'; +import { Tooltip } from 'UI'; +import { Button } from 'antd' import { useStore } from 'App/mstore'; import { observer } from 'mobx-react-lite'; import { useModal } from 'App/components/Modal'; @@ -24,7 +25,7 @@ function AddProjectButton({ isAdmin = false }: any) { title={`${!isAdmin ? PERMISSION_WARNING : !canAddProject ? LIMIT_WARNING : 'Add a Project'}`} disabled={isAdmin || canAddProject} > - diff --git a/frontend/app/components/Client/Sites/BlockedIps.js b/frontend/app/components/Client/Sites/BlockedIps.js deleted file mode 100644 index 98f6acfde..000000000 --- a/frontend/app/components/Client/Sites/BlockedIps.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react'; -import { Input, Button, Icon } from 'UI'; -import styles from './blockedIps.module.css'; - -class BlockedIps extends React.PureComponent { - render() { - return ( -
-

{ 'Block IP' }

-
- -
- - -
- -
-
-
{ '192.128.2.1' }
-
- -
-
-
-
-
- ); - } -} - -export default BlockedIps; diff --git a/frontend/app/components/Client/Sites/GDPRForm.js b/frontend/app/components/Client/Sites/GDPRForm.js index fa54f73be..0a35f7399 100644 --- a/frontend/app/components/Client/Sites/GDPRForm.js +++ b/frontend/app/components/Client/Sites/GDPRForm.js @@ -1,7 +1,8 @@ import React from 'react'; import { observer } from 'mobx-react-lite'; import { useStore } from "App/mstore"; -import { Form, Button, Input, Icon } from 'UI'; +import { Form, Input, Icon } from 'UI'; +import { Button } from 'antd' import { validateNumber } from 'App/validate'; import styles from './siteForm.module.css'; import Select from 'Shared/Select'; @@ -115,12 +116,13 @@ function GDPRForm(props) {
+
) diff --git a/frontend/app/components/Client/Sites/InstallButton/InstallButton.tsx b/frontend/app/components/Client/Sites/InstallButton/InstallButton.tsx index da1a2fb44..f3ce8b8df 100644 --- a/frontend/app/components/Client/Sites/InstallButton/InstallButton.tsx +++ b/frontend/app/components/Client/Sites/InstallButton/InstallButton.tsx @@ -1,7 +1,7 @@ import { useModal } from 'App/components/Modal'; import React from 'react'; import TrackingCodeModal from 'Shared/TrackingCodeModal'; -import { Button } from 'UI'; +import { Button } from 'antd'; interface Props { site: any; @@ -16,7 +16,7 @@ function InstallButton(props: Props) { ); }; return ( - ); diff --git a/frontend/app/components/Client/Sites/NewSiteForm.tsx b/frontend/app/components/Client/Sites/NewSiteForm.tsx index fdb380e75..6445fc700 100644 --- a/frontend/app/components/Client/Sites/NewSiteForm.tsx +++ b/frontend/app/components/Client/Sites/NewSiteForm.tsx @@ -3,8 +3,8 @@ import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react'; import { RouteComponentProps, withRouter } from 'react-router-dom'; import { toast } from 'react-toastify'; import { useStore } from 'App/mstore'; -import { Button, Form, Icon, Input } from 'UI'; -import { confirm } from 'UI'; +import { confirm, Form, Icon, Input } from 'UI'; +import { Button } from 'antd' import { observer } from 'mobx-react-lite'; import styles from './siteForm.module.css'; @@ -141,8 +141,8 @@ const NewSiteForm = ({ location: { pathname }, onClose }: Props) => {
{site.exists() && (
- {project.conditionsCount > 0 ? ( diff --git a/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx b/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx index 2c1ee6e2c..dd495a2c8 100644 --- a/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx +++ b/frontend/app/components/Client/Users/components/UserForm/UserForm.tsx @@ -5,8 +5,8 @@ import React from 'react'; import { useModal } from 'App/components/Modal'; import { useStore } from 'App/mstore'; -import { Button, CopyButton, Form, Icon, Input } from 'UI'; -import { confirm } from 'UI'; +import { confirm, CopyButton, Form, Icon, Input } from 'UI'; +import { Button } from 'antd' import Select from 'Shared/Select'; @@ -139,22 +139,20 @@ function UserForm() { onClick={onSave} disabled={!user.valid(isEnterprise) || isSaving} loading={isSaving} - variant="primary" + type="primary" className="float-left mr-2" > {user.exists() ? 'Update' : 'Invite'} {user.exists() && }
-
- -
+ {!user.exists() ? null : +
+ +
+ } {!user.isJoined && user.invitationLink && ( diff --git a/frontend/app/components/Client/Users/components/UserListItem/UserListItem.tsx b/frontend/app/components/Client/Users/components/UserListItem/UserListItem.tsx index c83aa439d..338d2e04b 100644 --- a/frontend/app/components/Client/Users/components/UserListItem/UserListItem.tsx +++ b/frontend/app/components/Client/Users/components/UserListItem/UserListItem.tsx @@ -1,6 +1,7 @@ //@ts-nocheck import React from 'react'; -import { Button, Tooltip } from 'UI'; +import { Tooltip, Icon } from 'UI'; +import { Button } from 'antd' import { checkForRecent } from 'App/date'; import cn from 'classnames'; @@ -79,9 +80,8 @@ function UserListItem(props: Props) { {!user.isJoined && user.invitationLink && !user.isExpiredInvite && ( diff --git a/frontend/app/components/Dashboard/components/Alerts/AlertForm/BottomButtons.tsx b/frontend/app/components/Dashboard/components/Alerts/AlertForm/BottomButtons.tsx index 9a5e716f0..5dbb460bd 100644 --- a/frontend/app/components/Dashboard/components/Alerts/AlertForm/BottomButtons.tsx +++ b/frontend/app/components/Dashboard/components/Alerts/AlertForm/BottomButtons.tsx @@ -1,5 +1,6 @@ import React from 'react' -import { Button, Icon } from 'UI' +import { Icon } from 'UI' +import { Button } from 'antd' interface IBottomButtons { loading: boolean @@ -14,8 +15,7 @@ function BottomButtons({ loading, instance, deleting, onDelete }: IBottomButtons
- {hasFilters && } - + {hasFilters && } +
diff --git a/frontend/app/components/Dashboard/components/CardUserList/CardUserList.tsx b/frontend/app/components/Dashboard/components/CardUserList/CardUserList.tsx index e6d7a1a4d..842184f2e 100644 --- a/frontend/app/components/Dashboard/components/CardUserList/CardUserList.tsx +++ b/frontend/app/components/Dashboard/components/CardUserList/CardUserList.tsx @@ -2,7 +2,8 @@ import { useModal } from 'App/components/Modal'; import { observer } from 'mobx-react-lite'; import React, { useEffect, useState } from 'react'; import { RouteComponentProps, withRouter } from 'react-router'; -import { Loader, Pagination, Button } from 'UI'; +import { Loader, Pagination } from 'UI'; +import { Button } from 'antd' import SessionsModal from './SessionsModal'; import CardUserItem from './CardUserItem'; import { useStore } from 'App/mstore'; @@ -45,7 +46,7 @@ function CardUserList(props: RouteComponentProps) {

Returning users between

- +
diff --git a/frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx b/frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx index 3d8cfb44e..1be4a2444 100644 --- a/frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx +++ b/frontend/app/components/Dashboard/components/DashboardEditModal/DashboardEditModal.tsx @@ -53,7 +53,7 @@ function DashboardEditModal(props: Props) { value={ dashboard.name } onChange={write} placeholder="Title" - maxLength={100} + maxLength={40} autoFocus={focusTitle} /> diff --git a/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx b/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx index 659b4a604..20429e74a 100644 --- a/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx +++ b/frontend/app/components/Dashboard/components/DashboardModal/DashboardModal.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useObserver } from 'mobx-react-lite'; import DashboardMetricSelection from '../DashboardMetricSelection'; import DashboardForm from '../DashboardForm'; -import { Button } from 'UI'; +import { Button } from 'antd'; import { withRouter, RouteComponentProps } from 'react-router-dom'; import { useStore } from 'App/mstore'; import { useModal } from 'App/components/Modal'; @@ -67,7 +67,7 @@ function DashboardModal(props: Props) {
- -
- {TAGS.map((tag) => ( - addTag(tag)} - key={tag} - className='cursor-pointer rounded-lg hover:bg-indigo-50' - color={tagActive(tag) ? tagProps[tag] : undefined} - bordered={false} - - > -
- {tagActive(tag) ? ( - - ) : null} - {tag} -
-
- ))} -
- -
setPublic(!isPublic)} - > - -
Visible to team members
-
- {slackChannelsOptions.length > 1 ? ( -
-
setSlack(!useSlack)} - > - - Share via Slack -
- - {useSlack && ( -
- -
- )} -
- ) : null} - -
- - -
- - ); -} - -export default observer(CreateNote); diff --git a/frontend/app/components/Session_/Player/Controls/components/PlayingTime.tsx b/frontend/app/components/Session_/Player/Controls/components/PlayingTime.tsx index f666a43a2..393cf3b3b 100644 --- a/frontend/app/components/Session_/Player/Controls/components/PlayingTime.tsx +++ b/frontend/app/components/Session_/Player/Controls/components/PlayingTime.tsx @@ -31,6 +31,7 @@ function PlayingTime({ timeMode, setTimeMode, startedAt, sessionTz }: Props) { distance={20} render={({ close }) => (
, }, { type: 'divider' }, - { - key: ItemKey.AddNote, - label: 'Add Note', - icon: , - }, + // { + // key: ItemKey.AddNote, + // label: 'Add Note', + // icon: , + // }, { key: ItemKey.CopySessionUrl, label: 'Copy Session URL', @@ -131,16 +130,16 @@ function Overlay({ nextId, isClickmap }: Props) { case ItemKey.State: toggleBottomBlock(STORAGE); break; - case ItemKey.AddNote: - showModal( - , - { right: true, width: 380 } - ); - break; + // case ItemKey.AddNote: + // showModal( + // , + // { right: true, width: 380 } + // ); + // break; case ItemKey.CopySessionUrl: copy(window.location.origin + window.location.pathname); toast.success('Session URL copied to clipboard'); diff --git a/frontend/app/components/Session_/Player/Overlay/AutoplayTimer.tsx b/frontend/app/components/Session_/Player/Overlay/AutoplayTimer.tsx index a4180d056..e780a4820 100644 --- a/frontend/app/components/Session_/Player/Overlay/AutoplayTimer.tsx +++ b/frontend/app/components/Session_/Player/Overlay/AutoplayTimer.tsx @@ -2,7 +2,8 @@ import React, { useEffect, useState } from 'react'; import cn from 'classnames'; import { observer } from 'mobx-react-lite'; import { withRouter } from 'react-router-dom'; -import { Button, Link } from 'UI'; +import { Link } from 'UI'; +import { Button } from 'antd' import { session as sessionRoute, withSiteId } from 'App/routes'; import stl from './AutoplayTimer.module.css'; import clsOv from './overlay.module.css'; @@ -50,12 +51,12 @@ function AutoplayTimer({ history }: any) {
-
- +
diff --git a/frontend/app/components/Session_/ScreenRecorder/ScreenRecorder.tsx b/frontend/app/components/Session_/ScreenRecorder/ScreenRecorder.tsx index fbfcce9ae..6df8e775a 100644 --- a/frontend/app/components/Session_/ScreenRecorder/ScreenRecorder.tsx +++ b/frontend/app/components/Session_/ScreenRecorder/ScreenRecorder.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { screenRecorder } from 'App/utils/screenRecorder'; -import { Tooltip } from 'antd' -import { Button } from 'UI'; +import { Tooltip, Button } from 'antd' +import { Icon } from 'UI'; import { SessionRecordingStatus } from 'Player'; let stopRecorderCb: () => void; import { recordingsService } from 'App/services'; @@ -116,7 +116,7 @@ function ScreenRecorder() { - @@ -127,8 +127,9 @@ function ScreenRecorder() { return (
diff --git a/frontend/app/components/Session_/Subheader.tsx b/frontend/app/components/Session_/Subheader.tsx index b3efe5863..df461e635 100644 --- a/frontend/app/components/Session_/Subheader.tsx +++ b/frontend/app/components/Session_/Subheader.tsx @@ -1,7 +1,7 @@ import { ShareAltOutlined } from '@ant-design/icons'; import { Button as AntButton, Switch, Tooltip, Dropdown } from 'antd'; import cn from 'classnames'; -import { Link2, Keyboard } from 'lucide-react'; +import { Link2, Keyboard, Bot } from 'lucide-react'; import { observer } from 'mobx-react-lite'; import React, { useMemo } from 'react'; import { MoreOutlined } from '@ant-design/icons'; @@ -21,6 +21,7 @@ import { Bookmark as BookmarkIcn, BookmarkCheck, Vault } from 'lucide-react'; import { useModal } from 'Components/ModalContext'; import IssueForm from 'Components/Session_/Issues/IssueForm'; import ShareModal from '../shared/SharePopup/SharePopup'; +import UnitStepsModal from "./UnitStepsModal"; const disableDevtools = 'or_devtools_uxt_toggle'; @@ -116,6 +117,13 @@ function SubHeader(props) { }); }; + const exportEvents = () => { + const allEvents = sessionStore.current.events; + const width = store.get().width; + const height = store.get().height; + openModal(, { title: 'Export Events', width: 640 }); + } + return ( <>
Keyboard Shortcuts
, onClick: showKbHelp + }, + { + key: '5', + label:
+ + Export Events +
, + onClick: exportEvents, } ] }} diff --git a/frontend/app/components/Session_/UnitStepsModal/index.tsx b/frontend/app/components/Session_/UnitStepsModal/index.tsx new file mode 100644 index 000000000..033453d53 --- /dev/null +++ b/frontend/app/components/Session_/UnitStepsModal/index.tsx @@ -0,0 +1,96 @@ +import React from 'react'; +import { TYPES, Input, Click, Location } from 'App/types/session/event'; +import { CodeBlock, CopyButton } from 'UI'; +import { Segmented } from 'antd'; + +interface Props { + events: Input[] | Click[] | Location[]; + width: number; + height: number; +} + +function UnitStepsModal({ events, width, height }: Props) { + const [eventStr, setEventStr] = React.useState(''); + const [activeFramework, setActiveFramework] = React.useState('puppeteer'); + + React.useEffect(() => { + const userEventTypes = [TYPES.LOCATION, TYPES.CLICK, TYPES.INPUT]; + const puppeteerEvents = { + [TYPES.LOCATION]: (event: Location) => `await page.goto('${event.url}')`, + [TYPES.CLICK]: (event: Click) => + `await page.locator('${ + event.selector.length ? event.selector : event.label + }').click()`, + [TYPES.INPUT]: (event: Input) => + `await page.locator('${event.label}').type('Test Input')`, + screen: () => + `await page.setViewport({width: ${width}, height: ${height})`, + }; + const cypressEvents = { + [TYPES.LOCATION]: (event: Location) => `cy.visit('${event.url}')`, + [TYPES.CLICK]: (event: Click) => + `cy.get('${ + event.selector.length ? event.selector : event.label + }').click()`, + [TYPES.INPUT]: (event: Input) => + `cy.get('${event.label}').type('Test Input')`, + screen: () => `cy.viewport(${width}, ${height})`, + }; + const playWrightEvents = { + [TYPES.LOCATION]: (event: Location) => `await page.goto('${event.url}')`, + [TYPES.CLICK]: (event: Click) => + event.selector.length + ? `await page.locator('${event.selector}').click()` + : `await page.getByText('${event.label}').click()`, + [TYPES.INPUT]: (event: Input) => + `await page.getByLabel('${event.label}').fill('Test Input')`, + screen: () => + `await page.setViewport({width: ${width}, height: ${height})`, + }; + + const collections = { + puppeteer: puppeteerEvents, + cypress: cypressEvents, + playwright: playWrightEvents, + } + + // @ts-ignore + const usedCollection = collections[activeFramework]; + + let finalScript = ''; + events.forEach((ev) => { + if (userEventTypes.includes(ev.type)) { + finalScript += usedCollection[ev.type](ev); + finalScript += '\n'; + } + }); + setEventStr(finalScript); + }, [events, activeFramework]); + + return ( +
+
+ setActiveFramework(value)} + /> + +
+
+ +
+
+ ); +} + +export default UnitStepsModal; diff --git a/frontend/app/components/Session_/components/HeaderMenu.tsx b/frontend/app/components/Session_/components/HeaderMenu.tsx deleted file mode 100644 index 621334cf7..000000000 --- a/frontend/app/components/Session_/components/HeaderMenu.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React from 'react'; -import { Button, Icon } from 'UI'; -import styles from './menu.module.css'; -import cn from 'classnames'; -import OutsideClickDetectingDiv from 'Shared/OutsideClickDetectingDiv'; - -interface MenuItem { - key: number; - autoclose?: boolean; - component?: React.ReactElement; -} - -interface Props { - items: MenuItem[]; - useSc?: boolean; -} - -export default class ItemMenu extends React.PureComponent { - state = { - displayed: false, - }; - - handleEsc = (e: KeyboardEvent) => e.key === 'Escape' && this.state.displayed && this.toggleMenu(); - handleSc = (e: KeyboardEvent) => e.key === 'M' && e.shiftKey ? this.toggleMenu() : null; - - componentDidMount() { - document.addEventListener('keydown', this.handleEsc, false); - if (this.props.useSc) { - document.addEventListener('keydown', this.handleSc, false) - } - } - componentWillUnmount() { - document.removeEventListener('keydown', this.handleEsc, false); - if (this.props.useSc) { - document.removeEventListener('keydown', this.handleSc, false) - } - } - - toggleMenu = () => { - this.setState({ displayed: !this.state.displayed }); - }; - - closeMenu = () => { - this.setState({ displayed: false }); - }; - - render() { - const { items } = this.props; - const { displayed } = this.state; - - return ( -
- - -
- {items.map((item) => - item.component ? ( -
- {item.component} -
- ) : null - )} -
-
-
- ); - } -} diff --git a/frontend/app/components/Session_/components/NotePopup.tsx b/frontend/app/components/Session_/components/NotePopup.tsx deleted file mode 100644 index 5f38f1ba3..000000000 --- a/frontend/app/components/Session_/components/NotePopup.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import CreateNote from 'Components/Session_/Player/Controls/components/CreateNote'; -import React from 'react'; -import { observer } from 'mobx-react-lite'; -import { useStore } from 'App/mstore'; -import { PlayerContext } from 'App/components/Session/playerContext'; -import { Button, Tooltip } from 'antd'; -import { MessageOutlined } from '@ant-design/icons'; -import { useModal } from 'App/components/Modal'; - -function NotePopup() { - const { sessionStore } = useStore(); - const tooltipActive = sessionStore.createNoteTooltip.isVisible; - const { player, store } = React.useContext(PlayerContext); - const { showModal, hideModal } = useModal(); - const toggleNotePopup = () => { - if (tooltipActive) return; - player.pause(); - showModal( - , - { - right: true, - width: 380, - } - ); - }; - - return ( - - - - ); -} - -export default observer(NotePopup) diff --git a/frontend/app/components/Signup/SignupForm/SignupForm.tsx b/frontend/app/components/Signup/SignupForm/SignupForm.tsx index 36f0f761a..f9d91201b 100644 --- a/frontend/app/components/Signup/SignupForm/SignupForm.tsx +++ b/frontend/app/components/Signup/SignupForm/SignupForm.tsx @@ -15,7 +15,8 @@ import { SITE_ID_STORAGE_KEY } from 'App/constants/storageKeys'; import { useStore } from 'App/mstore'; import { login } from 'App/routes'; import { validatePassword } from 'App/validate'; -import { Button, Form, Input, Link } from 'UI'; +import { Form, Input, Link } from 'UI'; +import { Button } from 'antd' import Select from 'Shared/Select'; @@ -221,8 +222,8 @@ const SignupForm = () => { ) : null} -
- - - ); -} - -export default withPageTitle('Password Change - OpenReplay')( - observer(UpdatePassword) -); diff --git a/frontend/app/components/UpdatePassword/updatePassword.module.css b/frontend/app/components/UpdatePassword/updatePassword.module.css deleted file mode 100644 index 386a99e19..000000000 --- a/frontend/app/components/UpdatePassword/updatePassword.module.css +++ /dev/null @@ -1,127 +0,0 @@ -@import 'icons.css'; - -.form { - position: absolute; - top: 50%; - margin-top: -300px; - width: 520px; - left: 50%; - margin-left: -260px; - - & .passwordPolicy { - color: $gray-medium; - padding: 5px 0 10px; - font-size: 13px; - } - - & form { - padding: 10px 70px; - border: solid 2px $gray-light; - border-radius: 2px; - background-color: white; - } - & h2 { - text-align: center; - font-size: 20px; - color: #555555; - margin: 35px 0; - font-weight: 300; - } -} - -.formFooter { - text-align: center; - padding: 15px 0; -} - -.links { - display: flex; - align-items: center; - justify-content: center; - padding: 10px 0; - margin-top: 20px; - - & .divider { - width: 1px; - height: 12px; - background-color: $gray-medium; - margin: 0 5px; - } -} - -.logo { - background-image: svg-load('logo.svg'); - background-repeat: no-repeat; - background-size: contain; - background-position: center center; - height: 50px; - margin-bottom: 20px; -} - - -.email, .password { - display: block; - margin-top: 15px; - width: 100%; - height: 45px; - line-height: 45px; - border: $gray-light solid 1px; - border-radius: 3px; - font-size: 14px; - padding: 0 10px; - transition: all 0.2s; - - &::placeholder { - color: #AAA; - } - - &:focus { - border-color: $teal; - transition: all 0.2s; - } -} - -.errors { - border-radius: 5px; - width: 400px; - margin: auto; - border: 2px solid $red; - padding: 15px; - background-color: $white; -} - -.submit { - display: block; - border-radius: 5px; - background: $teal; - width: 135px; - height: 45px; - margin: 20px auto; - color: $white; - font-size: 16px; - cursor: pointer; -} - -.inputWithIcon { - position: relative; - - & input { - padding-left: 45px; - } -} - -@define-mixin inputIcon $name { - position: absolute; - left: 15px; - top: calc(50% - 8px); - @mixin icon $name, $gray-medium, 15px; -} - -.inputIconUser { - @mixin inputIcon user-alt; -} - -.inputIconPassword { - @mixin inputIcon lock-alt; -} - diff --git a/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx b/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx index 3e73b8dad..6815680e4 100644 --- a/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx +++ b/frontend/app/components/shared/AlertTriggersModal/AlertTriggersModal.tsx @@ -1,5 +1,6 @@ import React, { useEffect } from 'react'; -import { Button, NoContent, Loader } from 'UI'; +import { NoContent, Loader } from 'UI'; +import { Button } from 'antd' import cn from 'classnames'; import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG'; import ListItem from './ListItem' @@ -37,7 +38,6 @@ function AlertTriggersModal(props: Props) { { count > 0 && (
diff --git a/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx b/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx index 47bbf8b78..d4729ecb1 100644 --- a/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx +++ b/frontend/app/components/shared/DevTools/TimeTable/TimeTable.tsx @@ -2,7 +2,8 @@ import React from 'react'; import { VList, VListHandle } from 'virtua'; import cn from 'classnames'; import { Duration } from 'luxon'; -import { NoContent, Button } from 'UI'; +import { NoContent, Icon } from 'UI'; +import { Button } from 'antd' import { percentOf } from 'App/utils'; import BarRow from './BarRow'; @@ -214,21 +215,13 @@ function TimeTable(props: Props) { {navigation && (
diff --git a/frontend/app/components/shared/DocLink/DocLink.js b/frontend/app/components/shared/DocLink/DocLink.js index 3647e79e5..c3ae25f11 100644 --- a/frontend/app/components/shared/DocLink/DocLink.js +++ b/frontend/app/components/shared/DocLink/DocLink.js @@ -1,5 +1,6 @@ import React from 'react' -import { Button, Icon } from 'UI' +import { Icon } from 'UI' +import { Button } from 'antd' export default function DocLink({ className = '', url, label }) { const openLink = () => { @@ -8,7 +9,7 @@ export default function DocLink({ className = '', url, label }) { return (
- diff --git a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx index 5d4c60ca1..378d9c5a6 100644 --- a/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx +++ b/frontend/app/components/shared/Filters/FilterValue/FilterValue.tsx @@ -20,6 +20,13 @@ function FilterValue(props: Props) { const { filter } = props; const isAutoOpen = filter.autoOpen; + React.useEffect(() => { + if (isAutoOpen) { + setTimeout(() => { + filter.autoOpen = false; + }, 250) + } + }, [isAutoOpen]) const [durationValues, setDurationValues] = useState({ minDuration: filter.value?.[0], maxDuration: filter.value.length > 1 ? filter.value[1] : filter.value[0], diff --git a/frontend/app/components/shared/ImageViewer/ImageViewer.js b/frontend/app/components/shared/ImageViewer/ImageViewer.js deleted file mode 100644 index 28d9aadfc..000000000 --- a/frontend/app/components/shared/ImageViewer/ImageViewer.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useState } from 'react' -import { Button } from 'UI'; - -export default function ImageViewer( - { source, activeIndex, onClose } -) { - const [currentIndex, setCurrentIndex] = useState(activeIndex) - const onPrevClick = () => { - setCurrentIndex(currentIndex - 1); - } - const onNextClick = () => { - setCurrentIndex(currentIndex + 1); - } - return ( -
-
- - - -
- -
- ) -} diff --git a/frontend/app/components/shared/ImageViewer/index.js b/frontend/app/components/shared/ImageViewer/index.js deleted file mode 100644 index 86ec5cbec..000000000 --- a/frontend/app/components/shared/ImageViewer/index.js +++ /dev/null @@ -1 +0,0 @@ -export { default } from './ImageViewer'; \ No newline at end of file diff --git a/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js b/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js index fa806a0d2..bc1900336 100644 --- a/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js +++ b/frontend/app/components/shared/IntegrateSlackButton/IntegrateSlackButton.js @@ -1,5 +1,6 @@ import React from 'react' -import { Button, Icon } from 'UI' +import { Icon } from 'UI' +import { Button } from 'antd' import { CLIENT_TABS, client as clientRoute } from 'App/routes'; import { withRouter } from 'react-router-dom'; @@ -14,7 +15,7 @@ function IntegrateSlackTeamsButton({ history }) {
{savedSearch.exists() && ( - )} diff --git a/frontend/app/components/shared/SearchActions/SearchActions.tsx b/frontend/app/components/shared/SearchActions/SearchActions.tsx index ddc27c858..305ad52ea 100644 --- a/frontend/app/components/shared/SearchActions/SearchActions.tsx +++ b/frontend/app/components/shared/SearchActions/SearchActions.tsx @@ -40,14 +40,14 @@ function SearchActions() {
- +
{showPanel ? ( diff --git a/frontend/app/components/shared/SessionFilters/SessionFilters.tsx b/frontend/app/components/shared/SessionFilters/SessionFilters.tsx index 4e40105ff..84b95a585 100644 --- a/frontend/app/components/shared/SessionFilters/SessionFilters.tsx +++ b/frontend/app/components/shared/SessionFilters/SessionFilters.tsx @@ -23,28 +23,34 @@ function SessionFilters() { projectsStore.instance?.saveRequestPayloads ?? false; const activeProject = projectsStore.active + const reloadTags = async () => { + const tags = await tagWatchStore.getTags(); + if (tags) { + addOptionsToFilter( + FilterKey.TAGGED_ELEMENT, + tags.map((tag) => ({ + label: tag.name, + value: tag.tagId.toString(), + })) + ); + searchStore.refreshFilterOptions(); + } + } + useEffect(() => { // Add default location/screen filter if no filters are present if (searchStore.instance.filters.length === 0) { searchStore.addFilterByKeyAndValue(activeProject?.platform === 'web' ? FilterKey.LOCATION : FilterKey.VIEW_MOBILE , '', 'isAny') } + void reloadTags(); }, [projectsStore.activeSiteId, activeProject]) + useSessionSearchQueryHandler({ appliedFilter, loading: metaLoading, onBeforeLoad: async () => { - const tags = await tagWatchStore.getTags(); - if (tags) { - addOptionsToFilter( - FilterKey.TAGGED_ELEMENT, - tags.map((tag) => ({ - label: tag.name, - value: tag.tagId.toString(), - })) - ); - searchStore.refreshFilterOptions(); - } + await reloadTags(); }, }); diff --git a/frontend/app/components/shared/SessionItem/MetaMoreButton/MetaMoreButton.tsx b/frontend/app/components/shared/SessionItem/MetaMoreButton/MetaMoreButton.tsx index 9253b2de9..c8bdaff61 100644 --- a/frontend/app/components/shared/SessionItem/MetaMoreButton/MetaMoreButton.tsx +++ b/frontend/app/components/shared/SessionItem/MetaMoreButton/MetaMoreButton.tsx @@ -1,5 +1,6 @@ import React from 'react'; -import { Popover, Button } from 'UI'; +import { Popover } from 'UI'; +import { Button } from 'antd' import MetaItem from '../MetaItem'; interface Props { @@ -23,7 +24,7 @@ export default function MetaMoreButton(props: Props) { placement="bottom" >
- +
); diff --git a/frontend/app/components/shared/SessionSettings/components/ConditionalRecordingSettings.tsx b/frontend/app/components/shared/SessionSettings/components/ConditionalRecordingSettings.tsx index 90e9dc2df..a6a710831 100644 --- a/frontend/app/components/shared/SessionSettings/components/ConditionalRecordingSettings.tsx +++ b/frontend/app/components/shared/SessionSettings/components/ConditionalRecordingSettings.tsx @@ -1,7 +1,8 @@ import { Conditions } from 'App/mstore/types/FeatureFlag'; import React from 'react'; import ConditionSet from 'Shared/ConditionSet'; -import { Button } from 'UI'; +import { Icon } from 'UI'; +import { Button } from 'antd'; import { nonConditionalFlagFilters } from 'Types/filter/newFilter'; function ConditionalRecordingSettings({ @@ -43,7 +44,7 @@ function ConditionalRecordingSettings({ />
matching -
diff --git a/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx b/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx index 6d30059c2..a03997648 100644 --- a/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx +++ b/frontend/app/components/shared/SessionSettings/components/DefaultTimezone.tsx @@ -5,8 +5,8 @@ import { toast } from 'react-toastify'; import { useStore } from 'App/mstore'; import { Timezone } from 'App/mstore/types/sessionSettings'; -import { Button, Icon } from 'UI'; - +import { Icon } from 'UI'; +import { Button } from 'antd' import Select from 'Shared/Select'; type TimezonesDropdown = Timezone[]; @@ -104,8 +104,7 @@ function DefaultTimezone() {
- +
diff --git a/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx b/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx index 2ede00e77..c6ecbf091 100644 --- a/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx +++ b/frontend/app/components/shared/SessionsTabOverview/components/SessionList/SessionList.tsx @@ -1,7 +1,8 @@ import React, { useEffect } from 'react'; import { FilterKey } from 'Types/filter/filterType'; import SessionItem from 'Shared/SessionItem'; -import { NoContent, Loader, Pagination, Button } from 'UI'; +import { NoContent, Loader, Pagination, Icon } from 'UI'; +import { Button } from 'antd' import { useLocation, withRouter } from 'react-router-dom'; import AnimatedSVG, { ICONS } from 'Shared/AnimatedSVG/AnimatedSVG'; import { numberWithCommas } from 'App/utils'; @@ -188,10 +189,9 @@ function SessionList() { )} + )} { (focused || !selected) && ( diff --git a/frontend/app/components/ui/Avatar/Avatar.js b/frontend/app/components/ui/Avatar/Avatar.js index 536ee6a62..67a10c550 100644 --- a/frontend/app/components/ui/Avatar/Avatar.js +++ b/frontend/app/components/ui/Avatar/Avatar.js @@ -1,7 +1,8 @@ import React from 'react'; import cn from 'classnames'; import { avatarIconName } from 'App/iconNames'; -import { Icon, Tooltip } from 'UI'; +import { Icon } from 'UI'; +import { Tooltip } from 'antd' const Avatar = ({ isActive = false, @@ -13,7 +14,7 @@ const Avatar = ({ }) => { var iconName = avatarIconName(seed); return ( - +
{ const { className = '', label = '', ...rest } = props; return ( - + + {label} + ); }; diff --git a/frontend/app/components/ui/CopyButton/CopyButton.js b/frontend/app/components/ui/CopyButton/CopyButton.js index bceb38b31..5df72b999 100644 --- a/frontend/app/components/ui/CopyButton/CopyButton.js +++ b/frontend/app/components/ui/CopyButton/CopyButton.js @@ -3,7 +3,7 @@ import { useState } from 'react'; import copy from 'copy-to-clipboard'; import { Button } from 'antd'; -function CopyButton({ content, variant="text-primary", className = '', btnText = 'copy' }) { +function CopyButton({ content, variant="text", className = 'capitalize mt-2 font-medium text-neutral-400', btnText = 'copy', size = "small" }) { const [copied, setCopied] = useState(false) const copyHandler = () => { @@ -16,14 +16,14 @@ function CopyButton({ content, variant="text-primary", className = '', btnText return ( - ) + ); } export default CopyButton diff --git a/frontend/app/components/ui/ErrorDetails/ErrorDetails.tsx b/frontend/app/components/ui/ErrorDetails/ErrorDetails.tsx index 9cd076295..c869a4d18 100644 --- a/frontend/app/components/ui/ErrorDetails/ErrorDetails.tsx +++ b/frontend/app/components/ui/ErrorDetails/ErrorDetails.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import ErrorFrame from '../ErrorFrame/ErrorFrame'; -import { Button, Icon } from 'UI'; +import { Icon } from 'UI'; +import { Button } from 'antd' import { observer } from 'mobx-react-lite'; import { useStore } from 'App/mstore'; @@ -44,10 +45,10 @@ function ErrorDetails(props: Props) {

Stacktrace

- -
diff --git a/frontend/app/components/ui/HelpText/HelpText.tsx b/frontend/app/components/ui/HelpText/HelpText.tsx deleted file mode 100644 index 0bfdfdc5e..000000000 --- a/frontend/app/components/ui/HelpText/HelpText.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; -import { Icon, Tooltip } from 'UI'; - -interface Props { - text: string; - className?: string; - position?: string; -} -export default function HelpText(props: Props) { - const { text, className = '', position = 'top center' } = props; - return ( -
- -
- -
-
-
- ); -} diff --git a/frontend/app/components/ui/HelpText/index.ts b/frontend/app/components/ui/HelpText/index.ts deleted file mode 100644 index 0868cbffd..000000000 --- a/frontend/app/components/ui/HelpText/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default } from './HelpText'; \ No newline at end of file diff --git a/frontend/app/components/ui/IconButton/IconButton.js b/frontend/app/components/ui/IconButton/IconButton.js index 2d24bd1f5..6e325a016 100644 --- a/frontend/app/components/ui/IconButton/IconButton.js +++ b/frontend/app/components/ui/IconButton/IconButton.js @@ -1,6 +1,7 @@ import React from 'react'; import cn from 'classnames'; -import { CircularLoader, Icon, Tooltip } from 'UI'; +import { Tooltip } from 'antd' +import { CircularLoader, Icon } from 'UI'; import stl from './iconButton.module.css'; const IconButton = React.forwardRef( diff --git a/frontend/app/components/ui/Input/Input.tsx b/frontend/app/components/ui/Input/Input.tsx index 9e93376c8..6bfb67853 100644 --- a/frontend/app/components/ui/Input/Input.tsx +++ b/frontend/app/components/ui/Input/Input.tsx @@ -1,6 +1,6 @@ import cn from 'classnames'; import React from 'react'; - +import { Input as AntInput } from 'antd' import { Icon } from 'UI'; interface Props { @@ -36,7 +36,7 @@ const Input = React.forwardRef((props: Props, ref: any) => { /> )} {type === 'textarea' ? ( -