diff --git a/deploy/docker/clickhouse-setup/docker-compose.arm.yaml b/deploy/docker/clickhouse-setup/docker-compose.arm.yaml index 66dbcec949..f666105b32 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.arm.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.arm.yaml @@ -23,7 +23,7 @@ services: - '--storage.path=/data' query-service: - image: signoz/query-service:0.7.0 + image: signoz/query-service:0.6.2 container_name: query-service command: ["-config=/root/config/prometheus.yml"] volumes: @@ -40,7 +40,7 @@ services: condition: service_healthy frontend: - image: signoz/frontend:0.7.0 + image: signoz/frontend:0.6.2 container_name: frontend depends_on: - query-service @@ -50,8 +50,8 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector: - image: signoz/otelcontribcol:0.43.0 - command: ["--config=/etc/otel-collector-config.yaml"] + image: signoz/otelcontribcol:0.6.0 + command: ["--config=/etc/otel-collector-config.yaml", "--mem-ballast-size-mib=683"] volumes: - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml ports: @@ -63,8 +63,8 @@ services: condition: service_healthy otel-collector-metrics: - image: signoz/otelcontribcol:0.43.0 - command: ["--config=/etc/otel-collector-metrics-config.yaml"] + image: signoz/otelcontribcol:0.6.0 + command: ["--config=/etc/otel-collector-metrics-config.yaml", "--mem-ballast-size-mib=683"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml depends_on: diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index 96b27e6ca8..3c5dbbc64d 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -26,7 +26,7 @@ services: query-service: - image: signoz/query-service:0.7.0 + image: signoz/query-service:0.6.2 container_name: query-service command: ["-config=/root/config/prometheus.yml"] volumes: @@ -43,7 +43,7 @@ services: condition: service_healthy frontend: - image: signoz/frontend:0.7.0 + image: signoz/frontend:0.6.2 container_name: frontend depends_on: - query-service @@ -53,8 +53,8 @@ services: - ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf otel-collector: - image: signoz/otelcontribcol:0.43.0 - command: ["--config=/etc/otel-collector-config.yaml"] + image: signoz/otelcontribcol:0.6.0 + command: ["--config=/etc/otel-collector-config.yaml", "--mem-ballast-size-mib=683"] volumes: - ./otel-collector-config.yaml:/etc/otel-collector-config.yaml ports: @@ -66,8 +66,8 @@ services: condition: service_healthy otel-collector-metrics: - image: signoz/otelcontribcol:0.43.0 - command: ["--config=/etc/otel-collector-metrics-config.yaml"] + image: signoz/otelcontribcol:0.6.0 + command: ["--config=/etc/otel-collector-metrics-config.yaml", "--mem-ballast-size-mib=683"] volumes: - ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml depends_on: diff --git a/deploy/docker/clickhouse-setup/otel-collector-config.yaml b/deploy/docker/clickhouse-setup/otel-collector-config.yaml index a4a2641daa..eeaf7221d7 100644 --- a/deploy/docker/clickhouse-setup/otel-collector-config.yaml +++ b/deploy/docker/clickhouse-setup/otel-collector-config.yaml @@ -27,14 +27,14 @@ processors: signozspanmetrics/prometheus: metrics_exporter: prometheus latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ] - # memory_limiter: - # # Same as --mem-ballast-size-mib CLI argument - # ballast_size_mib: 683 - # # 80% of maximum memory up to 2G - # limit_mib: 1500 - # # 25% of limit up to 2G - # spike_limit_mib: 512 - # check_interval: 5s + memory_limiter: + # Same as --mem-ballast-size-mib CLI argument + ballast_size_mib: 683 + # 80% of maximum memory up to 2G + limit_mib: 1500 + # 25% of limit up to 2G + spike_limit_mib: 512 + check_interval: 5s # queued_retry: # num_workers: 4 # queue_size: 100 diff --git a/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml b/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml index 3af039268c..c1c046f504 100644 --- a/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml +++ b/deploy/docker/clickhouse-setup/otel-collector-metrics-config.yaml @@ -16,14 +16,14 @@ processors: batch: send_batch_size: 1000 timeout: 10s - # memory_limiter: - # # Same as --mem-ballast-size-mib CLI argument - # ballast_size_mib: 683 - # # 80% of maximum memory up to 2G - # limit_mib: 1500 - # # 25% of limit up to 2G - # spike_limit_mib: 512 - # check_interval: 5s + memory_limiter: + # Same as --mem-ballast-size-mib CLI argument + ballast_size_mib: 683 + # 80% of maximum memory up to 2G + limit_mib: 1500 + # 25% of limit up to 2G + spike_limit_mib: 512 + check_interval: 5s # queued_retry: # num_workers: 4 # queue_size: 100 diff --git a/frontend/package.json b/frontend/package.json index 576a5260f7..4eaf1f5fd8 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -36,7 +36,6 @@ "babel-preset-react-app": "^10.0.0", "chart.js": "^3.4.0", "chartjs-adapter-date-fns": "^2.0.0", - "color": "^4.2.1", "cross-env": "^7.0.3", "css-loader": "4.3.0", "css-minimizer-webpack-plugin": "^3.2.0", @@ -60,7 +59,6 @@ "react-grid-layout": "^1.2.5", "react-redux": "^7.2.2", "react-router-dom": "^5.2.0", - "react-use": "^17.3.2", "react-vis": "^1.11.7", "redux": "^4.0.5", "redux-thunk": "^2.3.0", @@ -95,7 +93,6 @@ "@babel/preset-react": "^7.12.13", "@babel/preset-typescript": "^7.12.17", "@testing-library/cypress": "^8.0.0", - "@types/color": "^3.0.3", "@types/compression-webpack-plugin": "^9.0.0", "@types/copy-webpack-plugin": "^8.0.1", "@types/d3": "^6.2.0", @@ -141,7 +138,6 @@ "prettier": "2.2.1", "react-hot-loader": "^4.13.0", "ts-node": "^10.2.1", - "typescript-plugin-css-modules": "^3.4.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.5.0" } diff --git a/frontend/src/AppRoutes/pageComponents.ts b/frontend/src/AppRoutes/pageComponents.ts index eb7430eb3c..feb99a7c24 100644 --- a/frontend/src/AppRoutes/pageComponents.ts +++ b/frontend/src/AppRoutes/pageComponents.ts @@ -18,12 +18,15 @@ export const ServiceMapPage = Loadable( ), ); -export const TraceFilter = Loadable( - () => import(/* webpackChunkName: "Trace Filter Page" */ 'pages/Trace'), +export const TraceDetailPages = Loadable( + () => import(/* webpackChunkName: "TraceDetailPage" */ 'pages/Trace'), ); -export const TraceDetail = Loadable( - () => import(/* webpackChunkName: "TraceDetail Page" */ 'pages/TraceDetail'), +export const TraceGraphPage = Loadable( + () => + import( + /* webpackChunkName: "TraceGraphPage" */ 'modules/Traces/TraceGraphDef' + ), ); export const UsageExplorerPage = Loadable( diff --git a/frontend/src/AppRoutes/routes.ts b/frontend/src/AppRoutes/routes.ts index fd598b1b2c..d508828dea 100644 --- a/frontend/src/AppRoutes/routes.ts +++ b/frontend/src/AppRoutes/routes.ts @@ -17,8 +17,8 @@ import { ServicesTablePage, SettingsPage, SignupPage, - TraceFilter, - TraceDetail, + TraceDetailPages, + TraceGraphPage, UsageExplorerPage, } from './pageComponents'; @@ -44,9 +44,9 @@ const routes: AppRoutes[] = [ exact: true, }, { - path: ROUTES.TRACE_DETAIL, + path: ROUTES.TRACE_GRAPH, exact: true, - component: TraceDetail, + component: TraceGraphPage, }, { path: ROUTES.SETTINGS, @@ -96,7 +96,7 @@ const routes: AppRoutes[] = [ { path: ROUTES.TRACE, exact: true, - component: TraceFilter, + component: TraceDetailPages, }, { path: ROUTES.CHANNELS_NEW, diff --git a/frontend/src/api/trace/getSpansAggregate.ts b/frontend/src/api/trace/getSpansAggregate.ts index b630e8ce30..1f63f034e4 100644 --- a/frontend/src/api/trace/getSpansAggregate.ts +++ b/frontend/src/api/trace/getSpansAggregate.ts @@ -15,7 +15,6 @@ const getSpanAggregate = async ( end: String(props.end), limit: props.limit, offset: props.offset, - order: props.order, }; const exclude: TraceFilterEnum[] = []; diff --git a/frontend/src/api/trace/getTraceItem.ts b/frontend/src/api/trace/getTraceItem.ts deleted file mode 100644 index 1d00340852..0000000000 --- a/frontend/src/api/trace/getTraceItem.ts +++ /dev/null @@ -1,27 +0,0 @@ -import axios from 'api'; -import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; -import { AxiosError } from 'axios'; -import { ErrorResponse, SuccessResponse } from 'types/api'; -import { Props, PayloadProps } from 'types/api/trace/getTraceItem'; - -const getTraceItem = async ( - props: Props, -): Promise | ErrorResponse> => { - try { - const response = await axios.request({ - url: `/traces/${props.id}`, - method: 'get', - }); - - return { - statusCode: 200, - error: null, - message: 'Success', - payload: response.data, - }; - } catch (error) { - return ErrorResponseHandler(error as AxiosError); - } -}; - -export default getTraceItem; diff --git a/frontend/src/components/NotFound/styles.ts b/frontend/src/components/NotFound/styles.ts index 812fba7f6c..731ab31c2a 100644 --- a/frontend/src/components/NotFound/styles.ts +++ b/frontend/src/components/NotFound/styles.ts @@ -2,6 +2,7 @@ import { Link } from 'react-router-dom'; import styled from 'styled-components'; export const Button = styled(Link)` + height: 100%; border: 2px solid #2f80ed; box-sizing: border-box; border-radius: 10px; diff --git a/frontend/src/constants/routes.ts b/frontend/src/constants/routes.ts index acd95003ea..ed685729dd 100644 --- a/frontend/src/constants/routes.ts +++ b/frontend/src/constants/routes.ts @@ -3,7 +3,7 @@ const ROUTES = { SERVICE_METRICS: '/application/:servicename', SERVICE_MAP: '/service-map', TRACE: '/trace', - TRACE_DETAIL: '/trace/:id', + TRACE_GRAPH: '/trace/:id', SETTINGS: '/settings', INSTRUMENTATION: '/add-instrumentation', USAGE_EXPLORER: '/usage-explorer', diff --git a/frontend/src/container/AppLayout/index.tsx b/frontend/src/container/AppLayout/index.tsx index b5a47f6c5c..407d57e3e8 100644 --- a/frontend/src/container/AppLayout/index.tsx +++ b/frontend/src/container/AppLayout/index.tsx @@ -37,7 +37,7 @@ const AppLayout: React.FC = ({ children }) => { {!isSignUpPage && } {children} - {/*
{`SigNoz Inc. © ${currentYear}`}
*/} +
{`SigNoz Inc. © ${currentYear}`}
); diff --git a/frontend/src/container/AppLayout/styles.ts b/frontend/src/container/AppLayout/styles.ts index 3bbd06db34..8c7098e425 100644 --- a/frontend/src/container/AppLayout/styles.ts +++ b/frontend/src/container/AppLayout/styles.ts @@ -12,8 +12,6 @@ export const Layout = styled(LayoutComponent)` export const Content = styled(LayoutComponent.Content)` &&& { margin: 0 1rem; - display: flex; - flex-direction: column; } `; diff --git a/frontend/src/container/GantChart/SpanLength/index.tsx b/frontend/src/container/GantChart/SpanLength/index.tsx deleted file mode 100644 index 38d6d46b4e..0000000000 --- a/frontend/src/container/GantChart/SpanLength/index.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Tooltip, Typography } from 'antd'; -import React from 'react'; -import { SpanBorder, SpanText, SpanWrapper, SpanLine } from './styles'; -import { toFixed } from 'utils/toFixed' -import { IIntervalUnit, resolveTimeFromInterval } from 'container/TraceDetail/utils'; -import useThemeMode from 'hooks/useThemeMode'; -interface SpanLengthProps { - width: string; - leftOffset: string; - bgColor: string; - toolTipText: string; - id: string; - inMsCount: number; - intervalUnit: IIntervalUnit; -} - -const SpanLength = (props: SpanLengthProps): JSX.Element => { - const { width, leftOffset, bgColor, intervalUnit } = props; - const { isDarkMode } = useThemeMode() - return ( - - - - {`${toFixed(resolveTimeFromInterval(props.inMsCount, intervalUnit), 2)} ${intervalUnit.name}`} - - ); -}; - -export default SpanLength; diff --git a/frontend/src/container/GantChart/SpanLength/styles.ts b/frontend/src/container/GantChart/SpanLength/styles.ts deleted file mode 100644 index 9ee22feab3..0000000000 --- a/frontend/src/container/GantChart/SpanLength/styles.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Typography } from 'antd'; -import styled from 'styled-components'; - -interface Props { - width: string; - leftOffset: string; - bgColor: string; - isDarkMode: boolean; -} - -export const SpanLine = styled.div` - width: ${({ leftOffset }) => `${leftOffset}%`}; - height: 0px; - border-bottom: 0.1px solid - ${({ isDarkMode }) => (isDarkMode ? '#303030' : '#c0c0c0')}; - top: 50%; - position: absolute; -`; -export const SpanBorder = styled.div` - background: ${({ bgColor }) => bgColor}; - border-radius: 5px; - height: 0.625rem; - width: ${({ width }) => `${width}%`}; - left: ${({ leftOffset }) => `${leftOffset}%`}; - top: 35%; - position: absolute; -`; - -export const SpanWrapper = styled.div` - display: flex; - width: 100%; - flex-direction: row; - align-items: center; - position: relative; - z-index: 2; - min-height: 2rem; - - /* &:before { - display: inline-block; - content: ''; - border-bottom: 1px solid #303030; - position: absolute; - left: -30px; - width: 30px; - z-index: 0; - } */ -`; - -export const SpanText = styled(Typography)>` - &&& { - left: ${({ leftOffset }) => `${leftOffset}%`}; - top: 65%; - position: absolute; - color: ${({ isDarkMode }) => (isDarkMode ? '##ACACAC' : '#666')}; - font-size: 0.75rem; - } -`; diff --git a/frontend/src/container/GantChart/SpanName/index.tsx b/frontend/src/container/GantChart/SpanName/index.tsx deleted file mode 100644 index e0614b4600..0000000000 --- a/frontend/src/container/GantChart/SpanName/index.tsx +++ /dev/null @@ -1,30 +0,0 @@ -import React from 'react'; -import { - Service, - Span, - SpanWrapper, - SpanConnector, - Container, - SpanName, -} from './styles'; - -const SpanNameComponent = ({ - name, - serviceName, -}: SpanNameComponent): JSX.Element => { - return ( - - - {name} - {serviceName} - - - ); -}; - -interface SpanNameComponent { - name: string; - serviceName: string; -} - -export default SpanNameComponent; diff --git a/frontend/src/container/GantChart/SpanName/styles.ts b/frontend/src/container/GantChart/SpanName/styles.ts deleted file mode 100644 index b037349d7e..0000000000 --- a/frontend/src/container/GantChart/SpanName/styles.ts +++ /dev/null @@ -1,41 +0,0 @@ -import styled from 'styled-components'; -import { Typography } from 'antd'; - -export const Span = styled(Typography.Paragraph)` - &&& { - font-size: 0.75rem; - margin: 0; - /* border-bottom: 1px solid grey; */ - } -`; - -export const Service = styled(Typography)` - &&& { - color: #acacac; - font-size: 0.75rem; - } -`; - -export const SpanWrapper = styled.div` - display: flex; - flex-direction: column; - margin-left: 0.625rem; - width: 10rem; -`; - -export const SpanConnector = styled.div` - width: 37px; - border: 1px solid #303030; - height: 0; -`; - -export const Container = styled.div` - display: flex; - align-items: center; - justify-content: flex-start; -`; - -export const SpanName = styled.div` - width: fit-content; - border-bottom: 1px solid black; -`; diff --git a/frontend/src/container/GantChart/Trace/index.tsx b/frontend/src/container/GantChart/Trace/index.tsx deleted file mode 100644 index 341500e6fa..0000000000 --- a/frontend/src/container/GantChart/Trace/index.tsx +++ /dev/null @@ -1,186 +0,0 @@ -import React, { useRef, useState, useEffect } from 'react'; - -import { - CardComponent, - CardContainer, - CaretContainer, - Wrapper, - HoverCard, -} from './styles'; -import { CaretDownFilled, CaretRightFilled } from '@ant-design/icons'; -import SpanLength from '../SpanLength'; -import SpanName from '../SpanName'; -import { pushDStree } from 'store/actions'; -import { getMetaDataFromSpanTree, getTopLeftFromBody } from '../utils'; -import { ITraceMetaData } from '..'; -import { Col, Row } from 'antd'; -import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants' -import { IIntervalUnit, resolveTimeFromInterval } from 'container/TraceDetail/utils'; -import useThemeMode from 'hooks/useThemeMode'; - -const Trace = (props: TraceProps): JSX.Element => { - const { - name, - activeHoverId, - setActiveHoverId, - globalSpread, - globalStart, - serviceName, - startTime, - value, - serviceColour, - id, - setActiveSelectedId, - activeSelectedId, - level, - activeSpanPath, - isExpandAll, - intervalUnit, - } = props; - - const { isDarkMode } = useThemeMode() - const [isOpen, setOpen] = useState(activeSpanPath[level] === id); - - useEffect(() => { - if (!isOpen) { - setOpen(activeSpanPath[level] === id) - } - }, [activeSpanPath, isOpen]) - - useEffect(() => { - if (isExpandAll) { - setOpen(isExpandAll) - } - else { - setOpen(activeSpanPath[level] === id) - } - }, [isExpandAll]) - - const isOnlyChild = props.children.length === 1; - const [top, setTop] = useState(0); - - const ref = useRef(null); - - React.useEffect(() => { - if (activeSelectedId === id) { - ref.current?.scrollIntoView({ block: 'nearest', behavior: 'auto', inline: 'nearest' }); - } - }, [activeSelectedId]) - - const onMouseEnterHandler = () => { - setActiveHoverId(props.id); - if (ref.current) { - const { top } = getTopLeftFromBody(ref.current); - setTop(top); - } - }; - - const onMouseLeaveHandler = () => { - setActiveHoverId(''); - }; - - const onClick = () => { - setActiveSelectedId(id); - } - const { totalSpans } = getMetaDataFromSpanTree(props); - - const inMsCount = value; - const nodeLeftOffset = ((startTime - globalStart) * 1e2) / globalSpread; - const width = (value * 1e2) / (globalSpread * 1e6); - const panelWidth = SPAN_DETAILS_LEFT_COL_WIDTH - (level * (16 + 1)) - 16; - - return ( - <> - - - - - - - - {totalSpans !== 1 && ( - { - e.stopPropagation() - setOpen((state) => !state); - }} - > - {totalSpans} - - {isOpen ? : } - - - )} - - - - - - - - - - - - {isOpen && ( - <> - {props.children.map((child) => ( - - ))} - - )} - - - ); -}; - -interface ITraceGlobal { - globalSpread: ITraceMetaData['spread']; - globalStart: ITraceMetaData['globalStart']; -} - -interface TraceProps extends pushDStree, ITraceGlobal { - activeHoverId: string; - setActiveHoverId: React.Dispatch>; - setActiveSelectedId: React.Dispatch>; - activeSelectedId: string; - level: number; - activeSpanPath: string[]; - isExpandAll: boolean; - intervalUnit: IIntervalUnit; -} - -export default Trace; diff --git a/frontend/src/container/GantChart/Trace/styles.ts b/frontend/src/container/GantChart/Trace/styles.ts deleted file mode 100644 index b500db6120..0000000000 --- a/frontend/src/container/GantChart/Trace/styles.ts +++ /dev/null @@ -1,77 +0,0 @@ -import styled, { css } from 'styled-components'; - -interface Props { - isOnlyChild: boolean; -} - -export const Wrapper = styled.ul` - display: flex; - flex-direction: column; - padding-bottom: 0.5rem; - padding-top: 0.5rem; - position: relative; - z-index: 1; - - ul { - border-left: ${({ isOnlyChild }) => isOnlyChild && 'none'} !important; - - ${({ isOnlyChild }) => - isOnlyChild && - css` - &:before { - border-left: 1px solid #434343; - display: inline-block; - content: ''; - height: 54px; - position: absolute; - left: 0; - top: -35px; - } - `} - } -`; - -export const CardContainer = styled.li` - display: flex; - width: 100%; - cursor: pointer; -`; - -export const CardComponent = styled.div` - border: 1px solid ${({ isDarkMode }) => (isDarkMode ? '#434343' : '#333')}; - box-sizing: border-box; - border-radius: 2px; - display: flex; - justify-content: center; - align-items: center; - padding: 1px 8px; - background: ${({ isDarkMode }) => (isDarkMode ? '#1d1d1d' : '#ddd')}; - height: 22px; -`; - -export const CaretContainer = styled.span` - margin-left: 0.304rem; -`; - -interface HoverCardProps { - isHovered: boolean; - isSelected: boolean; - top: number; - isDarkMode: boolean; -} - -export const HoverCard = styled.div` - display: ${({ isSelected, isHovered }) => - isSelected || isHovered ? 'block' : 'none'}; - width: 200%; - background-color: ${({ isHovered, isDarkMode }) => - isHovered && (isDarkMode ? '#262626' : '#ddd')}; - background-color: ${({ isSelected, isDarkMode }) => - isSelected && (isDarkMode ? '#4f4f4f' : '#bbb')}; - position: absolute; - top: 0; - left: -100%; - right: 0; - height: 3rem; - opacity: 0.5; -`; diff --git a/frontend/src/container/GantChart/index.tsx b/frontend/src/container/GantChart/index.tsx deleted file mode 100644 index fa8b37d15a..0000000000 --- a/frontend/src/container/GantChart/index.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import Trace from './Trace'; -import { MinusSquareOutlined, PlusSquareOutlined } from '@ant-design/icons' -import { Wrapper, CardWrapper, CardContainer, CollapseButton } from './styles'; -import { getSpanPath } from './utils'; -import { IIntervalUnit } from 'container/TraceDetail/utils' -import { ITraceTree } from 'types/api/trace/getTraceItem'; - -const GanttChart = (props: GanttChartProps): JSX.Element => { - const { - data, - traceMetaData, - activeHoverId, - setActiveHoverId, - activeSelectedId, - setActiveSelectedId, - spanId, - intervalUnit - } = props; - - const { globalStart, spread: globalSpread } = traceMetaData; - - const [isExpandAll, setIsExpandAll] = useState(false); - const [activeSpanPath, setActiveSpanPath] = useState([]); - - useEffect(() => { - setActiveSpanPath(getSpanPath(data, spanId)) - }, [spanId]); - - useEffect(() => { - setActiveSpanPath(getSpanPath(data, activeSelectedId)) - }, [activeSelectedId]); - - const handleCollapse = () => { - setIsExpandAll((prev) => !prev); - }; - return ( - <> - - - - {isExpandAll ? : } - - - - - - - - ); -}; - -export interface ITraceMetaData { - globalEnd: number; - globalStart: number; - levels: number; - spread: number; - totalSpans: number; -} - -export interface GanttChartProps { - data: ITraceTree; - traceMetaData: ITraceMetaData; - activeSelectedId: string; - activeHoverId: string; - setActiveHoverId: React.Dispatch>; - setActiveSelectedId: React.Dispatch>; - spanId: string; - intervalUnit: IIntervalUnit -} - -export default GanttChart; diff --git a/frontend/src/container/GantChart/styles.ts b/frontend/src/container/GantChart/styles.ts deleted file mode 100644 index cefa618526..0000000000 --- a/frontend/src/container/GantChart/styles.ts +++ /dev/null @@ -1,47 +0,0 @@ -import styled from 'styled-components'; - -export const Wrapper = styled.ul` - padding-left: 0; - position: absolute; - width: 100%; - height: 100%; - - ul { - list-style: none; - border-left: 1px solid #434343; - padding-left: 1rem; - width: 100%; - } - - ul li { - position: relative; - - &:before { - position: absolute; - left: -1rem; - top: 10px; - content: ''; - height: 1px; - width: 1rem; - background-color: #434343; - } - } -`; - -export const CardWrapper = styled.div` - display: flex; - width: 100%; - margin-left: 1rem; - margin-top: 1.5rem; -`; - -export const CardContainer = styled.li` - display: flex; - width: 100%; -`; - -export const CollapseButton = styled.div` - position: absolute; - top: 0; - left: 0; -`; diff --git a/frontend/src/container/GantChart/utils.ts b/frontend/src/container/GantChart/utils.ts deleted file mode 100644 index 8ee9411e05..0000000000 --- a/frontend/src/container/GantChart/utils.ts +++ /dev/null @@ -1,165 +0,0 @@ -import { ITraceTree } from 'types/api/trace/getTraceItem'; - -export const getMetaDataFromSpanTree = (treeData: ITraceTree) => { - let globalStart = Number.POSITIVE_INFINITY; - let globalEnd = Number.NEGATIVE_INFINITY; - let totalSpans = 0; - let levels = 1; - const traverse = (treeNode: ITraceTree, level: number = 0) => { - if (!treeNode) { - return; - } - totalSpans++; - levels = Math.max(levels, level); - const startTime = treeNode.startTime; - const endTime = startTime + treeNode.value; - globalStart = Math.min(globalStart, startTime); - globalEnd = Math.max(globalEnd, endTime); - - for (const childNode of treeNode.children) { - traverse(childNode, level + 1); - } - }; - traverse(treeData, 1); - - globalStart = globalStart * 1e6; - globalEnd = globalEnd * 1e6; - - return { - globalStart, - globalEnd, - spread: globalEnd - globalStart, - totalSpans, - levels, - }; -}; - -export function getTopLeftFromBody(elem: HTMLElement) { - let box = elem.getBoundingClientRect(); - - let body = document.body; - let docEl = document.documentElement; - - let scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop; - let scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft; - - let clientTop = docEl.clientTop || body.clientTop || 0; - let clientLeft = docEl.clientLeft || body.clientLeft || 0; - - let top = box.top + scrollTop - clientTop; - let left = box.left + scrollLeft - clientLeft; - - return { top: Math.round(top), left: Math.round(left) }; -} - -export const getNodeById = ( - searchingId: string, - treeData: ITraceTree, -): ITraceTree | undefined => { - let foundNode: ITraceTree | undefined = undefined; - const traverse = (treeNode: ITraceTree, level: number = 0) => { - if (!treeNode) { - return; - } - - if (searchingId == treeNode.id) { - foundNode = treeNode; - } - - for (const childNode of treeNode.children) { - traverse(childNode, level + 1); - } - }; - traverse(treeData, 1); - - return foundNode; -}; - -const getSpanWithoutChildren = ( - span: ITraceTree, -): Omit => { - return { - id: span.id, - name: span.name, - parent: span.parent, - serviceColour: span.serviceColour, - serviceName: span.serviceName, - startTime: span.startTime, - tags: span.tags, - time: span.time, - value: span.value, - error: span.error, - hasError: span.hasError, - }; -}; - -export const isSpanPresentInSearchString = ( - searchedString: string, - tree: ITraceTree, -): boolean => { - const parsedTree = getSpanWithoutChildren(tree); - - const stringifyTree = JSON.stringify(parsedTree); - - if (stringifyTree.includes(searchedString)) { - return true; - } - return false; -}; - -export const isSpanPresent = ( - tree: ITraceTree, - searchedKey: string, -): ITraceTree[] => { - const foundNode: ITraceTree[] = []; - - const traverse = ( - treeNode: ITraceTree, - level: number = 0, - foundNode: ITraceTree[], - ) => { - if (!treeNode) { - return; - } - - const isPresent = isSpanPresentInSearchString(searchedKey, treeNode); - - if (isPresent) { - foundNode.push(treeNode); - } - - for (const childNode of treeNode.children) { - traverse(childNode, level + 1, foundNode); - } - }; - traverse(tree, 1, foundNode); - - return foundNode; -}; - -export const getSpanPath = (tree: ITraceTree, spanId: string): string[] => { - const spanPath: string[] = []; - - const traverse = (treeNode: ITraceTree) => { - if (!treeNode) { - return false; - } - - spanPath.push(treeNode.id); - - if (spanId === treeNode.id) { - return true; - } - - let foundInChild = false; - for (const childNode of treeNode.children) { - if (traverse(childNode)) foundInChild = true; - } - if (!foundInChild) { - spanPath.pop(); - } - return foundInChild; - }; - traverse(tree); - return spanPath; -}; diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx index 5da66f3394..61aae23128 100644 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx @@ -16,7 +16,6 @@ import getChartData from 'lib/getChartData'; import GetMaxMinTime from 'lib/getMaxMinTime'; import GetMinMax from 'lib/getMinMax'; import getStartAndEndTime from 'lib/getStartAndEndTime'; -import getStep from 'lib/getStep'; import React, { useCallback, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; @@ -91,11 +90,7 @@ const FullView = ({ end: queryMinMax.max.toString(), query: query.query, start: queryMinMax.min.toString(), - step: `${getStep({ - start: queryMinMax.min, - end: queryMinMax.max, - inputFormat: 's', - })}`, + step: '60', }); return { query: query.query, diff --git a/frontend/src/container/Header/index.tsx b/frontend/src/container/Header/index.tsx index a9636c0b9f..8884b2231b 100644 --- a/frontend/src/container/Header/index.tsx +++ b/frontend/src/container/Header/index.tsx @@ -11,7 +11,7 @@ import { Container } from './styles'; const routesToSkip = [ ROUTES.SETTINGS, ROUTES.LIST_ALL_ALERT, - ROUTES.TRACE_DETAIL, + ROUTES.TRACE_GRAPH, ]; const TopNav = (): JSX.Element | null => { diff --git a/frontend/src/container/SideNav/index.tsx b/frontend/src/container/SideNav/index.tsx index 93c618205b..6e203d4ab2 100644 --- a/frontend/src/container/SideNav/index.tsx +++ b/frontend/src/container/SideNav/index.tsx @@ -1,5 +1,10 @@ import { Menu, Typography } from 'antd'; -import { SlackButton, SlackMenuItemContainer, ToggleButton } from './styles'; +import { + MenuItem, + SlackButton, + SlackMenuItemContainer, + ToggleButton, +} from './styles'; import ROUTES from 'constants/routes'; import history from 'lib/history'; import React, { useCallback, useState } from 'react'; @@ -12,6 +17,7 @@ import { ToggleDarkMode } from 'store/actions'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import AppReducer from 'types/reducer/app'; +import getTheme from 'lib/theme/getTheme'; import setTheme from 'lib/theme/setTheme'; import menus from './menuItems'; @@ -89,10 +95,11 @@ const SideNav = ({ toggleDarkMode }: Props): JSX.Element => { {name} ))} + - }> + }> Support - + diff --git a/frontend/src/container/SideNav/styles.ts b/frontend/src/container/SideNav/styles.ts index 534d02183a..2b75d0dc5a 100644 --- a/frontend/src/container/SideNav/styles.ts +++ b/frontend/src/container/SideNav/styles.ts @@ -20,7 +20,6 @@ interface LogoProps { } export const Sider = styled(SiderComponent)` - z-index: 999; .ant-typography { color: white; } @@ -46,12 +45,17 @@ export const SlackButton = styled(Typography)` } `; -export const SlackMenuItemContainer = styled.div` - position: fixed; - bottom: 48px; - background: #262626; - width: ${({ collapsed }) => (!collapsed ? '200px' : '80px')}; +export const MenuItem = styled(Menu.Item)` + &&& { + position: fixed; + bottom: 48px; + width: 100%; + height: 48px; + background: #262626; + } +`; +export const SlackMenuItemContainer = styled.div` &&& { li { ${({ collapsed }) => diff --git a/frontend/src/container/Timeline/index.tsx b/frontend/src/container/Timeline/index.tsx deleted file mode 100644 index c729ac15f0..0000000000 --- a/frontend/src/container/Timeline/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import React, { useState, useMemo } from 'react'; -import { isEqual } from 'lodash-es'; -import styles from './style.module.css'; -import { useMeasure } from 'react-use'; -import { toFixed } from 'utils/toFixed'; -import { - INTERVAL_UNITS, - resolveTimeFromInterval, -} from 'container/TraceDetail/utils'; -import useThemeMode from 'hooks/useThemeMode'; -import { Interval } from './types'; -import { getIntervalSpread, getIntervals } from './utils'; -interface TimelineProps { - traceMetaData: object; - globalTraceMetadata: object; - intervalUnit: object; - setIntervalUnit: Function; -} -const Timeline = ({ - traceMetaData, - globalTraceMetadata, - intervalUnit, - setIntervalUnit, -}: TimelineProps) => { - const [ref, { width }] = useMeasure(); - const { isDarkMode } = useThemeMode(); - - const Timeline_Height = 22; - const Timeline_H_Spacing = 0; - - const [intervals, setIntervals] = useState(null); - - useMemo(() => { - const { - baseInterval, - baseSpread, - intervalSpreadNormalized, - } = getIntervalSpread({ - globalTraceMetadata: globalTraceMetadata, - localTraceMetaData: traceMetaData, - }); - - let intervalUnit = INTERVAL_UNITS[0]; - for (const idx in INTERVAL_UNITS) { - const standard_interval = INTERVAL_UNITS[idx]; - if (baseSpread * standard_interval.multiplier < 1) { - intervalUnit = INTERVAL_UNITS[idx - 1]; - break; - } - } - - setIntervalUnit(intervalUnit); - setIntervals( - getIntervals({ - baseInterval, - baseSpread, - intervalSpreadNormalized, - intervalUnit, - }), - ); - }, [traceMetaData, globalTraceMetadata]); - - return ( -
- - - {intervals && - intervals.map((interval, index) => ( - - - {interval.label} - - - - ))} - -
- ); -}; - -export default Timeline; diff --git a/frontend/src/container/Timeline/style.module.css b/frontend/src/container/Timeline/style.module.css deleted file mode 100644 index 2ddc6e497f..0000000000 --- a/frontend/src/container/Timeline/style.module.css +++ /dev/null @@ -1,8 +0,0 @@ -.svg-container { - overflow: visible; - position: absolute; -} -.timeline-tick { - text-anchor: middle; - font-size: 0.6rem; -} diff --git a/frontend/src/container/Timeline/types.ts b/frontend/src/container/Timeline/types.ts deleted file mode 100644 index b4cc4cee9a..0000000000 --- a/frontend/src/container/Timeline/types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface Interval { - label: string; - percentage: number; -} diff --git a/frontend/src/container/Timeline/utils.ts b/frontend/src/container/Timeline/utils.ts deleted file mode 100644 index e7e6a79a01..0000000000 --- a/frontend/src/container/Timeline/utils.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { isEqual } from 'lodash-es'; -import { toFixed } from 'utils/toFixed'; -import { - INTERVAL_UNITS, - resolveTimeFromInterval, -} from 'container/TraceDetail/utils'; - -export const getIntervalSpread = ({ - localTraceMetaData, - globalTraceMetadata, -}) => { - const { - globalStart: localStart, - globalEnd: localEnd, - spread: localSpread, - } = localTraceMetaData; - const { globalStart, globalEnd, globalSpread } = globalTraceMetadata; - - let baseInterval = 0; - - if (!isEqual(localTraceMetaData, globalTraceMetadata)) { - baseInterval = localStart - globalStart; - } - - const MIN_INTERVALS = 5; - const baseSpread = localSpread; - let intervalSpread = (baseSpread / MIN_INTERVALS) * 1.0; - const integerPartString = intervalSpread.toString().split('.')[0]; - const integerPartLength = integerPartString.length; - const intervalSpreadNormalized = - intervalSpread < 1.0 - ? intervalSpread - : Math.floor( - Number(integerPartString) / Math.pow(10, integerPartLength - 1), - ) * Math.pow(10, integerPartLength - 1); - return { - baseInterval, - baseSpread, - intervalSpreadNormalized, - }; -}; - -export const getIntervals = ({ - baseInterval, - baseSpread, - intervalSpreadNormalized, - intervalUnit, -}) => { - const intervals: Interval[] = [ - { - label: `${toFixed(resolveTimeFromInterval(baseInterval, intervalUnit), 2)}${ - intervalUnit.name - }`, - percentage: 0, - }, - ]; - - let tempBaseSpread = baseSpread; - let elapsedIntervals = 0; - - while (tempBaseSpread && intervals.length < 20) { - let interval_time; - if (tempBaseSpread <= 1.5 * intervalSpreadNormalized) { - interval_time = elapsedIntervals + tempBaseSpread; - tempBaseSpread = 0; - } else { - interval_time = elapsedIntervals + intervalSpreadNormalized; - tempBaseSpread -= intervalSpreadNormalized; - } - elapsedIntervals = interval_time; - - const interval: Interval = { - label: `${toFixed( - resolveTimeFromInterval(interval_time + baseInterval, intervalUnit), - 2, - )}${intervalUnit.name}`, - percentage: (interval_time / baseSpread) * 100, - }; - intervals.push(interval); - } - - return intervals; -}; diff --git a/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx b/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx index f8072ab895..a377de487f 100644 --- a/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx +++ b/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx @@ -75,7 +75,7 @@ const SingleTags = (props: AllTagsProps): JSX.Element => { value={AllMenu.find((e) => e.key === selectedOperator)?.value || ''} > {AllMenu.map((e) => ( - ))} diff --git a/frontend/src/container/Trace/Search/util.ts b/frontend/src/container/Trace/Search/util.ts index 91e235b4a1..d74a133229 100644 --- a/frontend/src/container/Trace/Search/util.ts +++ b/frontend/src/container/Trace/Search/util.ts @@ -13,14 +13,14 @@ export const parseQueryToTags = (query: string): PayloadProps => { const noOfTags = query.split(' AND '); const tags: Tags = noOfTags.map((filter) => { - const isInPresent = filter.includes('in'); - const isNotInPresent = filter.includes('not in'); + const isInPresent = filter.includes('IN'); + const isNotInPresent = filter.includes('NOT_IN'); - if (!isNotInPresent && !isInPresent) { + if (!isNotInPresent || !isInPresent) { isError = true; } - const splitBy = isNotInPresent ? 'not in' : isInPresent ? 'in' : ''; + const splitBy = isNotInPresent ? 'NOT_IN' : isInPresent ? 'IN' : ''; if (splitBy.length === 0) { isError = true; @@ -40,15 +40,13 @@ export const parseQueryToTags = (query: string): PayloadProps => { const removingFirstAndLastBrackets = `${filterForTags?.slice(1, -1)}`; - const noofFilters = removingFirstAndLastBrackets - .split(',') - .map((e) => e.replaceAll(/"/g, '')); + const noofFilters = removingFirstAndLastBrackets.split(','); noofFilters.forEach((e) => { const firstChar = e.charAt(0); const lastChar = e.charAt(e.length - 1); - if (firstChar === '"' && lastChar === '"') { + if (!(firstChar === '"' && lastChar === '"')) { isError = true; } }); @@ -75,9 +73,7 @@ export const parseTagsToQuery = (tags: Tags): PayloadProps => { isError = true; } - return `${Key[0]} ${Operator} (${Values.map((e) => { - return `"${e.replaceAll(/"/g, '')}"`; - }).join(',')})`; + return `${Key[0]} ${Operator} (${Values.map((e) => `"${e}"`).join(',')})`; }) .join(' AND '); diff --git a/frontend/src/container/Trace/TraceGraphFilter/config.ts b/frontend/src/container/Trace/TraceGraphFilter/config.ts index 0c97ca78d5..5d7a942b35 100644 --- a/frontend/src/container/Trace/TraceGraphFilter/config.ts +++ b/frontend/src/container/Trace/TraceGraphFilter/config.ts @@ -77,7 +77,7 @@ export const functions: Dropdown[] = [ key: 'p50', }, { - displayValue: '90th percentile(duration in ns)', + displayValue: '90th percentile(duration in ns', key: 'p90', }, { diff --git a/frontend/src/container/Trace/TraceTable/index.tsx b/frontend/src/container/Trace/TraceTable/index.tsx index 9a1155a5c7..919f680778 100644 --- a/frontend/src/container/Trace/TraceTable/index.tsx +++ b/frontend/src/container/Trace/TraceTable/index.tsx @@ -1,24 +1,26 @@ -import { TableProps, Tag } from 'antd'; -import Table, { ColumnsType } from 'antd/lib/table'; -import ROUTES from 'constants/routes'; -import dayjs from 'dayjs'; -import duration from 'dayjs/plugin/duration'; -import history from 'lib/history'; import React from 'react'; + +import Table, { ColumnsType } from 'antd/lib/table'; +import { TableProps, Tag } from 'antd'; + import { connect, useSelector } from 'react-redux'; +import { AppState } from 'store/reducers'; +import { TraceReducer } from 'types/reducer/trace'; import { bindActionCreators } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; +import AppActions from 'types/actions'; import { GetSpansAggregate, GetSpansAggregateProps, } from 'store/actions/trace/getInitialSpansAggregate'; -import { AppState } from 'store/reducers'; -import AppActions from 'types/actions'; import { GlobalReducer } from 'types/reducer/globalTime'; -import { TraceReducer } from 'types/reducer/trace'; +import dayjs from 'dayjs'; +import duration from 'dayjs/plugin/duration'; +import history from 'lib/history'; +import ROUTES from 'constants/routes'; dayjs.extend(duration); -const TraceTable = ({ getSpansAggregate }: TraceProps): JSX.Element => { +const TraceTable = ({ getSpansAggregate }: TraceProps) => { const { spansAggregate, selectedFilter, @@ -39,16 +41,17 @@ const TraceTable = ({ getSpansAggregate }: TraceProps): JSX.Element => { title: 'Date', dataIndex: 'timestamp', key: 'timestamp', - sorter: true, - render: (value: TableType['timestamp']): JSX.Element => { + render: (value: TableType['timestamp']) => { const day = dayjs(value); return
{day.format('DD/MM/YYYY hh:mm:ss A')}
; }, + sorter: (a, b) => dayjs(a.timestamp).diff(dayjs(b.timestamp)), }, { title: 'Service', dataIndex: 'serviceName', key: 'serviceName', + sorter: (a, b) => a.serviceName.length - b.serviceName.length, }, { title: 'Operation', @@ -59,19 +62,22 @@ const TraceTable = ({ getSpansAggregate }: TraceProps): JSX.Element => { title: 'Duration', dataIndex: 'durationNano', key: 'durationNano', - render: (value: TableType['durationNano']): JSX.Element => ( -
- {`${dayjs - .duration({ milliseconds: value / 1000000 }) - .asMilliseconds()} ms`} -
- ), + sorter: (a, b) => a.durationNano - b.durationNano, + render: (value: TableType['durationNano']) => { + return ( +
+ {`${dayjs + .duration({ milliseconds: value / 1000000 }) + .asMilliseconds()} ms`} +
+ ); + }, }, { title: 'Method', dataIndex: 'httpMethod', key: 'httpMethod', - render: (value: TableType['httpMethod']): JSX.Element => { + render: (value: TableType['httpMethod']) => { if (value.length === 0) { return
-
; } @@ -82,7 +88,8 @@ const TraceTable = ({ getSpansAggregate }: TraceProps): JSX.Element => { title: 'Status Code', dataIndex: 'httpCode', key: 'httpCode', - render: (value: TableType['httpCode']): JSX.Element => { + sorter: (a, b) => a.httpCode.length - b.httpCode.length, + render: (value: TableType['httpCode']) => { if (value.length === 0) { return
-
; } @@ -91,13 +98,7 @@ const TraceTable = ({ getSpansAggregate }: TraceProps): JSX.Element => { }, ]; - const onChangeHandler: TableProps['onChange'] = ( - props, - _, - sort, - ) => { - const { order = 'ascend' } = sort; - + const onChangeHandler: TableProps['onChange'] = (props) => { if (props.current && props.pageSize) { getSpansAggregate({ maxTime: globalTime.maxTime, @@ -106,7 +107,6 @@ const TraceTable = ({ getSpansAggregate }: TraceProps): JSX.Element => { current: props.current, pageSize: props.pageSize, selectedTags, - order: order === 'ascend' ? 'ascending' : 'descending', }); } }; @@ -118,10 +118,12 @@ const TraceTable = ({ getSpansAggregate }: TraceProps): JSX.Element => { loading={loading || filterLoading} columns={columns} onRow={(record) => ({ - onClick: (): void => { + onClick: () => { history.push({ pathname: ROUTES.TRACE + '/' + record.traceID, - search: '?' + 'spanId=' + record.spanID, + state: { + spanId: record.spanID, + }, }); }, })} diff --git a/frontend/src/container/TraceDetail/SelectedSpanDetails/ErrorTag.tsx b/frontend/src/container/TraceDetail/SelectedSpanDetails/ErrorTag.tsx deleted file mode 100644 index ebe2ea2559..0000000000 --- a/frontend/src/container/TraceDetail/SelectedSpanDetails/ErrorTag.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import { Button, Modal, Collapse } from 'antd'; -import useThemeMode from 'hooks/useThemeMode'; -import React, { useRef, useState } from 'react'; -import { ITraceTree } from 'types/api/trace/getTraceItem'; -import { CustomSubText, CustomSubTitle } from './styles'; -// import Editor from 'components/Editor'; - -const { Panel } = Collapse; - -const ErrorTag = ({ event }: ErrorTagProps) => { - const [isOpen, setIsOpen] = useState(false); - const { isDarkMode } = useThemeMode(); - // const useTextRef = useRef(''); - - const [text, setText] = useState({ - text: '', - subText: '', - }); - - const onToggleHandler = (state: boolean) => { - setIsOpen(state); - }; - - return ( - <> - {event?.map(({ attributeMap, name }) => { - const attributes = Object.keys(attributeMap); - - return ( - - - {attributes.map((event) => { - const value = attributeMap[event]; - const isEllipsed = value.length > 24; - - return ( - <> - {event} - - {value} -
- {isEllipsed && ( - - )} -
- - - - ); - })} -
-
- ); - })} - onToggleHandler(false)} - title="Log Message" - visible={isOpen} - destroyOnClose - footer={[]} - > - {text.text} - - {text.subText} - - - - ); -}; - -interface ErrorTagProps { - event: ITraceTree['event']; -} - -export default ErrorTag; diff --git a/frontend/src/container/TraceDetail/SelectedSpanDetails/index.tsx b/frontend/src/container/TraceDetail/SelectedSpanDetails/index.tsx deleted file mode 100644 index 35ed013d9c..0000000000 --- a/frontend/src/container/TraceDetail/SelectedSpanDetails/index.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import { Space, Tabs, Typography } from 'antd'; -import React from 'react'; -import { ITraceTree } from 'types/api/trace/getTraceItem'; -import { - CardContainer, - CustomSubText, - CustomSubTitle, - CustomText, - CustomTitle, -} from './styles'; -import ErrorTag from './ErrorTag'; -import useThemeMode from 'hooks/useThemeMode'; - -const { TabPane } = Tabs; - -const SelectedSpanDetails = (props: SelectedSpanDetailsProps): JSX.Element => { - const { tree } = props; - const { isDarkMode } = useThemeMode(); - if (!tree) { - return <>; - } - - const { name, tags, serviceName } = tree; - - return ( - - - Details for selected Span - - Service - {serviceName} - - - Operation - {name} - - - - - {tags.length !== 0 ? ( - tags.map((tags) => { - return ( - - {tags.value && ( - <> - {tags.key} - - {tags.key === 'error' ? 'true' : tags.value} - - - )} - - ); - }) - ) : ( - No tags in selected span - )} - - - {tree.event && Object.keys(tree.event).length !== 0 ? ( - - ) : ( - No events data in selected span - )} - - - - ); -}; - -interface SelectedSpanDetailsProps { - tree?: ITraceTree; -} - -export default SelectedSpanDetails; diff --git a/frontend/src/container/TraceDetail/SelectedSpanDetails/styles.ts b/frontend/src/container/TraceDetail/SelectedSpanDetails/styles.ts deleted file mode 100644 index f467a87b35..0000000000 --- a/frontend/src/container/TraceDetail/SelectedSpanDetails/styles.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { Typography } from 'antd'; -import styled from 'styled-components'; -const { Text, Title, Paragraph } = Typography; - -export const CustomTitle = styled(Title)` - &&& { - font-size: 14px; - } -`; - -export const CustomText = styled(Text)` - &&& { - color: #2d9cdb; - } -`; - -export const CustomSubTitle = styled(Title)` - &&& { - /* color: #bdbdbd; */ - font-size: 14px; - margin-bottom: 8px; - } -`; - -interface CustomSubTextProps { - isDarkMode: boolean; -} - -export const CustomSubText = styled(Paragraph)` - &&& { - background: ${({ isDarkMode }) => (isDarkMode ? '#444' : '#ddd')}; - font-size: 12px; - padding: 6px 8px; - word-break: break-all; - margin-bottom: 16px; - } -`; - -export const CardContainer = styled.div` - margin: 0 0.5rem; - position: absolute; - height: 100%; - width: 100%; - flex: 1; - overflow-y: auto; -`; diff --git a/frontend/src/container/TraceDetail/TraceGraph.module.css b/frontend/src/container/TraceDetail/TraceGraph.module.css deleted file mode 100644 index 9127050c97..0000000000 --- a/frontend/src/container/TraceDetail/TraceGraph.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.trace-detail-content-spacing { - margin-right: 1rem; -} diff --git a/frontend/src/container/TraceDetail/index.tsx b/frontend/src/container/TraceDetail/index.tsx deleted file mode 100644 index 99d693fc85..0000000000 --- a/frontend/src/container/TraceDetail/index.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import { Col, Divider, Row, Typography, Space, Button } from 'antd'; -import { FilterOutlined } from '@ant-design/icons'; -import GanttChart from 'container/GantChart'; -import { getNodeById } from 'container/GantChart/utils'; -import Timeline from 'container/Timeline'; -import TraceFlameGraph from 'container/TraceFlameGraph'; -import dayjs from 'dayjs'; -import { spanServiceNameToColorMapping } from 'lib/getRandomColor'; -import { getSortedData } from './utils'; -import { ITraceTree, PayloadProps } from 'types/api/trace/getTraceItem'; -import { getSpanTreeMetadata } from 'utils/getSpanTreeMetadata'; -import { spanToTreeUtil } from 'utils/spanToTree'; -import SelectedSpanDetails from './SelectedSpanDetails'; -import useUrlQuery from 'hooks/useUrlQuery'; -import styles from './TraceGraph.module.css'; -import history from 'lib/history'; -import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants'; -import { INTERVAL_UNITS } from './utils'; - -const TraceDetail = ({ response }: TraceDetailProps): JSX.Element => { - const spanServiceColors = useMemo( - () => spanServiceNameToColorMapping(response[0].events), - [response], - ); - - const urlQuery = useUrlQuery(); - const [spanId, _setSpanId] = useState(urlQuery.get('spanId')); - - const [intervalUnit, setIntervalUnit] = useState(INTERVAL_UNITS[0]); - const [searchSpanString, setSearchSpanString] = useState(''); - const [activeHoverId, setActiveHoverId] = useState(''); - const [activeSelectedId, setActiveSelectedId] = useState(spanId || ''); - - const [treeData, setTreeData] = useState( - spanToTreeUtil(response[0].events), - ); - - const { treeData: tree, ...traceMetaData } = useMemo(() => { - return getSpanTreeMetadata(getSortedData(treeData), spanServiceColors); - }, [treeData]); - - const [globalTraceMetadata, _setGlobalTraceMetadata] = useState({ - ...traceMetaData, - }); - - useEffect(() => { - if (activeSelectedId) { - history.replace({ - pathname: history.location.pathname, - search: `?spanId=${activeSelectedId}`, - }); - } - }, [activeSelectedId]); - - const getSelectedNode = useMemo(() => { - return getNodeById(activeSelectedId, treeData); - }, [activeSelectedId, treeData]); - - const onSearchHandler = (value: string) => { - setSearchSpanString(value); - setTreeData(spanToTreeUtil(response[0].events)); - }; - const onFocusSelectedSpanHandler = () => { - const treeNode = getNodeById(activeSelectedId, tree); - if (treeNode) { - setTreeData(treeNode); - } - }; - - const onResetHandler = () => { - setTreeData(spanToTreeUtil(response[0].events)); - }; - - return ( - - - - - - Trace Details - - - {traceMetaData.totalSpans} Span - - - - - - - - - {dayjs(traceMetaData.globalStart / 1e6).format('hh:mm:ssa MM/DD')} - - - - - - - - - {/* */} - - - - - - - - -
- -
- - - - - - - -
- ); -}; - -interface TraceDetailProps { - response: PayloadProps; -} - -export default TraceDetail; diff --git a/frontend/src/container/TraceDetail/utils.ts b/frontend/src/container/TraceDetail/utils.ts deleted file mode 100644 index c92e6b37bb..0000000000 --- a/frontend/src/container/TraceDetail/utils.ts +++ /dev/null @@ -1,57 +0,0 @@ -/** - * string is present on the span or not - */ -import { ITraceTree, Span } from 'types/api/trace/getTraceItem'; -import { sortBy } from 'lodash-es'; - -export const filterSpansByString = ( - searchString: string, - spans: Span[], -): Span[] => - spans.filter((span) => { - const spanWithoutChildren = [...span].slice(0, 11); - return JSON.stringify(spanWithoutChildren).includes(searchString); - }); - -export interface IIntervalUnit { - name: 'ms' | 's' | 'm'; - multiplier: number; -} -export const INTERVAL_UNITS: IIntervalUnit[] = [ - { - name: 'ms', - multiplier: 1, - }, - { - name: 's', - multiplier: 1 / 1e3, - }, - { - name: 'm', - multiplier: 1 / (1e3 * 60), - }, -]; - -export const resolveTimeFromInterval = ( - intervalTime: number, - intervalUnit: IIntervalUnit, -) => { - return intervalTime * intervalUnit.multiplier; -}; - -export const getSortedData = (treeData: ITraceTree) => { - const traverse = (treeNode: ITraceTree, level: number = 0) => { - if (!treeNode) { - return; - } - - treeNode.children = sortBy(treeNode.children, (e) => e.startTime); - - for (const childNode of treeNode.children) { - traverse(childNode, level + 1); - } - }; - traverse(treeData, 1); - - return treeData; -}; diff --git a/frontend/src/container/TraceFlameGraph/__tests__/TraceFlameGraph.test.tsx b/frontend/src/container/TraceFlameGraph/__tests__/TraceFlameGraph.test.tsx deleted file mode 100644 index 74c17c3139..0000000000 --- a/frontend/src/container/TraceFlameGraph/__tests__/TraceFlameGraph.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { expect } from '@jest/globals'; -import React from 'react'; -import { render } from '@testing-library/react'; -import TraceFlameGraph from 'container/TraceFlameGraph'; - -test('loads and displays greeting', async () => { - const { asFragment } = render(); - expect(asFragment()).toMatchSnapshot(); -}); diff --git a/frontend/src/container/TraceFlameGraph/__tests__/__snapshots__/TraceFlameGraph.test.tsx.snap b/frontend/src/container/TraceFlameGraph/__tests__/__snapshots__/TraceFlameGraph.test.tsx.snap deleted file mode 100644 index ec5ff7b75b..0000000000 --- a/frontend/src/container/TraceFlameGraph/__tests__/__snapshots__/TraceFlameGraph.test.tsx.snap +++ /dev/null @@ -1,3 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`loads and displays greeting 1`] = ``; diff --git a/frontend/src/container/TraceFlameGraph/index.tsx b/frontend/src/container/TraceFlameGraph/index.tsx deleted file mode 100644 index 511becaf39..0000000000 --- a/frontend/src/container/TraceFlameGraph/index.tsx +++ /dev/null @@ -1,183 +0,0 @@ -import React, { useState, useLayoutEffect, useMemo } from 'react'; -import Color from 'color'; -import { pushDStree } from 'store/actions'; -import { - SpanItemContainer, - TraceFlameGraphContainer, - TOTAL_SPAN_HEIGHT, -} from './styles'; -import { - IIntervalUnit, - resolveTimeFromInterval, -} from 'container/TraceDetail/utils'; -import { toFixed } from 'utils/toFixed'; -import useThemeMode from 'hooks/useThemeMode'; - -const SpanItem = ({ - topOffset = 0, // top offset in px - leftOffset = 0, // left offset in % - width = 10, // width in % - spanData, - tooltipText, - onSpanSelect, // function which gets invoked on clicking span - onSpanHover, - hoveredSpanId, - selectedSpanId, -}: { - topOffset: number; - leftOffset: number; - width: number; - spanData: pushDStree; - tooltipText: string; - onSpanSelect: Function; - onSpanHover: Function; - hoveredSpanId: string; - selectedSpanId: string; -}) => { - const { serviceColour } = spanData; - const [isSelected, setIsSelected] = useState(false); - const [isLocalHover, setIsLocalHover] = useState(false); - const { isDarkMode } = useThemeMode(); - - useLayoutEffect(() => { - if ( - !isSelected && - (spanData.id === hoveredSpanId || spanData.id === selectedSpanId) - ) { - setIsSelected(true); - } - }, [hoveredSpanId, selectedSpanId]); - - const handleHover = (hoverState: boolean) => { - setIsLocalHover(hoverState); - - if (hoverState) onSpanHover(spanData.id); - else onSpanHover(null); - }; - - const handleClick = () => { - onSpanSelect(spanData.id); - }; - - const spanColor = useMemo((): string => { - const selectedSpanColor = isDarkMode - ? Color(serviceColour).lighten(0.3) - : Color(serviceColour).darken(0.3); - return `${isSelected ? selectedSpanColor : serviceColour}`; - }, [isSelected, serviceColour]); - - return ( - <> - { - handleHover(true); - }} - onMouseLeave={() => { - handleHover(false); - }} - topOffset={topOffset} - leftOffset={leftOffset} - width={width} - spanColor={spanColor} - selected={isSelected} - zIdx={isSelected ? 1 : 0} - > - - ); -}; - -const TraceFlameGraph = (props: { - treeData: pushDStree; - traceMetaData: any; - onSpanHover: Function; - onSpanSelect: Function; - hoveredSpanId: string; - selectedSpanId: string; - intervalUnit: IIntervalUnit; -}) => { - if (!props.treeData || props.treeData.id === 'empty' || !props.traceMetaData) { - return null; - } - const { intervalUnit } = props; - - const { - globalStart, - globalEnd, - spread, - totalSpans, - levels, - } = props.traceMetaData; - const RenderSpanRecursive = ({ - level = 0, - spanData, - parentLeftOffset = 0, - onSpanHover, - onSpanSelect, - hoveredSpanId, - selectedSpanId, - }: { - spanData: pushDStree; - level?: number; - parentLeftOffset?: number; - onSpanHover: Function; - onSpanSelect: Function; - hoveredSpanId: string; - selectedSpanId: string; - }) => { - if (!spanData) { - return null; - } - - const leftOffset = ((spanData.startTime - globalStart) * 100) / spread; - const width = ((spanData.value / 1e6) * 100) / spread; - const toolTipText = `${spanData.name}\n${toFixed( - resolveTimeFromInterval(spanData.value / 1e6, intervalUnit), - 2, - )} ${intervalUnit.name}`; - - return ( - <> - - {spanData.children.map((childData) => ( - - ))} - - ); - }; - return ( - <> - - - - - ); -}; - -export default TraceFlameGraph; diff --git a/frontend/src/container/TraceFlameGraph/styles.ts b/frontend/src/container/TraceFlameGraph/styles.ts deleted file mode 100644 index ad262421cd..0000000000 --- a/frontend/src/container/TraceFlameGraph/styles.ts +++ /dev/null @@ -1,38 +0,0 @@ -import styled from 'styled-components'; - -const SPAN_HEIGHT = 10; -const SPAN_V_PADDING = 1; -export const TOTAL_SPAN_HEIGHT = SPAN_HEIGHT + 2 * SPAN_V_PADDING; - -/** - * An individual span for traces flame graph - */ -export const SpanItemContainer = styled.div<{ - topOffset: number; - leftOffset: number; - width: number; - spanColor: string; - selected: boolean; - zIdx: number; -}>` - position: absolute; - top: ${(props) => props.topOffset}px; - left: ${(props) => props.leftOffset}%; - width: ${(props) => props.width}%; - height: ${SPAN_HEIGHT}px; - margin: ${SPAN_V_PADDING}px 0; - background-color: ${({ spanColor }) => spanColor}; - border-radius: ${SPAN_HEIGHT / 2}px; - z-index: ${(props) => props.zIdx}; -`; - -/** - * Container for spans, for traces flame graph. - */ -export const TraceFlameGraphContainer = styled.div<{ - height: number; -}>` - position: relative; - width: 100%; - height: ${({ height }) => (height ? height : 120)}px; -`; diff --git a/frontend/src/hooks/useThemeMode.ts b/frontend/src/hooks/useThemeMode.ts deleted file mode 100644 index 496ea82904..0000000000 --- a/frontend/src/hooks/useThemeMode.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { useSelector } from 'react-redux'; -import { AppState } from 'store/reducers'; -import AppReducer from 'types/reducer/app'; - -export interface IUseThemeModeReturn { - isDarkMode: boolean; -} - -const useThemeMode = () => { - const { isDarkMode } = useSelector((state) => state.app); - - return { isDarkMode }; -}; - -export default useThemeMode; diff --git a/frontend/src/hooks/useUrlQuery.ts b/frontend/src/hooks/useUrlQuery.ts deleted file mode 100644 index 6f20744a2d..0000000000 --- a/frontend/src/hooks/useUrlQuery.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { useMemo } from 'react'; -import { useLocation } from 'react-router-dom'; - -function useUrlQuery() { - const { search } = useLocation(); - - return useMemo(() => new URLSearchParams(search), [search]); -} - -export default useUrlQuery; diff --git a/frontend/src/lib/__tests__/getStep.test.ts b/frontend/src/lib/__tests__/getStep.test.ts deleted file mode 100644 index 638c21cf4e..0000000000 --- a/frontend/src/lib/__tests__/getStep.test.ts +++ /dev/null @@ -1,67 +0,0 @@ -import dayjs from 'dayjs'; -import getStep, { DefaultStepSize } from 'lib/getStep'; - -describe('lib/getStep', () => { - test('should return default step when the given range is less than 1 day', () => { - const start = dayjs(); - const end = start.add(1, 'hour'); - const startUnix = start.valueOf(); - const endUnix = end.valueOf(); - - expect( - getStep({ - start: startUnix / 1e3, - end: endUnix / 1e3, - inputFormat: 's', - }), - ).toEqual(DefaultStepSize); - - expect( - getStep({ - start: startUnix, - end: endUnix, - inputFormat: 'ms', - }), - ).toEqual(DefaultStepSize); - - expect( - getStep({ - start: startUnix * 1e6, - end: endUnix * 1e6, - inputFormat: 'ns', - }), - ).toEqual(DefaultStepSize); - }); - - test('should return relevant step when the given range is greater than 1 day', () => { - const start = dayjs(); - const end = start.add(1, 'Day').add(1, 'Second'); - const startUnix = start.valueOf(); - const endUnix = end.valueOf(); - - const expectedStepSize = end.diff(start, 'days') * DefaultStepSize; - expect( - getStep({ - start: startUnix / 1e3, - end: endUnix / 1e3, - inputFormat: 's', - }), - ).toEqual(expectedStepSize); - - expect( - getStep({ - start: startUnix, - end: endUnix, - inputFormat: 'ms', - }), - ).toEqual(expectedStepSize); - - expect( - getStep({ - start: startUnix * 1e6, - end: endUnix * 1e6, - inputFormat: 'ns', - }), - ).toEqual(expectedStepSize); - }); -}); diff --git a/frontend/src/lib/getRandomColor.ts b/frontend/src/lib/getRandomColor.ts index 5eaaa2a724..49361caae8 100644 --- a/frontend/src/lib/getRandomColor.ts +++ b/frontend/src/lib/getRandomColor.ts @@ -1,17 +1,14 @@ -import { span } from 'store/actions'; - export const colors = [ - '#2F80ED', - '#BB6BD9', '#F2994A', - '#219653', '#56CCF2', '#F2C94C', + '#219653', + '#2F80ED', + '#EB5757', + '#BB6BD9', '#BDBDBD', ]; -export const errorColor = '#d32f2f'; - export function getRandomNumber(min: number, max: number): number { return Math.random() * (max - min) + min; } @@ -21,16 +18,4 @@ const getRandomColor = (): string => { return colors[index]; }; -export const spanServiceNameToColorMapping = (spans: span[]) => { - const serviceNameSet = new Set(); - spans.forEach((spanItem) => { - serviceNameSet.add(spanItem[3]); - }); - const serviceToColorMap: { [key: string]: string } = {}; - Array.from(serviceNameSet).forEach((serviceName, idx) => { - serviceToColorMap[`${serviceName}`] = colors[idx % colors.length]; - }); - return serviceToColorMap; -}; - export default getRandomColor; diff --git a/frontend/src/lib/getStep.ts b/frontend/src/lib/getStep.ts deleted file mode 100644 index 2458782d27..0000000000 --- a/frontend/src/lib/getStep.ts +++ /dev/null @@ -1,43 +0,0 @@ -import dayjs from 'dayjs'; - -type DateType = number | string; -type DateInputFormatType = 's' | 'ms' | 'ns'; - -interface GetStepInput { - start: DateType; - end: DateType; - inputFormat: DateInputFormatType; -} - -/** - * Converts given timestamp to ms. - */ -const convertToMs = (timestamp: number, inputFormat: DateInputFormatType) => { - switch (inputFormat) { - case 's': - return timestamp * 1e3; - case 'ms': - return timestamp * 1; - case 'ns': - return timestamp / 1e6; - } -}; - -export const DefaultStepSize = 60; - -/** - * Returns relevant step size based on given start and end date. - */ -const getStep = ({ start, end, inputFormat = 'ms' }: GetStepInput): number => { - const startDate = dayjs(convertToMs(Number(start), inputFormat)); - const endDate = dayjs(convertToMs(Number(end), inputFormat)); - const diffDays = Math.abs(endDate.diff(startDate, 'days')); - - if (diffDays > 1) { - return DefaultStepSize * diffDays; - } - - return DefaultStepSize; -}; - -export default getStep; diff --git a/frontend/src/modules/Traces/FilterStateDisplay.tsx b/frontend/src/modules/Traces/FilterStateDisplay.tsx new file mode 100644 index 0000000000..37b747a11b --- /dev/null +++ b/frontend/src/modules/Traces/FilterStateDisplay.tsx @@ -0,0 +1,129 @@ +import { Card, Tag as AntTag } from 'antd'; +import React from 'react'; +import { connect } from 'react-redux'; +import { TagItem, TraceFilters, updateTraceFilters } from 'store/actions'; +import { AppState } from 'store/reducers'; +import styled from 'styled-components'; + +const Tag = styled(AntTag)` + .anticon { + position: relative; + top: -3px; + } +`; + +interface FilterStateDisplayProps { + traceFilters: TraceFilters; + updateTraceFilters: (props: TraceFilters) => void; +} + +const _FilterStateDisplay = (props: FilterStateDisplayProps): JSX.Element => { + const { traceFilters, updateTraceFilters } = props; + + function handleCloseTag(value: string): void { + if (value === 'service') { + updateTraceFilters({ ...traceFilters, service: '' }); + } + if (value === 'operation') { + updateTraceFilters({ ...traceFilters, operation: '' }); + } + if (value === 'maxLatency') { + updateTraceFilters({ + ...traceFilters, + latency: { max: '', min: traceFilters.latency?.min || '' }, + }); + } + if (value === 'minLatency') { + updateTraceFilters({ + ...traceFilters, + latency: { min: '', max: traceFilters.latency?.max || '' }, + }); + } + } + + function handleCloseTagElement(item: TagItem): void { + props.updateTraceFilters({ + ...props.traceFilters, + tags: props.traceFilters.tags?.filter((elem) => elem !== item), + }); + } + return ( + + {props.traceFilters.service === '' || + props.traceFilters.operation === undefined ? null : ( + { + handleCloseTag('service'); + }} + > + service:{props.traceFilters.service} + + )} + {props.traceFilters.operation === '' || + props.traceFilters.operation === undefined ? null : ( + { + handleCloseTag('operation'); + }} + > + operation:{props.traceFilters.operation} + + )} + {props.traceFilters.latency === undefined || + props.traceFilters.latency?.min === '' ? null : ( + { + handleCloseTag('minLatency'); + }} + > + minLatency: + {(parseInt(traceFilters?.latency?.min || '0') / 1000000).toString()}ms + + )} + {props.traceFilters.latency === undefined || + props.traceFilters.latency?.max === '' ? null : ( + { + handleCloseTag('maxLatency'); + }} + > + maxLatency: + {(parseInt(traceFilters?.latency?.max || '0') / 1000000).toString()}ms + + )} + {props.traceFilters.tags === undefined + ? null + : props.traceFilters.tags.map((item) => ( + { + handleCloseTagElement(item); + }} + > + {item.key} {item.operator} {item.value} + + ))} + + ); +}; + +const mapStateToProps = (state: AppState): { traceFilters: TraceFilters } => { + return { traceFilters: state.traceFilters }; +}; + +export const FilterStateDisplay = connect(mapStateToProps, { + updateTraceFilters: updateTraceFilters, +})(_FilterStateDisplay); diff --git a/frontend/src/modules/Traces/SelectedSpanDetails.tsx b/frontend/src/modules/Traces/SelectedSpanDetails.tsx new file mode 100644 index 0000000000..427066081e --- /dev/null +++ b/frontend/src/modules/Traces/SelectedSpanDetails.tsx @@ -0,0 +1,109 @@ +import { Card, Space, Tabs, Typography } from 'antd'; +import React from 'react'; +import { pushDStree } from 'store/actions'; +import styled from 'styled-components'; + +const { TabPane } = Tabs; + +const { Text, Title, Paragraph } = Typography; + +interface SelectedSpanDetailsProps { + data: pushDStree; +} + +// Check this discussion for antd with styled components +// https://gist.github.com/newswim/fa916c66477ddd5952f7d6548e6a0605 + +const CustomTitle = styled(Title)` + &&& { + color: #f2f2f2; + font-size: 14px; + } +`; + +const CustomText = styled(Text)` + &&& { + color: #2d9cdb; + font-size: 14px; + } +`; + +const CustomSubTitle = styled(Title)` + &&& { + color: #bdbdbd; + font-size: 14px; + margin-bottom: 8px; + } +`; + +const CustomSubText = styled(Paragraph)` + &&& { + background: #4f4f4f; + color: #2d9cdb; + font-size: 12px; + padding: 6px 8px; + word-break: break-all; + margin-bottom: 16px; + } +`; + +const CardContainer = styled(Card)` + .ant-card-body { + max-height: 90vh; + overflow-y: auto; + } +`; + +const SelectedSpanDetails = (props: SelectedSpanDetailsProps): JSX.Element => { + const spanTags = props.data?.tags; + const service = props.data?.name?.split(':')[0]; + const operation = props.data?.name?.split(':')[1]; + + return ( + + + Details for selected Span + + Service + {service} + + + Operation + {operation} + + + + + {spanTags && + spanTags.map((tags) => { + return ( + <> + {tags.value && ( + <> + {tags.key} + + {tags.key === 'error' ? 'true' : tags.value} + + + )} + + ); + })} + + + {spanTags && + spanTags + .filter((tags) => tags.key === 'error') + .map((error) => ( + <> + {error.key} + true + + ))} + + + + ); +}; + +export default SelectedSpanDetails; diff --git a/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChart.css b/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChart.css new file mode 100644 index 0000000000..98bae47c4a --- /dev/null +++ b/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChart.css @@ -0,0 +1,15 @@ +.row-styles { + cursor: pointer; +} +.hide { + display: none; +} + +/* .ant-tabs-nav-list { + justify-content: space-between; + width: 100%; +} */ + +.ant-table-body table { + margin-bottom: 64px; +} diff --git a/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChart.tsx b/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChart.tsx new file mode 100644 index 0000000000..032727766b --- /dev/null +++ b/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChart.tsx @@ -0,0 +1,389 @@ +import './TraceGanttChart.css'; + +import { + Button, + Col, + Progress, + Row, + Table as TableComponent, + Tabs, +} from 'antd'; +import TextToolTip from 'components/TextToolTip'; +import { has, isEmpty, max } from 'lodash-es'; +import traverseTreeData from 'modules/Traces/TraceGanttChart/TraceGanttChartHelpers'; +import React, { useEffect, useRef, useState } from 'react'; +import { pushDStree } from 'store/actions'; +import styled from 'styled-components'; + +const { TabPane } = Tabs; + +const StyledButton = styled(Button)` + border: 1px solid #e0e0e0; + border-radius: 4px; + color: #f2f2f2; + font-size: 14px; + line-height: 20px; + margin-right: 0.5rem; + margin-left: 0.5rem; +`; + +const Table = styled(TableComponent)` + .ant-tabs-nav-list { + width: 100%; + justify-content: space-between; + } +`; + +interface TraceGanttChartProps { + treeData: pushDStree[]; + clickedSpan: pushDStree; + selectedSpan: pushDStree; + resetZoom: (value: boolean) => {}; + setSpanTagsInfo: (p: { data: any }) => {}; +} + +const TraceGanttChart = ({ + treeData, + clickedSpan, + selectedSpan, + resetZoom, + setSpanTagsInfo, +}: TraceGanttChartProps) => { + const checkStrictly = true; + const [selectedRows, setSelectedRows] = useState([]); + const [clickedSpanData, setClickedSpanData] = useState(clickedSpan); + const [defaultExpandedRows, setDefaultExpandedRows] = useState([]); + const [sortedTreeData, setSortedTreeData] = useState(treeData); + const [isReset, setIsReset] = useState(false); + const [tabsContainerWidth, setTabsContainerWidth] = useState(0); + const tableRef = useRef(''); + const tabsContainer = document.querySelector( + '#collapsable .ant-tabs-nav-list', + ); + + const tabs = document.querySelectorAll('#collapsable .ant-tabs-tab'); + + const { id } = treeData || 'id'; + let maxGlobal = 0; + let minGlobal = 0; + let medianGlobal = 0; + const endTimeArray: [] = []; + + useEffect(() => { + if (id !== 'empty') { + setSortedTreeData(treeData); + if (clickedSpan) { + setClickedSpanData(clickedSpan); + } + if (tabsContainer) { + setTabsContainerWidth(tabsContainer.offsetWidth); + } + } + handleScroll(selectedSpan?.id); + }, [sortedTreeData, treeData, clickedSpan]); + + useEffect(() => { + if ( + !isEmpty(clickedSpanData) && + clickedSpan && + !selectedRows.includes(clickedSpan.id) && + !isReset + ) { + setSelectedRows([clickedSpan.id]); + getParentKeys(clickedSpan); + handleFocusOnSelectedPath('', [clickedSpan.id]); + } + }, [clickedSpan, selectedRows, isReset, clickedSpanData]); + + const parentKeys: string[] = []; + const childrenKeys: string[] = []; + + const getParentKeys = (obj) => { + if (has(obj, 'parent')) { + parentKeys.push(obj.parent.id); + getParentKeys(obj.parent); + } + }; + + const getChildrenKeys = (obj: pushDStree) => { + if (has(obj, 'children')) { + childrenKeys.push(obj.id); + if (!isEmpty(obj.children)) { + obj.children.map((item) => { + getChildrenKeys(item); + }); + } + } + }; + + useEffect(() => { + if (!isEmpty(selectedSpan) && isEmpty(clickedSpan)) { + getParentKeys(selectedSpan); + const keys = [selectedSpan?.id, ...parentKeys]; + setDefaultExpandedRows(keys); + setSelectedRows([selectedSpan.id, clickedSpan]); + // setSpanTagsInfo({data: selectedSpan}) + } else { + setSelectedRows([treeData?.[0]?.id]); + setDefaultExpandedRows([treeData?.[0]?.id]); + // /.setSpanTagsInfo({data: treeData?.[0]}) + } + }, [selectedSpan, treeData, clickedSpan]); + + const getMaxEndTime = (treeData) => { + if (treeData.length > 0) { + if (treeData?.id !== 'empty') { + return Array.from(treeData).map((item, key) => { + if (!isEmpty(item.children)) { + endTimeArray.push(item.time / 1000000 + item.startTime); + getMaxEndTime(item.children); + } else { + endTimeArray.push(item.time / 1000000 + item.startTime); + } + }); + } + } + }; + + if (id !== 'empty') { + getMaxEndTime(treeData); + maxGlobal = max(endTimeArray); + minGlobal = treeData?.[0]?.startTime; + medianGlobal = (minGlobal + maxGlobal) / 2; + } + + /* + timeDiff = maxGlobal - startTime + totalTime = maxGlobal - minGlobal + totalWidth = width of container + */ + const getPaddingLeft = (timeDiff, totalTime, totalWidth) => { + return ((timeDiff / totalTime) * totalWidth).toFixed(0); + }; + + const tabMinVal = 0; + const tabMedianVal = (medianGlobal - minGlobal).toFixed(0); + const tabMaxVal = (maxGlobal - minGlobal).toFixed(0); + + const columns = [ + { + title: '', + dataIndex: 'name', + key: 'name', + }, + { + title: ( + + + + + + ), + dataIndex: 'trace', + name: 'trace', + render: (_, record: pushDStree) => { + const widths = []; + let length; + + if (widths.length < tabs.length) { + Array.from(tabs).map((tab) => { + widths.push(tab.offsetWidth); + }); + } + + let paddingLeft = 0; + const startTime = parseFloat(record.startTime.toString()); + const duration = parseFloat((record.time / 1000000).toFixed(2)); + paddingLeft = parseInt( + getPaddingLeft( + startTime - minGlobal, + maxGlobal - minGlobal, + tabsContainerWidth, + ), + ); + let textPadding = paddingLeft; + if (paddingLeft === tabsContainerWidth - 20) { + textPadding = tabsContainerWidth - 40; + } + length = ((duration / (maxGlobal - startTime)) * 100).toFixed(2); + + return ( + <> +
{duration}ms
+ + + ); + }, + }, + ]; + + const handleFocusOnSelectedPath = (event, selectedRowsList = selectedRows) => { + if (!isEmpty(selectedRowsList)) { + // initializing the node + let node: pushDStree = { + children: [], + id: '', + name: '', + startTime: 0, + tags: [], + time: 0, + value: 0, + }; + + traverseTreeData(treeData, (item: pushDStree) => { + if (item.id === selectedRowsList[0]) { + node = item; + } + }); + + try { + setSpanTagsInfo({ data: node }); + } catch (e) { + // TODO: error logging. + console.error('Node not found in Tree Data.'); + } + + // get the parent of the node + getParentKeys(node); + + // get the children of the node + getChildrenKeys(node); + + const rows = document.querySelectorAll('#collapsable table tbody tr'); + rows.forEach((row) => { + const attribKey = row.getAttribute('data-row-key') || ''; + if ( + !isEmpty(attribKey) && + !selectedRowsList.includes(attribKey) && + !childrenKeys.includes(attribKey) + ) { + row.classList.add('hide'); + } + }); + setDefaultExpandedRows([...parentKeys, ...childrenKeys]); + } + }; + + const handleResetFocus = () => { + const rows = document.querySelectorAll('#collapsable table tbody tr'); + rows.forEach((row) => { + row.classList.remove('hide'); + }); + + resetZoom(true); + }; + + const handleScroll = (id: string): void => { + if (!isEmpty(id)) { + const selectedRow = document.querySelectorAll( + `[data-row-key='${id}']`, + ); + selectedRow?.[0]?.scrollIntoView(); + } + }; + + const rowSelection = { + onChange: (selectedRowKeys: []) => { + setSelectedRows(selectedRowKeys); + setClickedSpanData({}); + if (isEmpty(selectedRowKeys)) { + setIsReset(true); + } else { + setIsReset(false); + } + }, + onSelect: (record: pushDStree) => { + handleRowOnClick(record); + }, + selectedRowKeys: selectedRows, + }; + + const handleRowOnClick = (record: pushDStree) => { + let node = {}; + traverseTreeData(treeData, (item: pushDStree) => { + if (item.id === record.id) { + node = item; + } + }); + + try { + setSpanTagsInfo({ data: node }); + } catch (e) { + // TODO: error logging. + console.error('Node not found in TreeData.'); + } + + const selectedRowKeys = selectedRows; + if (selectedRowKeys.indexOf(record.id) >= 0) { + selectedRowKeys.splice(selectedRowKeys.indexOf(record.key), 1); + } else { + selectedRowKeys.push(record.id); + } + setSelectedRows([record.id]); + }; + + const handleOnExpandedRowsChange = (item: string[]) => { + setDefaultExpandedRows(item); + }; + + return ( + <> + {id !== 'empty' && ( + <> + + + + + + + Focus on selected path + + Reset Focus + + + + { + return { + onClick: () => handleRowOnClick(record), // click row + }; + }} + onExpandedRowsChange={(keys) => + handleOnExpandedRowsChange(keys.map((e) => e.toString())) + } + pagination={false} + expandable={{ + expandedRowKeys: defaultExpandedRows, + }} + scroll={{ y: 540 }} + rowClassName="row-styles" + filterMultiple={false} + /> + + )} + + ); +}; + +export default TraceGanttChart; diff --git a/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChartHelpers.ts b/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChartHelpers.ts new file mode 100644 index 0000000000..55e7e5aee6 --- /dev/null +++ b/frontend/src/modules/Traces/TraceGanttChart/TraceGanttChartHelpers.ts @@ -0,0 +1,40 @@ +import { isEmpty } from 'lodash-es'; +import { pushDStree } from 'store/actions'; + +interface itemProps { + treeData: pushDStree[]; + marked: boolean; +} + +// Doing DFS traversal on the tree. +// Callback to be called for each element in the tree once. +const traverseTreeData = ( + tree: pushDStree[], + callback: (item: pushDStree) => void, +): void => { + if (isEmpty(tree) || tree[0].id === 'empty') return; + const node = { treeData: tree, marked: false }; + const stk: [itemProps] = [node]; + + while (!isEmpty(stk)) { + const x = stk[stk.length - 1]; + + // marked means seeing the node for the second time. + if (x.marked) { + x.marked = false; + stk.pop(); + x.treeData.map((item: pushDStree) => { + callback(item); + }); + } else { + x.marked = true; + x.treeData.map((item) => { + if (item.children.length > 0) { + stk.push({ treeData: item.children, marked: false }); + } + }); + } + } +}; + +export default traverseTreeData; diff --git a/frontend/src/modules/Traces/TraceGanttChart/index.tsx b/frontend/src/modules/Traces/TraceGanttChart/index.tsx new file mode 100644 index 0000000000..cce8f15870 --- /dev/null +++ b/frontend/src/modules/Traces/TraceGanttChart/index.tsx @@ -0,0 +1 @@ +export { default } from './TraceGanttChart'; diff --git a/frontend/src/modules/Traces/TraceGraph.css b/frontend/src/modules/Traces/TraceGraph.css new file mode 100644 index 0000000000..99648f61f2 --- /dev/null +++ b/frontend/src/modules/Traces/TraceGraph.css @@ -0,0 +1,59 @@ +.d3-tip { + line-height: 1; + padding: 2px; + background: rgba(0, 0, 0, 0.8); + color: #fff; + border-radius: 2px; + font-size: 12px; +} + +/* Creates a small triangle extender for the tooltip */ +.d3-tip:after { + box-sizing: border-box; + display: inline; + font-size: 12px; + width: 100%; + line-height: 1; + color: rgba(0, 0, 0, 0.8); + content: "\25BC"; + position: absolute; + text-align: center; +} + +/* Style northward tooltips differently */ +.d3-tip.n:after { + margin: -1px 0 0 0; + top: 100%; + left: 0; +} + +/* SVG element */ +/* Way to add borders in SVG - https://stackoverflow.com/questions/18330344/how-to-add-border-outline-stroke-to-svg-elements-in-css */ +.frame { + fill: none; + stroke: rgba(255, 255, 255, 0.25); + stroke-width: 1; + stroke-linecap: round; + stroke-linejoin: round; +} + +/* Prevent text vertical shift on hover */ +.d3-flame-graph-label { + border: 1px dotted transparent; + cursor: pointer; +} + +/* Transparency simulates sub pixel border https://stackoverflow.com/questions/13891177/css-border-less-than-1px */ + +.d3-flame-graph-label:hover { + border-color: rgba(255, 255, 255, 0.75); +} +/* +.d3-flame-graph-label:hover { + border: 1px solid; + border-color: rgba(255, 255, 255, 0.75); + } */ + +.fade:not(.show) { + opacity: 0.5; +} diff --git a/frontend/src/modules/Traces/TraceGraph.tsx b/frontend/src/modules/Traces/TraceGraph.tsx new file mode 100644 index 0000000000..2cd6e59c1d --- /dev/null +++ b/frontend/src/modules/Traces/TraceGraph.tsx @@ -0,0 +1,216 @@ +import './TraceGraph.css'; + +import { Affix, Card, Col, Row, Space } from 'antd'; +import * as d3 from 'd3'; +import { flamegraph } from 'd3-flame-graph'; +import * as d3Tip from 'd3-tip'; +import { isEmpty, sortBy } from 'lodash-es'; +import React, { useEffect, useState } from 'react'; +import { connect, useDispatch } from 'react-redux'; +import { useLocation, useParams } from 'react-router-dom'; +import { + fetchTraceItem, + pushDStree, + spansWSameTraceIDResponse, +} from 'store/actions'; +import { AppState } from 'store/reducers'; +import styled from 'styled-components'; +import { spanToTreeUtil } from 'utils/spanToTree'; + +import SelectedSpanDetails from './SelectedSpanDetails'; +import TraceGanttChart from './TraceGanttChart'; + +interface TraceGraphProps { + traceItem: spansWSameTraceIDResponse; + fetchTraceItem: Function; +} + +const TraceGanttChartContainer = styled(Card)` + background: #333333; + border-radius: 5px; +`; + +const _TraceGraph = (props: TraceGraphProps) => { + const location = useLocation(); + const spanId = location?.state?.spanId; + const { id } = useParams<{ id?: string }>(); + + const [clickedSpanTags, setClickedSpanTags] = useState([]); + const [selectedSpan, setSelectedSpan] = useState({}); + const [clickedSpan, setClickedSpan] = useState(null); + const [resetZoom, setResetZoom] = useState(false); + const [sortedTreeData, setSortedTreeData] = useState([]); + + let sortedData = {}; + + const getSortedData = (treeData: pushDStree[], parent = {}) => { + if (!isEmpty(treeData)) { + if (treeData[0].id !== 'empty') { + return Array.from(treeData).map((item, key) => { + if (!isEmpty(item.children)) { + getSortedData(item.children, item); + sortedData = sortBy(item.children, (i) => i.startTime); + treeData[key].children = sortedData; + } + if (!isEmpty(parent)) { + treeData[key].parent = parent; + } + return treeData; + }); + } + return treeData; + } + }; + + const tree = spanToTreeUtil(props.traceItem[0].events); + const dispatch = useDispatch(); + + useEffect(() => { + //sets span width based on value - which is mapped to duration + fetchTraceItem(id || '')(dispatch); + }, [dispatch, id]); + + useEffect(() => { + if (props.traceItem) { + const sortedData = getSortedData([tree]); + setSortedTreeData(sortedData?.[0]); + getSpanInfo(sortedData?.[0], spanId); + // This is causing element to change ref. Can use both useRef or this approach. + d3 + .select('#chart') + .datum(tree) + .call(chart) + .sort((item) => item.startTime); + } + }, [props.traceItem]); + // if this monitoring of props.traceItem.data is removed then zoom on click doesn't work + // Doesn't work if only do initial check, works if monitor an element - as it may get updated in sometime + + useEffect(() => { + if ( + !isEmpty(sortedTreeData) && + sortedTreeData?.id !== 'empty' && + isEmpty(clickedSpanTags) + ) { + setClickedSpanTags(sortedTreeData?.[0]); + } + }, [sortedTreeData]); + + useEffect(() => { + if (resetZoom) { + // This is causing element to change ref. Can use both useRef or this approach. + d3 + .select('#chart') + .datum(tree) + .call(chart) + .sort((item) => item.startTime); + setResetZoom(false); + } + }, [resetZoom]); + + const tip = d3Tip + .default() + .attr('class', 'd3-tip') + .html(function (d: any) { + return d.data.name + '
duration: ' + d.data.value / 1000000 + 'ms'; + }); + + const onClick = (z: any) => { + setClickedSpanTags(z.data); + setClickedSpan(z.data); + setSelectedSpan([]); + console.log(`Clicked on ${z.data.name}, id: "${z.id}"`); + }; + + const setSpanTagsInfo = (z: any) => { + setClickedSpanTags(z.data); + }; + + const getSpanInfo = (data: [pushDStree], spanId: string): void => { + if (resetZoom) { + setSelectedSpan({}); + return; + } + if (data?.[0]?.id !== 'empty') { + Array.from(data).map((item) => { + if (item.id === spanId) { + setSelectedSpan(item); + setClickedSpanTags(item); + return item; + } else if (!isEmpty(item.children)) { + getSpanInfo(item.children, spanId); + } + }); + } + }; + + const chart = flamegraph() + .cellHeight(18) + .transitionDuration(500) + .inverted(true) + .tooltip(tip) + .minFrameSize(4) + .elided(false) + .differential(false) + .sort((item) => item.startTime) + //Use self value=true when we're using not using aggregated option, Which is not our case. + // In that case it's doing step function sort of stuff thru computation. + // Source flamegraph.js line 557 and 573. + // .selfValue(true) + .onClick(onClick) + .width(800); + + const handleResetZoom = (value) => { + setResetZoom(value); + }; + + return ( + +
+ + +
+
+ Trace Graph component ID is {id}{' '} +
+
+
+
+ + + + + +
+ + + + + + + + ); +}; + +const mapStateToProps = ( + state: AppState, +): { traceItem: spansWSameTraceIDResponse } => { + return { traceItem: state.traceItem }; +}; + +export const TraceGraph = connect(mapStateToProps, { + fetchTraceItem: fetchTraceItem, +})(_TraceGraph); diff --git a/frontend/src/modules/Traces/TraceGraphColumn.tsx b/frontend/src/modules/Traces/TraceGraphColumn.tsx new file mode 100644 index 0000000000..c32524580c --- /dev/null +++ b/frontend/src/modules/Traces/TraceGraphColumn.tsx @@ -0,0 +1,76 @@ +import { Table } from 'antd'; +import React from 'react'; +import { connect } from 'react-redux'; +import { pushDStree, traceResponseNew } from 'store/actions'; +import { AppState } from 'store/reducers'; + +interface TraceGraphColumnProps { + traces: traceResponseNew; +} + +interface TableDataSourceItem { + key: string; + operationName: string; + startTime: number; + duration: number; +} + +const _TraceGraphColumn = (props: TraceGraphColumnProps) => { + const columns: any = [ + { + title: 'Start Time (UTC Time)', + dataIndex: 'startTime', + key: 'startTime', + sorter: (a: any, b: any) => a.startTime - b.startTime, + sortDirections: ['descend', 'ascend'], + render: (value: number) => new Date(Math.round(value / 1000)).toUTCString(), + }, + { + title: 'Duration (in ms)', + dataIndex: 'duration', + key: 'duration', + sorter: (a: any, b: any) => a.duration - b.duration, + sortDirections: ['descend', 'ascend'], + render: (value: number) => (value / 1000000).toFixed(2), + }, + { + title: 'Operation', + dataIndex: 'operationName', + key: 'operationName', + }, + ]; + + const dataSource: TableDataSourceItem[] = []; + + if (props.traces[0].events.length > 0) { + props.traces[0].events.map( + (item: (number | string | string[] | pushDStree[])[], index) => { + if ( + typeof item[0] === 'number' && + typeof item[4] === 'string' && + typeof item[6] === 'string' && + typeof item[1] === 'string' && + typeof item[2] === 'string' + ) + dataSource.push({ + startTime: item[0], + operationName: item[4], + duration: parseInt(item[6]), + key: index.toString(), + }); + }, + ); + } + + return ( +
+
; + + ); +}; + +const mapStateToProps = (state: AppState): { traces: traceResponseNew } => { + return { traces: state.traces }; +}; + +export const TraceGraphColumn = connect(mapStateToProps)(_TraceGraphColumn); diff --git a/frontend/src/modules/Traces/TraceGraphDef.tsx b/frontend/src/modules/Traces/TraceGraphDef.tsx new file mode 100644 index 0000000000..13658a60ec --- /dev/null +++ b/frontend/src/modules/Traces/TraceGraphDef.tsx @@ -0,0 +1,5 @@ +export { TraceGraph as default } from './TraceGraph'; + +// PNOTE +// Because react.lazy doesn't work on named components +// https://reactjs.org/docs/code-splitting.html#:~:text=Named%20Exports,t%20pull%20in%20unused%20components diff --git a/frontend/src/modules/Traces/styles.ts b/frontend/src/modules/Traces/styles.ts new file mode 100644 index 0000000000..a16e487b3d --- /dev/null +++ b/frontend/src/modules/Traces/styles.ts @@ -0,0 +1,16 @@ +import { Card as CardComponent, Typography } from 'antd'; +import styled from 'styled-components'; + +export const CustomGraphContainer = styled.div` + min-height: 30vh; +`; + +export const Card = styled(CardComponent)` + .ant-card-body { + padding-bottom: 0; + } +`; + +export const CustomVisualizationsTitle = styled(Typography)` + margin-bottom: 1rem; +`; diff --git a/frontend/src/pages/Trace/styles.ts b/frontend/src/pages/Trace/styles.ts index d7cf4c0869..f124268258 100644 --- a/frontend/src/pages/Trace/styles.ts +++ b/frontend/src/pages/Trace/styles.ts @@ -5,6 +5,7 @@ export const Container = styled.div` display: flex; flex: 1; min-height: 80vh; + margin-top: 1rem; `; diff --git a/frontend/src/pages/TraceDetail/constants.ts b/frontend/src/pages/TraceDetail/constants.ts deleted file mode 100644 index 0253cbeff0..0000000000 --- a/frontend/src/pages/TraceDetail/constants.ts +++ /dev/null @@ -1 +0,0 @@ -export const SPAN_DETAILS_LEFT_COL_WIDTH = 350; diff --git a/frontend/src/pages/TraceDetail/index.tsx b/frontend/src/pages/TraceDetail/index.tsx deleted file mode 100644 index bf29a5244b..0000000000 --- a/frontend/src/pages/TraceDetail/index.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import useFetch from 'hooks/useFetch'; -import getTraceItem from 'api/trace/getTraceItem'; -import { useParams } from 'react-router-dom'; -import { Props as TraceDetailProps } from 'types/api/trace/getTraceItem'; -import Spinner from 'components/Spinner'; -import { Typography } from 'antd'; -import TraceDetailContainer from 'container/TraceDetail'; - -const TraceDetail = (): JSX.Element => { - const { id } = useParams(); - - const traceDetailResponse = useFetch(getTraceItem, { - id, - }); - - if (traceDetailResponse.error) { - return ( - - {traceDetailResponse.errorMessage || 'Something went wrong'} - - ); - } - - if (traceDetailResponse.loading || traceDetailResponse.payload === undefined) { - return ; - } - - return ; -}; - -export default TraceDetail; diff --git a/frontend/src/store/actions/index.ts b/frontend/src/store/actions/index.ts index 6ee8a31184..22d4fd9178 100644 --- a/frontend/src/store/actions/index.ts +++ b/frontend/src/store/actions/index.ts @@ -4,5 +4,7 @@ export * from './global'; export * from './metrics'; export * from './MetricsActions'; export * from './serviceMap'; +export * from './traceFilters'; +export * from './traces'; export * from './types'; export * from './usage'; diff --git a/frontend/src/store/actions/metrics/getInitialData.ts b/frontend/src/store/actions/metrics/getInitialData.ts index 942cb0dbed..7c43fc0427 100644 --- a/frontend/src/store/actions/metrics/getInitialData.ts +++ b/frontend/src/store/actions/metrics/getInitialData.ts @@ -6,7 +6,6 @@ import getServiceOverview from 'api/metrics/getServiceOverview'; import getTopEndPoints from 'api/metrics/getTopEndPoints'; import { AxiosError } from 'axios'; import GetMinMax from 'lib/getMinMax'; -import getStep from 'lib/getStep'; import { Dispatch } from 'redux'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; @@ -65,7 +64,7 @@ export const GetInitialData = ( end: maxTime, service: props.serviceName, start: minTime, - step: getStep({ start: minTime, end: maxTime, inputFormat: 'ns' }), + step, }), getTopEndPoints({ end: maxTime, diff --git a/frontend/src/store/actions/trace/getInitialSpansAggregate.ts b/frontend/src/store/actions/trace/getInitialSpansAggregate.ts index 11d061e079..0ae6362eea 100644 --- a/frontend/src/store/actions/trace/getInitialSpansAggregate.ts +++ b/frontend/src/store/actions/trace/getInitialSpansAggregate.ts @@ -1,12 +1,11 @@ -import { notification } from 'antd'; -import getSpansAggregate from 'api/trace/getSpansAggregate'; import { Dispatch, Store } from 'redux'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import { UPDATE_SPANS_AGGREEGATE } from 'types/actions/trace'; -import { Props as GetSpanAggregateProps } from 'types/api/trace/getSpanAggregate'; +import getSpansAggregate from 'api/trace/getSpansAggregate'; import { GlobalReducer } from 'types/reducer/globalTime'; import { TraceReducer } from 'types/reducer/trace'; +import { notification } from 'antd'; export const GetSpansAggregate = ( props: GetSpansAggregateProps, @@ -53,7 +52,6 @@ export const GetSpansAggregate = ( offset: props.current * props.pageSize - props.pageSize, selectedTags: props.selectedTags, isFilterExclude: traces.isFilterExclude, - order: props.order, }); if (response.statusCode === 200) { @@ -114,5 +112,4 @@ export interface GetSpansAggregateProps { current: TraceReducer['spansAggregate']['currentPage']; pageSize: TraceReducer['spansAggregate']['pageSize']; selectedTags: TraceReducer['selectedTags']; - order: GetSpanAggregateProps['order']; } diff --git a/frontend/src/store/actions/traceFilters.ts b/frontend/src/store/actions/traceFilters.ts new file mode 100644 index 0000000000..35502674fd --- /dev/null +++ b/frontend/src/store/actions/traceFilters.ts @@ -0,0 +1,38 @@ +// Action creator must have a type and optionally a payload +import { ActionTypes } from './types'; + +export interface TagItem { + key: string; + value: string; + operator: 'equals' | 'contains' | 'regex'; +} + +export interface LatencyValue { + min: string; + max: string; +} + +export interface TraceFilters { + tags?: TagItem[]; + service?: string; + latency?: LatencyValue; + operation?: string; + kind?: string; +} + +//define interface for action. Action creator always returns object of this type +export interface updateTraceFiltersAction { + type: ActionTypes.updateTraceFilters; + payload: TraceFilters; +} + +export const updateTraceFilters = ( + traceFilters: TraceFilters, +): updateTraceFiltersAction => { + return { + type: ActionTypes.updateTraceFilters, + payload: traceFilters, + }; +}; + +//named export when you want to export multiple functions from the same file diff --git a/frontend/src/store/actions/traces.ts b/frontend/src/store/actions/traces.ts index 8ac074cd2f..72200fb5eb 100644 --- a/frontend/src/store/actions/traces.ts +++ b/frontend/src/store/actions/traces.ts @@ -43,10 +43,6 @@ export interface pushDStree { startTime: number; tags: TraceTagItem[]; children: pushDStree[]; - parent: pushDStree; - serviceName: string; - serviceColour: string; - hasError: boolean; } export interface spanItem { diff --git a/frontend/src/store/actions/types.ts b/frontend/src/store/actions/types.ts index 2aaa38f9c3..6c2902c1b3 100644 --- a/frontend/src/store/actions/types.ts +++ b/frontend/src/store/actions/types.ts @@ -1,4 +1,6 @@ import { serviceMapItemAction, servicesAction } from './serviceMap'; +import { updateTraceFiltersAction } from './traceFilters'; +import { FetchTraceItemAction, FetchTracesAction } from './traces'; import { getUsageDataAction } from './usage'; export enum ActionTypes { @@ -11,4 +13,10 @@ export enum ActionTypes { fetchTraceItem = 'FETCH_TRACE_ITEM', } -export type Action = getUsageDataAction | servicesAction | serviceMapItemAction; +export type Action = + | FetchTraceItemAction + | FetchTracesAction + | updateTraceFiltersAction + | getUsageDataAction + | servicesAction + | serviceMapItemAction; diff --git a/frontend/src/store/reducers/index.ts b/frontend/src/store/reducers/index.ts index 690464b215..9c2bdecb1f 100644 --- a/frontend/src/store/reducers/index.ts +++ b/frontend/src/store/reducers/index.ts @@ -6,10 +6,14 @@ import globalTimeReducer from './global'; import metricsReducers from './metric'; import { ServiceMapReducer } from './serviceMap'; import traceReducer from './trace'; +import TraceFilterReducer from './traceFilters'; +import { traceItemReducer } from './traces'; import { usageDataReducer } from './usage'; const reducers = combineReducers({ + traceFilters: TraceFilterReducer, traces: traceReducer, + traceItem: traceItemReducer, usageDate: usageDataReducer, globalTime: globalTimeReducer, serviceMap: ServiceMapReducer, diff --git a/frontend/src/store/reducers/traceFilters.ts b/frontend/src/store/reducers/traceFilters.ts new file mode 100644 index 0000000000..d234015c73 --- /dev/null +++ b/frontend/src/store/reducers/traceFilters.ts @@ -0,0 +1,29 @@ +import { TraceFilters } from 'store/actions/traceFilters'; +import { ActionTypes } from 'store/actions/types'; + +type ACTION = { + type: ActionTypes; + payload: TraceFilters; +}; + +const initialState: TraceFilters = { + service: '', + tags: [], + operation: '', + latency: { min: '', max: '' }, + kind: '', +}; + +const TraceFilterReducer = ( + state = initialState, + action: ACTION, +): TraceFilters => { + switch (action.type) { + case ActionTypes.updateTraceFilters: + return action.payload; + default: + return state; + } +}; + +export default TraceFilterReducer; diff --git a/frontend/src/store/reducers/traces.ts b/frontend/src/store/reducers/traces.ts new file mode 100644 index 0000000000..afe8436818 --- /dev/null +++ b/frontend/src/store/reducers/traces.ts @@ -0,0 +1,33 @@ +import { + Action, + ActionTypes, + spanList, + spansWSameTraceIDResponse, + traceResponseNew, +} from 'store/actions'; + +// PNOTE - Initializing is a must for state variable otherwise it gives an error in reducer +const spanlistinstance: spanList = { events: [], segmentID: '', columns: [] }; +export const tracesReducer = ( + state: traceResponseNew = { '0': spanlistinstance }, + action: Action, +): traceResponseNew => { + switch (action.type) { + case ActionTypes.fetchTraces: + return action.payload; + default: + return state; + } +}; + +export const traceItemReducer = ( + state: spansWSameTraceIDResponse = { '0': spanlistinstance }, + action: Action, +): spansWSameTraceIDResponse => { + switch (action.type) { + case ActionTypes.fetchTraceItem: + return action.payload; + default: + return state; + } +}; diff --git a/frontend/src/types/api/trace/getSpanAggregate.ts b/frontend/src/types/api/trace/getSpanAggregate.ts index 3263621009..0c2232efa9 100644 --- a/frontend/src/types/api/trace/getSpanAggregate.ts +++ b/frontend/src/types/api/trace/getSpanAggregate.ts @@ -7,7 +7,6 @@ export interface Props { limit: number; offset: number; selectedTags: TraceReducer['selectedTags']; - order?: 'descending' | 'ascending'; isFilterExclude: TraceReducer['isFilterExclude']; } diff --git a/frontend/src/types/api/trace/getTraceItem.ts b/frontend/src/types/api/trace/getTraceItem.ts deleted file mode 100644 index fc05448650..0000000000 --- a/frontend/src/types/api/trace/getTraceItem.ts +++ /dev/null @@ -1,50 +0,0 @@ -export interface Props { - id: string; -} - -export interface PayloadProps { - [id: string]: { - events: Span[]; - segmentID: string; - columns: string[]; - }; -} - -export type Span = [ - number, - string, - string, - string, - string, - string, - string, - string | string[], - string | string[], - string | string[], - ITraceTree[], -]; - -export interface ITraceTree { - id: string; - name: string; - value: number; - time: number; - startTime: number; - tags: ITraceTag[]; - children: ITraceTree[]; - parent?: ITraceTree; - serviceName: string; - serviceColour: string; - hasError?: boolean; - event?: ITraceEvents[]; -} - -export interface ITraceTag { - key: string; - value: string; -} - -interface ITraceEvents { - attributeMap: { event: string; [key: string]: string }; - name?: string; -} diff --git a/frontend/src/types/global.d.ts b/frontend/src/types/global.d.ts deleted file mode 100644 index dd674b33e6..0000000000 --- a/frontend/src/types/global.d.ts +++ /dev/null @@ -1,17 +0,0 @@ -// For CSS -declare module '*.module.css' { - const classes: { [key: string]: string }; - export default classes; -} - -// For LESS -declare module '*.module.less' { - const classes: { [key: string]: string }; - export default classes; -} - -// For SCSS -declare module '*.module.scss' { - const classes: { [key: string]: string }; - export default classes; -} diff --git a/frontend/src/typings/react-app-env.ts b/frontend/src/typings/react-app-env.ts new file mode 100644 index 0000000000..6431bc5fc6 --- /dev/null +++ b/frontend/src/typings/react-app-env.ts @@ -0,0 +1 @@ +/// diff --git a/frontend/src/typings/react-graph-vis.ts b/frontend/src/typings/react-graph-vis.ts new file mode 100644 index 0000000000..bef518e573 --- /dev/null +++ b/frontend/src/typings/react-graph-vis.ts @@ -0,0 +1,39 @@ +//You must first install the vis and react types 'npm install --save-dev @types/vis @types/react' +declare module 'react-graph-vis' { + import { Network, NetworkEvents, Options, Node, Edge, DataSet } from 'vis'; + import { Component } from 'react'; + + export { Network, NetworkEvents, Options, Node, Edge, DataSet } from 'vis'; + + export interface graphEvents { + [event: NetworkEvents]: (params) => void; + } + + //Doesn't appear that this module supports passing in a vis.DataSet directly. Once it does graph can just use the Data object from vis. + export interface graphData { + nodes: Node[]; + edges: Edge[]; + } + + export interface NetworkGraphProps { + graph: graphData; + options?: Options; + events?: graphEvents; + getNetwork?: (network: Network) => void; + identifier?: string; + style?: React.CSSProperties; + getNodes?: (nodes: DataSet) => void; + getEdges?: (edges: DataSet) => void; + } + + export interface NetworkGraphState { + identifier: string; + } + + export default class NetworkGraph extends Component< + NetworkGraphProps, + NetworkGraphState + > { + render(): JSX.Element; + } +} diff --git a/frontend/src/utils/getSpanTreeMetadata.ts b/frontend/src/utils/getSpanTreeMetadata.ts deleted file mode 100644 index 2938507603..0000000000 --- a/frontend/src/utils/getSpanTreeMetadata.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { errorColor } from 'lib/getRandomColor'; -import { ITraceTree } from 'types/api/trace/getTraceItem'; -/** - * Traverses the Span Tree data and returns the relevant meta data. - * Metadata includes globalStart, globalEnd, - */ -export const getSpanTreeMetadata = ( - treeData: ITraceTree, - spanServiceColours: { [key: string]: string }, -) => { - let globalStart = Number.POSITIVE_INFINITY; - let globalEnd = Number.NEGATIVE_INFINITY; - let totalSpans = 0; - let levels = 1; - const traverse = (treeNode: ITraceTree, level: number = 0) => { - if (!treeNode) { - return; - } - totalSpans++; - levels = Math.max(levels, level); - const startTime = treeNode.startTime; - const endTime = startTime + treeNode.value / 1e6; - globalStart = Math.min(globalStart, startTime); - globalEnd = Math.max(globalEnd, endTime); - if (treeNode.hasError) { - treeNode.serviceColour = errorColor; - } else treeNode.serviceColour = spanServiceColours[treeNode.serviceName]; - for (const childNode of treeNode.children) { - traverse(childNode, level + 1); - } - }; - traverse(treeData, 1); - - return { - globalStart, - globalEnd, - spread: globalEnd - globalStart, - totalSpans, - levels, - treeData, - }; -}; diff --git a/frontend/src/utils/spanToTree.ts b/frontend/src/utils/spanToTree.ts index 0f50cf6d40..e56e9854ea 100644 --- a/frontend/src/utils/spanToTree.ts +++ b/frontend/src/utils/spanToTree.ts @@ -1,10 +1,9 @@ -import { cloneDeep } from 'lodash-es'; -import { ITraceTree, Span } from 'types/api/trace/getTraceItem'; +import { pushDStree, RefItem, span } from 'store/actions'; // PNOTE - should the data be taken from redux or only through props? - Directly as arguments -export const spanToTreeUtil = (originalList: Span[]): ITraceTree => { +export const spanToTreeUtil = (spanlist: span[]): pushDStree => { // Initializing tree. What should be returned is trace is empty? We should have better error handling - let tree: ITraceTree = { + let tree: pushDStree = { id: 'empty', name: 'default', value: 0, @@ -12,12 +11,8 @@ export const spanToTreeUtil = (originalList: Span[]): ITraceTree => { startTime: 0, tags: [], children: [], - serviceColour: '', - serviceName: '', }; - let spanlist = cloneDeep(originalList); - // let spans :spanItem[]= trace.spans; if (spanlist) { @@ -29,15 +24,12 @@ export const spanToTreeUtil = (originalList: Span[]): ITraceTree => { //May1 //https://stackoverflow.com/questions/13315131/enforcing-the-type-of-the-indexed-members-of-a-typescript-object - const mapped_array: { [id: string]: Span } = {}; - const originalListArray: { [id: string]: Span } = {}; + const mapped_array: { [id: string]: span } = {}; for (let i = 0; i < spanlist.length; i++) { - originalListArray[spanlist[i][1]] = originalList[i]; - mapped_array[spanlist[i][1]] = spanlist[i]; - mapped_array[spanlist[i][1]][10] = []; //initialising the 10th element in the Span data structure which is array - // of type ITraceTree + mapped_array[spanlist[i][1]][10] = []; //initialising the 10th element in the span data structure which is array + // of type pushDStree // console.log('IDs while creating mapped array') // console.log(`SpanID is ${spanlist[i][1]}\n`); } @@ -62,22 +54,15 @@ export const spanToTreeUtil = (originalList: Span[]): ITraceTree => { } } - const push_object: ITraceTree = { + const push_object: pushDStree = { id: child_span[1], - name: child_span[4], + name: child_span[3] + ': ' + child_span[4], value: parseInt(child_span[6]), time: parseInt(child_span[6]), startTime: child_span[0], tags: tags_temp, children: mapped_array[id][10], - serviceName: child_span[3], - hasError: !!child_span[11], - serviceColour: '', - event: originalListArray[id][10].map((e) => { - return JSON.parse(decodeURIComponent(e || '{}')) || {}; - }), }; - const referencesArr = mapped_array[id][9]; let refArray = []; if (typeof referencesArr === 'string') { @@ -85,7 +70,7 @@ export const spanToTreeUtil = (originalList: Span[]): ITraceTree => { } else { refArray = referencesArr; } - const references = []; + const references: RefItem[] = []; refArray.forEach((element) => { element = element @@ -131,5 +116,5 @@ export const spanToTreeUtil = (originalList: Span[]): ITraceTree => { } // end of for loop } // end of if(spans) - return { ...tree }; + return tree; }; diff --git a/frontend/src/utils/toFixed.ts b/frontend/src/utils/toFixed.ts deleted file mode 100644 index 6aabbb267e..0000000000 --- a/frontend/src/utils/toFixed.ts +++ /dev/null @@ -1,6 +0,0 @@ -export const toFixed = (input: number, fixedCount: number) => { - if (input.toString().split('.').length > 1) { - return input.toFixed(fixedCount); - } - return input; -}; diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 3ff85194f8..b43a985abc 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -18,8 +18,7 @@ "isolatedModules": true, "noEmit": true, "baseUrl": "./src", - "downlevelIteration": true, - "plugins": [{ "name": "typescript-plugin-css-modules" }] + "downlevelIteration": true }, "exclude": ["node_modules"], "include": ["./src"] diff --git a/frontend/webpack.config.js b/frontend/webpack.config.js index 549f98e0d1..5b94f0f903 100644 --- a/frontend/webpack.config.js +++ b/frontend/webpack.config.js @@ -61,15 +61,7 @@ const config = { }, { test: /\.css$/, - use: [ - 'style-loader', - { - loader: 'css-loader', - options: { - modules: true, - }, - }, - ], + use: ['style-loader', 'css-loader'], }, { test: /\.(jpe?g|png|gif|svg)$/i, @@ -90,9 +82,6 @@ const config = { }, { loader: 'css-loader', - options: { - modules: true, - }, }, { loader: 'less-loader', diff --git a/frontend/webpack.config.prod.js b/frontend/webpack.config.prod.js index 7ccc97d6ba..291fa84e15 100644 --- a/frontend/webpack.config.prod.js +++ b/frontend/webpack.config.prod.js @@ -74,15 +74,7 @@ const config = { }, { test: /\.css$/, - use: [ - MiniCssExtractPlugin.loader, - { - loader: 'css-loader', - options: { - modules: true, - }, - }, - ], + use: [MiniCssExtractPlugin.loader, 'css-loader'], }, { test: /\.(jpe?g|png|gif|svg)$/i, @@ -103,9 +95,6 @@ const config = { }, { loader: 'css-loader', - options: { - modules: true, - }, }, { loader: 'less-loader', diff --git a/frontend/yarn.lock b/frontend/yarn.lock index dd0fab967c..9bdfc03964 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -1773,25 +1773,6 @@ dependencies: "@types/node" "*" -"@types/color-convert@*": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@types/color-convert/-/color-convert-2.0.0.tgz#8f5ee6b9e863dcbee5703f5a517ffb13d3ea4e22" - integrity sha512-m7GG7IKKGuJUXvkZ1qqG3ChccdIM/qBBo913z+Xft0nKCX4hAU/IxKwZBU4cpRZ7GS5kV4vOblUkILtSShCPXQ== - dependencies: - "@types/color-name" "*" - -"@types/color-name@*": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" - integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== - -"@types/color@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/color/-/color-3.0.3.tgz#e6d8d72b7aaef4bb9fe80847c26c7c786191016d" - integrity sha512-X//qzJ3d3Zj82J9sC/C18ZY5f43utPbAJ6PhYt/M7uG6etcF6MRpKdN880KBy43B0BMzSfeT96MzrsNjFI3GbA== - dependencies: - "@types/color-convert" "*" - "@types/compression-webpack-plugin@^9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@types/compression-webpack-plugin/-/compression-webpack-plugin-9.0.0.tgz#d7d504e2268e84e1413a99c072d6ff9aee31f213" @@ -2165,11 +2146,6 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/js-cookie@^2.2.6": - version "2.2.7" - resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-2.2.7.tgz#226a9e31680835a6188e887f3988e60c04d3f6a3" - integrity sha512-aLkWa0C0vO5b4Sr798E26QgOkss68Un0bLjs7u9qxzPT5CG+8DuNTffWES58YzJs3hrVAOs1wonycqEBqNJubA== - "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.9" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" @@ -2645,11 +2621,6 @@ dependencies: lodash "^4" -"@xobotyi/scrollbar-width@^1.9.5": - version "1.9.5" - resolved "https://registry.yarnpkg.com/@xobotyi/scrollbar-width/-/scrollbar-width-1.9.5.tgz#80224a6919272f405b87913ca13b92929bdf3c4d" - integrity sha512-N8tkAACJx2ww8vFMneJmaAgmjAG1tnVBZJRLRcx061tmsLRZHSEZSLuGWnwPtunsSLvSqXQ2wfp7Mgqg1I+2dQ== - "@xtuc/ieee754@^1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" @@ -3566,11 +3537,6 @@ bcrypt-pbkdf@^1.0.0: resolved "https://registry.yarnpkg.com/bezier-js/-/bezier-js-4.1.1.tgz#414df656833104e86765c0fa5e31439fb3e83a34" integrity sha512-oVOS6SSFFFlfnZdzC+lsfvhs/RRcbxJ47U04M4s5QIBaJmr3YWmTIL3qmrOK9uW+nUUcl9Jccmo/xpTrG+bBoQ== -big.js@^3.1.3: - version "3.2.0" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" - integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q== - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -3886,7 +3852,7 @@ chalk@2.1.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" -chalk@^2.0.0, chalk@^2.4.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -3931,21 +3897,6 @@ check-more-types@^2.24.0: resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" integrity sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA= -"chokidar@>=3.0.0 <4.0.0": - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - chokidar@^3.5.1, chokidar@^3.5.2: version "3.5.2" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" @@ -4108,27 +4059,11 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= -color-name@^1.0.0, color-name@~1.1.4: +color-name@~1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -color-string@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.0.tgz#63b6ebd1bec11999d1df3a79a7569451ac2be8aa" - integrity sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ== - dependencies: - color-name "^1.0.0" - simple-swizzle "^0.2.2" - -color@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/color/-/color-4.2.1.tgz#498aee5fce7fc982606c8875cab080ac0547c884" - integrity sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw== - dependencies: - color-convert "^2.0.1" - color-string "^1.9.0" - colord@^2.9.1: version "2.9.1" resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.1.tgz#c961ea0efeb57c9f0f4834458f26cb9cc4a3f90e" @@ -4285,7 +4220,7 @@ copy-descriptor@^0.1.0: resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= -copy-to-clipboard@^3.2.0, copy-to-clipboard@^3.3.1: +copy-to-clipboard@^3.2.0: version "3.3.1" resolved "https://registry.yarnpkg.com/copy-to-clipboard/-/copy-to-clipboard-3.3.1.tgz#115aa1a9998ffab6196f93076ad6da3b913662ae" integrity sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw== @@ -4426,14 +4361,6 @@ css-declaration-sorter@^6.0.3: dependencies: timsort "^0.3.0" -css-in-js-utils@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/css-in-js-utils/-/css-in-js-utils-2.0.1.tgz#3b472b398787291b47cfe3e44fecfdd9e914ba99" - integrity sha512-PJF0SpJT+WdbVVt0AOYp9C8GnuruRlL/UFW7932nLWmFLQTaWEzTBQEx7/hn4BuV+WON75iAViSUJLiU3PKbpA== - dependencies: - hyphenate-style-name "^1.0.2" - isobject "^3.0.1" - css-loader@4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-4.3.0.tgz#c888af64b2a5b2e85462c72c0f4a85c7e2e0821e" @@ -4465,13 +4392,6 @@ css-minimizer-webpack-plugin@^3.2.0: serialize-javascript "^6.0.0" source-map "^0.6.1" -css-parse@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/css-parse/-/css-parse-2.0.0.tgz#a468ee667c16d81ccf05c58c38d2a97c780dbfd4" - integrity sha1-pGjuZnwW2BzPBcWMONKpfHgNv9Q= - dependencies: - css "^2.0.0" - css-select@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" @@ -4483,14 +4403,6 @@ css-select@^4.1.3: domutils "^2.6.0" nth-check "^2.0.0" -css-selector-tokenizer@^0.7.0: - version "0.7.3" - resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.3.tgz#735f26186e67c749aaf275783405cf0661fae8f1" - integrity sha512-jWQv3oCEL5kMErj4wRnK/OPoBi0D+P1FR2cDCKYPaMeD2eW3/mttav8HT4hT1CKopiJI/psEULjkClhvJo4Lvg== - dependencies: - cssesc "^3.0.0" - fastparse "^1.1.2" - css-to-react-native@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-3.0.0.tgz#62dbe678072a824a689bcfee011fc96e02a7d756" @@ -4518,16 +4430,6 @@ css.escape@^1.5.1: resolved "https://registry.yarnpkg.com/css.escape/-/css.escape-1.5.1.tgz#42e27d4fa04ae32f931a4b4d4191fa9cddee97cb" integrity sha1-QuJ9T6BK4y+TGktNQZH6nN3ul8s= -css@^2.0.0: - version "2.2.4" - resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" - integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== - dependencies: - inherits "^2.0.3" - source-map "^0.6.1" - source-map-resolve "^0.5.2" - urix "^0.1.0" - css@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" @@ -4616,7 +4518,7 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" -csstype@^3.0.2, csstype@^3.0.6: +csstype@^3.0.2: version "3.0.10" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== @@ -5270,13 +5172,6 @@ debug@ngokevin/debug#noTimestamp: version "2.2.0" resolved "https://codeload.github.com/ngokevin/debug/tar.gz/ef5f8e66d49ce8bc64c6f282c15f8b7164409e3a" -debug@~3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -5572,11 +5467,6 @@ dotenv@8.2.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a" integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw== -dotenv@^10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== - dtype@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/dtype/-/dtype-2.0.0.tgz#cd052323ce061444ecd2e8f5748f69a29be28434" @@ -5615,11 +5505,6 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== -emojis-list@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" - integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= - emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -5676,13 +5561,6 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error-stack-parser@^2.0.6: - version "2.0.7" - resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.7.tgz#b0c6e2ce27d0495cf78ad98715e0cad1219abb57" - integrity sha512-chLOW0ZGRf4s8raLrDxa5sdkvPec5YdvwbFnqJme4rk0rFajP8mPtrDL1+I+CwrQDCjswDA5sREX7jYQDQs9vA== - dependencies: - stackframe "^1.1.1" - es-abstract@^1.19.0, es-abstract@^1.19.1: version "1.19.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" @@ -6216,26 +6094,11 @@ fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= -fast-shallow-equal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-shallow-equal/-/fast-shallow-equal-1.0.0.tgz#d4dcaf6472440dcefa6f88b98e3251e27f25628b" - integrity sha512-HPtaa38cPgWvaCFmRNhlc6NG7pv6NUHqjPgVAkWGoB9mQMwYB27/K0CvOM5Czy+qpT3e8XJ6Q4aPAnzpNpzNaw== - fastest-levenshtein@^1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2" integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow== -fastest-stable-stringify@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/fastest-stable-stringify/-/fastest-stable-stringify-2.0.2.tgz#3757a6774f6ec8de40c4e86ec28ea02417214c76" - integrity sha512-bijHueCGd0LqqNK9b5oCMHc0MluJAx0cwqASgbWMvkO01lCYgIhacVRLcaDz3QnyYIRNJRDwMb41VuT6pHJ91Q== - -fastparse@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9" - integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ== - fastq@^1.6.0: version "1.13.0" resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" @@ -6511,13 +6374,6 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -generic-names@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-1.0.3.tgz#2d786a121aee508876796939e8e3bff836c20917" - integrity sha1-LXhqEhruUIh2eWk56OO/+DbCCRc= - dependencies: - loader-utils "^0.2.16" - gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -6622,7 +6478,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: version "7.2.0" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== @@ -6988,11 +6844,6 @@ husky@4.3.8: slash "^3.0.0" which-pm-runs "^1.0.0" -hyphenate-style-name@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d" - integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ== - iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -7000,13 +6851,6 @@ iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" -icss-utils@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-3.0.1.tgz#ee70d3ae8cac38c6be5ed91e851b27eed343ad0f" - integrity sha1-7nDTroysOMa+XtkehRsn7tNDrQ8= - dependencies: - postcss "^6.0.2" - icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" @@ -7014,11 +6858,6 @@ icss-utils@^4.0.0, icss-utils@^4.1.1: dependencies: postcss "^7.0.14" -icss-utils@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" - integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== - ieee754@^1.1.13: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" @@ -7050,11 +6889,6 @@ image-size@~0.5.0: resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c" integrity sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w= -immutable@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23" - integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw== - import-fresh@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" @@ -7122,13 +6956,6 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inline-style-prefixer@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-6.0.1.tgz#c5c0e43ba8831707afc5f5bbfd97edf45c1fa7ae" - integrity sha512-AsqazZ8KcRzJ9YPN1wMH2aNM7lkWQ8tSPrW5uDk1ziYwiAPWSZnUsC7lfZq+BDqLqz0B4Pho5wscWcJzVvRzDQ== - dependencies: - css-in-js-utils "^2.0.0" - internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" @@ -7200,11 +7027,6 @@ is-arrayish@^0.2.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= -is-arrayish@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" - integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== - is-bigint@^1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" @@ -7984,11 +7806,6 @@ jest@26.6.0: import-local "^3.0.2" jest-cli "^26.6.0" -js-cookie@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" - integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -8092,11 +7909,6 @@ json2mq@^0.2.0: dependencies: string-convert "^0.2.0" -json5@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - json5@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" @@ -8208,7 +8020,7 @@ less-plugin-npm-import@^2.1.0: promise "~7.0.1" resolve "~1.1.6" -less@^4.1.1, less@^4.1.2: +less@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/less/-/less-4.1.2.tgz#6099ee584999750c2624b65f80145f8674e4b4b0" integrity sha512-EoQp/Et7OSOVu0aJknJOtlXZsnr8XE8KwuzTHOLeVSEx8pVWUICc8Q0VYRHgzyjX78nMEyC/oztWFbgyhtNfDA== @@ -8246,7 +8058,7 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lilconfig@^2.0.3, lilconfig@^2.0.4: +lilconfig@^2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== @@ -8310,16 +8122,6 @@ loader-runner@^4.2.0: resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384" integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw== -loader-utils@^0.2.16: - version "0.2.17" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" - integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g= - dependencies: - big.js "^3.1.3" - emojis-list "^2.0.0" - json5 "^0.5.0" - object-assign "^4.0.1" - loader-utils@^1.1.0, loader-utils@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" @@ -8373,11 +8175,6 @@ lodash-es@^4.17.21: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== -lodash.camelcase@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" - integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= - lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" @@ -8418,7 +8215,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.7.0: +lodash@^4, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -8683,11 +8480,6 @@ mkdirp@^0.5.3, mkdirp@^0.5.5: dependencies: minimist "^1.2.5" -mkdirp@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - moment@>=2.13.0, moment@^2.24.0, moment@^2.25.3: version "2.29.1" resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" @@ -8741,20 +8533,6 @@ nan@^2.14.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee" integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ== -nano-css@^5.3.1: - version "5.3.4" - resolved "https://registry.yarnpkg.com/nano-css/-/nano-css-5.3.4.tgz#40af6a83a76f84204f346e8ccaa9169cdae9167b" - integrity sha512-wfcviJB6NOxDIDfr7RFn/GlaN7I/Bhe4d39ZRCJ3xvZX60LVe2qZ+rDqM49nm4YT81gAjzS+ZklhKP/Gnfnubg== - dependencies: - css-tree "^1.1.2" - csstype "^3.0.6" - fastest-stable-stringify "^2.0.2" - inline-style-prefixer "^6.0.0" - rtl-css-js "^1.14.0" - sourcemap-codec "^1.4.8" - stacktrace-js "^2.0.2" - stylis "^4.0.6" - nanoid@^2.0.3: version "2.1.11" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.1.11.tgz#ec24b8a758d591561531b4176a01e3ab4f0f0280" @@ -8765,11 +8543,6 @@ nanoid@^3.1.30: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.30.tgz#63f93cc548d2a113dc5dfbc63bfa09e2b9b64362" integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ== -nanoid@^3.2.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - nanomatch@^1.2.9: version "1.2.13" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" @@ -9319,11 +9092,14 @@ parse-json@^5.0.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" + parse-node-version@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== +parse5@6.0.1: + parse5-htmlparser2-tree-adapter@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" @@ -9332,6 +9108,7 @@ parse5-htmlparser2-tree-adapter@^6.0.1: parse5 "^6.0.1" parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== @@ -9567,41 +9344,6 @@ postcss-discard-overridden@^5.0.1: resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6" integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q== -postcss-filter-plugins@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-3.0.1.tgz#9d226e946d56542ab7c26123053459a331df545d" - integrity sha512-tRKbW4wWBEkSSFuJtamV2wkiV9rj6Yy7P3Y13+zaynlPEEZt8EgYKn3y/RBpMeIhNmHXFlSdzofml65hD5OafA== - dependencies: - postcss "^6.0.14" - -postcss-icss-keyframes@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/postcss-icss-keyframes/-/postcss-icss-keyframes-0.2.1.tgz#80c4455e0112b0f2f9c3c05ac7515062bb9ff295" - integrity sha1-gMRFXgESsPL5w8Bax1FQYruf8pU= - dependencies: - icss-utils "^3.0.1" - postcss "^6.0.2" - postcss-value-parser "^3.3.0" - -postcss-icss-selectors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/postcss-icss-selectors/-/postcss-icss-selectors-2.0.3.tgz#27fa1afcaab6c602c866cbb298f3218e9bc1c9b3" - integrity sha1-J/oa/Kq2xgLIZsuymPMhjpvBybM= - dependencies: - css-selector-tokenizer "^0.7.0" - generic-names "^1.0.2" - icss-utils "^3.0.1" - lodash "^4.17.4" - postcss "^6.0.2" - -postcss-load-config@^3.0.1: - version "3.1.3" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.3.tgz#21935b2c43b9a86e6581a576ca7ee1bde2bd1d23" - integrity sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw== - dependencies: - lilconfig "^2.0.4" - yaml "^1.10.2" - postcss-merge-longhand@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz#41f4f3270282ea1a145ece078b7679f0cef21c32" @@ -9802,11 +9544,6 @@ postcss-unique-selectors@^5.0.2: alphanum-sort "^1.0.2" postcss-selector-parser "^6.0.5" -postcss-value-parser@^3.3.0: - version "3.3.1" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz#9ff822547e2893213cf1c30efa51ac5fd1ba8281" - integrity sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ== - postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" @@ -9820,24 +9557,6 @@ postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: picocolors "^0.2.1" source-map "^0.6.1" -postcss@^6.0.14, postcss@^6.0.2: - version "6.0.23" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.23.tgz#61c82cc328ac60e677645f979054eb98bc0e3324" - integrity sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag== - dependencies: - chalk "^2.4.1" - source-map "^0.6.1" - supports-color "^5.4.0" - -postcss@^8.3.0: - version "8.4.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1" - integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA== - dependencies: - nanoid "^3.2.0" - picocolors "^1.0.0" - source-map-js "^1.0.2" - postcss@^8.3.5: version "8.4.4" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.4.tgz#d53d4ec6a75fd62557a66bb41978bf47ff0c2869" @@ -10602,31 +10321,6 @@ react-router@5.2.1: tiny-invariant "^1.0.2" tiny-warning "^1.0.0" -react-universal-interface@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/react-universal-interface/-/react-universal-interface-0.6.2.tgz#5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b" - integrity sha512-dg8yXdcQmvgR13RIlZbTRQOoUrDciFVoSBZILwjE2LFISxZZ8loVJKAkuzswl5js8BHda79bIb2b84ehU8IjXw== - -react-use@^17.3.2: - version "17.3.2" - resolved "https://registry.yarnpkg.com/react-use/-/react-use-17.3.2.tgz#448abf515f47c41c32455024db28167cb6e53be8" - integrity sha512-bj7OD0/1wL03KyWmzFXAFe425zziuTf7q8olwCYBfOeFHY1qfO1FAMjROQLsLZYwG4Rx63xAfb7XAbBrJsZmEw== - dependencies: - "@types/js-cookie" "^2.2.6" - "@xobotyi/scrollbar-width" "^1.9.5" - copy-to-clipboard "^3.3.1" - fast-deep-equal "^3.1.3" - fast-shallow-equal "^1.0.0" - js-cookie "^2.2.1" - nano-css "^5.3.1" - react-universal-interface "^0.6.2" - resize-observer-polyfill "^1.5.1" - screenfull "^5.1.0" - set-harmonic-interval "^1.0.1" - throttle-debounce "^3.0.1" - ts-easing "^0.2.0" - tslib "^2.1.0" - react-vis@^1.11.7: version "1.11.7" resolved "https://registry.yarnpkg.com/react-vis/-/react-vis-1.11.7.tgz#909902af00158895d14da1adfe1d0dc0045228ff" @@ -10861,11 +10555,6 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= -reserved-words@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.2.tgz#00a0940f98cd501aeaaac316411d9adc52b31ab1" - integrity sha1-AKCUD5jNUBrqqsMWQR2a3FKzGrE= - resize-observer-polyfill@^1.5.0, resize-observer-polyfill@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" @@ -10964,13 +10653,6 @@ rsvp@^4.8.4: resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -rtl-css-js@^1.14.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/rtl-css-js/-/rtl-css-js-1.15.0.tgz#680ed816e570a9ebccba9e1cd0f202c6a8bb2dc0" - integrity sha512-99Cu4wNNIhrI10xxUaABHsdDqzalrSRTie4GeCmbGVuehm4oj+fIy8fTzB+16pmKe8Bv9rl+hxIBez6KxExTew== - dependencies: - "@babel/runtime" "^7.1.2" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -11007,7 +10689,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@^2.1.2, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -11027,16 +10709,7 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" -sass@^1.32.13: - version "1.49.7" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.7.tgz#22a86a50552b9b11f71404dfad1b9ff44c6b0c49" - integrity sha512-13dml55EMIR2rS4d/RDHHP0sXMY3+30e1TKsyXaSz3iLWVoDWEoboY8WzJd5JMnxrRHffKO3wq2mpJ0jxRJiEQ== - dependencies: - chokidar ">=3.0.0 <4.0.0" - immutable "^4.0.0" - source-map-js ">=0.6.2 <2.0.0" - -sax@>=0.6.0, sax@^1.2.4, sax@~1.2.4: +sax@>=0.6.0, sax@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== @@ -11084,11 +10757,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.0.0" -screenfull@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba" - integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA== - scroll-into-view-if-needed@^2.2.25: version "2.2.28" resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.28.tgz#5a15b2f58a52642c88c8eca584644e01703d645a" @@ -11201,11 +10869,6 @@ set-blocking@^2.0.0, set-blocking@~2.0.0: resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= -set-harmonic-interval@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz#e1773705539cdfb80ce1c3d99e7f298bb3995249" - integrity sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g== - set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -11304,13 +10967,6 @@ simple-get@^3.0.3: once "^1.3.1" simple-concat "^1.0.0" -simple-swizzle@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" - integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= - dependencies: - is-arrayish "^0.3.1" - sirv@^1.0.7: version "1.0.19" resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" @@ -11392,17 +11048,12 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - source-map-js@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf" integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA== -source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: +source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== @@ -11434,11 +11085,6 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@0.5.6: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - integrity sha1-dc449SvwczxafwwRjYEzSiu19BI= - source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -11454,11 +11100,6 @@ source-map@^0.7.3, source-map@~0.7.2: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== -sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -11540,13 +11181,6 @@ stable@^0.1.8: resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== -stack-generator@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/stack-generator/-/stack-generator-2.0.5.tgz#fb00e5b4ee97de603e0773ea78ce944d81596c36" - integrity sha512-/t1ebrbHkrLrDuNMdeAcsvynWgoH/i4o8EGGfX7dEYDoTXOYVAkEpFdtshlvabzc6JlJ8Kf9YdFEoz7JkzGN9Q== - dependencies: - stackframe "^1.1.1" - stack-utils@^2.0.2: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" @@ -11554,28 +11188,6 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" -stackframe@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.1.tgz#1033a3473ee67f08e2f2fc8eba6aef4f845124e1" - integrity sha512-h88QkzREN/hy8eRdyNhhsO7RSJ5oyTqxxmmn0dzBIMUclZsjpfmrsg81vp8mjjAs2vAZ72nyWxRUwSwmh0e4xg== - -stacktrace-gps@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/stacktrace-gps/-/stacktrace-gps-3.0.4.tgz#7688dc2fc09ffb3a13165ebe0dbcaf41bcf0c69a" - integrity sha512-qIr8x41yZVSldqdqe6jciXEaSCKw1U8XTXpjDuy0ki/apyTn/r3w9hDAAQOhZdxvsC93H+WwwEu5cq5VemzYeg== - dependencies: - source-map "0.5.6" - stackframe "^1.1.1" - -stacktrace-js@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/stacktrace-js/-/stacktrace-js-2.0.2.tgz#4ca93ea9f494752d55709a081d400fdaebee897b" - integrity sha512-Je5vBeY4S1r/RnLydLl0TBTi3F2qdfWmYsGvtfZgEI+SCprPppaIhQf5nGcal4gI4cGpCV/duLcAzT1np6sQqg== - dependencies: - error-stack-parser "^2.0.6" - stack-generator "^2.0.5" - stacktrace-gps "^3.0.4" - static-extend@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" @@ -11773,25 +11385,6 @@ stylehacks@^5.0.1: browserslist "^4.16.0" postcss-selector-parser "^6.0.4" -stylis@^4.0.6: - version "4.0.13" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== - -stylus@^0.54.8: - version "0.54.8" - resolved "https://registry.yarnpkg.com/stylus/-/stylus-0.54.8.tgz#3da3e65966bc567a7b044bfe0eece653e099d147" - integrity sha512-vr54Or4BZ7pJafo2mpf0ZcwA74rpuYCZbxrHBsH8kbcXOwSfvBFwsRfpGO5OD5fhG5HDCFW737PKaawI7OqEAg== - dependencies: - css-parse "~2.0.0" - debug "~3.1.0" - glob "^7.1.6" - mkdirp "~1.0.4" - safer-buffer "^2.1.2" - sax "~1.2.4" - semver "^6.3.0" - source-map "^0.7.3" - super-animejs@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/super-animejs/-/super-animejs-3.1.0.tgz#59435946faafe880710e348cf24ad3126e45aed1" @@ -11809,7 +11402,7 @@ supports-color@^4.0.0: dependencies: has-flag "^2.0.0" -supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: +supports-color@^5.3.0, supports-color@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== @@ -12003,11 +11596,6 @@ throat@^5.0.0: resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== -throttle-debounce@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/throttle-debounce/-/throttle-debounce-3.0.1.tgz#32f94d84dfa894f786c9a1f290e7a645b6a19abb" - integrity sha512-dTEWWNu6JmeVXY0ZYoPuH5cRIwc0MeGbJwah9KUNYSJwommQpCzTySTpEe8Gs1J23aeWEuAobe4Ag7EHVt/LOg== - throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" @@ -12136,11 +11724,6 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" -ts-easing@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/ts-easing/-/ts-easing-0.2.0.tgz#c8a8a35025105566588d87dbda05dd7fbfa5a4ec" - integrity sha512-Z86EW+fFFh/IFB1fqQ3/+7Zpf9t2ebOAxNI/V6Wo7r5gqiqtxmgTlQ1qbqQcjLKYeSHPTsEmvlJUDg/EuL0uHQ== - ts-node@^10.2.1: version "10.4.0" resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" @@ -12183,7 +11766,7 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0: +tslib@^2.0.3, tslib@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== @@ -12266,25 +11849,6 @@ typedarray-to-buffer@^3.1.5: dependencies: is-typedarray "^1.0.0" -typescript-plugin-css-modules@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/typescript-plugin-css-modules/-/typescript-plugin-css-modules-3.4.0.tgz#4ff6905d88028684d1608c05c62cb6346e5548cc" - integrity sha512-2MdjfSg4MGex1csCWRUwKD+MpgnvcvLLr9bSAMemU/QYGqBsXdez0cc06H/fFhLtRoKJjXg6PSTur3Gy1Umhpw== - dependencies: - dotenv "^10.0.0" - icss-utils "^5.1.0" - less "^4.1.1" - lodash.camelcase "^4.3.0" - postcss "^8.3.0" - postcss-filter-plugins "^3.0.1" - postcss-icss-keyframes "^0.2.1" - postcss-icss-selectors "^2.0.3" - postcss-load-config "^3.0.1" - reserved-words "^0.1.2" - sass "^1.32.13" - stylus "^0.54.8" - tsconfig-paths "^3.9.0" - typescript@^4.0.5: version "4.5.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.2.tgz#8ac1fba9f52256fdb06fb89e4122fa6a346c2998" diff --git a/pkg/query-service/model/response.go b/pkg/query-service/model/response.go index 7526505d33..fb5c460747 100644 --- a/pkg/query-service/model/response.go +++ b/pkg/query-service/model/response.go @@ -205,8 +205,17 @@ func (item *SearchSpanReponseItem) GetValues() []interface{} { for _, item := range references { referencesStringArray = append(referencesStringArray, item.toString()) } + var errorEvent map[string]interface{} + for _, e := range item.Events { + json.Unmarshal([]byte(e), &errorEvent) + if errorEvent["name"] == "exception" { + break + } else { + errorEvent = nil + } + } - returnArray := []interface{}{int64(timeObj.UnixNano() / 1000000), item.SpanID, item.TraceID, item.ServiceName, item.Name, strconv.Itoa(int(item.Kind)), strconv.FormatInt(item.DurationNano, 10), item.TagsKeys, item.TagsValues, referencesStringArray, item.Events, item.HasError} + returnArray := []interface{}{int64(timeObj.UnixNano() / 1000000), item.SpanID, item.TraceID, item.ServiceName, item.Name, strconv.Itoa(int(item.Kind)), strconv.FormatInt(item.DurationNano, 10), item.TagsKeys, item.TagsValues, referencesStringArray, errorEvent, item.HasError} return returnArray } diff --git a/pkg/query-service/telemetry/telemetry.go b/pkg/query-service/telemetry/telemetry.go index 8a60be19da..5de8392e0c 100644 --- a/pkg/query-service/telemetry/telemetry.go +++ b/pkg/query-service/telemetry/telemetry.go @@ -22,7 +22,6 @@ const ( ) const api_key = "4Gmoa4ixJAUHx2BpJxsjwA1bEfnwEeRz" -const IP_NOT_FOUND_PLACEHOLDER = "NA" var telemetry *Telemetry var once sync.Once @@ -60,7 +59,7 @@ func createTelemetry() { // Get preferred outbound ip of this machine func getOutboundIP() string { - ip := []byte(IP_NOT_FOUND_PLACEHOLDER) + ip := []byte("NA") resp, err := http.Get("https://api.ipify.org?format=text") if err != nil { @@ -117,7 +116,7 @@ func (a *Telemetry) SendEvent(event string, data map[string]interface{}) { } userId := a.ipAddress - if a.isTelemetryAnonymous() || userId == IP_NOT_FOUND_PLACEHOLDER { + if a.isTelemetryAnonymous() { userId = a.GetDistinctId() } diff --git a/sample-apps/hotrod/README.md b/sample-apps/hotrod/README.md deleted file mode 100644 index 1907c23dfc..0000000000 --- a/sample-apps/hotrod/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# HotROD Sample Application (Kubernetes) - -Follow the steps in this section to install a sample application named HotR.O.D, and generate tracing data. - -```console -kubectl create ns sample-application - -kubectl -n sample-application apply -f https://github.com/SigNoz/signoz/raw/main/sample-apps/hotrod/hotrod.yaml -``` - -In case, you have installed SigNoz in namespace other than `platform` or selected Helm release name other than `my-release`, follow the steps below: - -```console -export HELM_RELEASE=my-release-2 -export SIGNOZ_NAMESPACE=platform-2 -export HOTROD_NAMESPACE=sample-application-2 - -curl -sL https://github.com/SigNoz/signoz/raw/main/sample-apps/hotrod/hotrod-install.sh | bash -``` - -To delete sample application: - -```console -export HOTROD_NAMESPACE=sample-application-2 - -curl -sL https://github.com/SigNoz/signoz/raw/main/sample-apps/hotrod/hotrod-delete.sh | bash -``` diff --git a/sample-apps/hotrod/hotrod-delete.sh b/sample-apps/hotrod/hotrod-delete.sh deleted file mode 100755 index f73f89c1a6..0000000000 --- a/sample-apps/hotrod/hotrod-delete.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -cd "$(dirname "${BASH_SOURCE[0]}")"; - -HOTROD_NAMESPACE=${HOTROD_NAMESPACE:-"sample-application"} - -if [[ "${HOTROD_NAMESPACE}" == "default" || "${HOTROD_NAMESPACE}" == "kube-system" || "${HOTROD_NAMESPACE}" == "platform" ]]; then - echo "Default k8s namespace and SigNoz namespace must not be deleted" - echo "Deleting components only" - kubectl delete --namespace="${HOTROD_NAMESPACE}" -f <(cat hotrod-template.yaml || curl -sL https://github.com/SigNoz/signoz/raw/main/sample-apps/hotrod/hotrod-template.yaml) -else - echo "Delete HotROD sample app namespace ${HOTROD_NAMESPACE}" - kubectl delete namespace "${HOTROD_NAMESPACE}" -fi - -if [ $? -ne 0 ]; then - echo "❌ Failed to delete HotROD sample application" -else - echo "✅ Succesfully deleted HotROD sample application" -fi diff --git a/sample-apps/hotrod/hotrod-install.sh b/sample-apps/hotrod/hotrod-install.sh deleted file mode 100755 index f6f3845205..0000000000 --- a/sample-apps/hotrod/hotrod-install.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -cd "$(dirname "${BASH_SOURCE[0]}")"; - -# Namespace to install sample app -HOTROD_NAMESPACE=${HOTROD_NAMESPACE:-"sample-application"} -SIGNOZ_NAMESPACE="${SIGNOZ_NAMESPACE:-platform}" - -# HotROD's docker image -if [[ -z $HOTROD_IMAGE ]]; then - HOTROD_REPO="${HOTROD_REPO:-jaegertracing/example-hotrod}" - HOTROD_TAG="${HOTROD_TAG:-1.30}" - HOTROD_IMAGE="${HOTROD_REPO}:${HOTROD_TAG}" -fi - -# Locust's docker image -if [[ -z $LOCUST_IMAGE ]]; then - LOCUST_REPO="${LOCUST_REPO:-grubykarol/locust}" - LOCUST_TAG="${LOCUST_TAG:-0.8.1-py3.6}" - LOCUST_IMAGE="${LOCUST_REPO}:${LOCUST_TAG}" -fi - -# Helm release name -HELM_RELEASE="${HELM_RELEASE:-my-release}" - -# Otel Collector service address -if [[ -z $JAEGER_ENDPOINT ]]; then - if [[ "$HELM_RELEASE" == *"signoz"* ]]; then - JAEGER_ENDPOINT="http://${HELM_RELEASE}-otel-collector.${SIGNOZ_NAMESPACE}.svc.cluster.local:14268/api/traces" - else - JAEGER_ENDPOINT="http://${HELM_RELEASE}-signoz-otel-collector.${SIGNOZ_NAMESPACE}.svc.cluster.local:14268/api/traces" - fi -fi - -# Create namespace for sample application if does not exist -kubectl create namespace "$HOTROD_NAMESPACE" --save-config --dry-run -o yaml 2>/dev/null | kubectl apply -f - - -# Setup sample apps into specified namespace -kubectl apply --namespace="${HOTROD_NAMESPACE}" -f <( \ - (cat hotrod-template.yaml 2>/dev/null || curl -sL https://github.com/SigNoz/signoz/raw/main/sample-apps/hotrod/hotrod-template.yaml) | \ - HOTROD_NAMESPACE="${HOTROD_NAMESPACE}" \ - HOTROD_IMAGE="${HOTROD_IMAGE}" \ - LOCUST_IMAGE="${LOCUST_IMAGE}" \ - JAEGER_ENDPOINT="${JAEGER_ENDPOINT}" \ - envsubst \ - ) - -if [ $? -ne 0 ]; then - echo "❌ Failed to deploy HotROD sample application" -else - echo "✅ Succesfully deployed HotROD sample application" -fi diff --git a/sample-apps/hotrod/hotrod-template.yaml b/sample-apps/hotrod/hotrod-template.yaml deleted file mode 100644 index 6fdd6dd9ae..0000000000 --- a/sample-apps/hotrod/hotrod-template.yaml +++ /dev/null @@ -1,223 +0,0 @@ -apiVersion: v1 -kind: ConfigMap -metadata: - name: locust-cm -data: - ATTACKED_HOST: http://hotrod:8080 ---- -apiVersion: v1 -kind: ConfigMap -metadata: - name: scripts-cm -data: - locustfile.py: | - from locust import HttpLocust, TaskSet, task - class UserTasks(TaskSet): - @task - def rachel(self): - self.client.get("/dispatch?customer=123&nonse=0.6308392664170006") - @task - def trom(self): - self.client.get("/dispatch?customer=392&nonse=0.015296363321630757") - @task - def japanese(self): - self.client.get("/dispatch?customer=731&nonse=0.8022286220408668") - @task - def coffee(self): - self.client.get("/dispatch?customer=567&nonse=0.0022220379420636593") - class WebsiteUser(HttpLocust): - task_set = UserTasks ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - service: hotrod - name: hotrod -spec: - replicas: 1 - selector: - matchLabels: - service: hotrod - strategy: {} - template: - metadata: - labels: - service: hotrod - spec: - containers: - - args: - - all - env: - - name: JAEGER_ENDPOINT - value: ${JAEGER_ENDPOINT} - image: ${HOTROD_IMAGE} - imagePullPolicy: IfNotPresent - name: hotrod - ports: - - containerPort: 8080 - resources: - requests: - cpu: 100m - memory: 100Mi - limits: - cpu: 200m - memory: 200Mi - restartPolicy: Always ---- -apiVersion: v1 -kind: Service -metadata: - labels: - service: hotrod - name: hotrod -spec: - ports: - - name: "8080" - port: 8080 - targetPort: 8080 - selector: - service: hotrod ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - deployment.kubernetes.io/revision: "1" - labels: - role: locust-master - name: locust-master -spec: - replicas: 1 - selector: - matchLabels: - role: locust-master - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - role: locust-master - spec: - containers: - - image: ${LOCUST_IMAGE} - imagePullPolicy: IfNotPresent - name: locust-master - env: - - name: ATTACKED_HOST - valueFrom: - configMapKeyRef: - name: locust-cm - key: ATTACKED_HOST - - name: LOCUST_MODE - value: MASTER - - name: LOCUST_OPTS - value: --print-stats - volumeMounts: - - mountPath: /locust - name: locust-scripts - ports: - - containerPort: 5557 - name: comm - - containerPort: 5558 - name: comm-plus-1 - - containerPort: 8089 - name: web-ui - resources: - requests: - cpu: 100m - memory: 100Mi - limits: - cpu: 200m - memory: 200Mi - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 - volumes: - - name: locust-scripts - configMap: - name: scripts-cm ---- -apiVersion: v1 -kind: Service -metadata: - labels: - role: locust-master - name: locust-master -spec: - ports: - - port: 5557 - name: communication - - port: 5558 - name: communication-plus-1 - - port: 8089 - targetPort: 8089 - name: web-ui - selector: - role: locust-master ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - annotations: - deployment.kubernetes.io/revision: "1" - labels: - role: locust-slave - name: locust-slave -spec: - replicas: 1 - selector: - matchLabels: - role: locust-slave - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - template: - metadata: - labels: - role: locust-slave - spec: - containers: - - image: ${LOCUST_IMAGE} - imagePullPolicy: IfNotPresent - name: locust-slave - env: - - name: ATTACKED_HOST - valueFrom: - configMapKeyRef: - name: locust-cm - key: ATTACKED_HOST - - name: LOCUST_MODE - value: SLAVE - - name: LOCUST_MASTER - value: locust-master - volumeMounts: - - mountPath: /locust - name: locust-scripts - resources: - requests: - cpu: 100m - memory: 100Mi - limits: - cpu: 200m - memory: 200Mi - terminationMessagePath: /dev/termination-log - terminationMessagePolicy: File - dnsPolicy: ClusterFirst - restartPolicy: Always - schedulerName: default-scheduler - securityContext: {} - terminationGracePeriodSeconds: 30 - volumes: - - name: locust-scripts - configMap: - name: scripts-cm