From 1b79a9bf35a1ebb0e99f729d81ab125435cde0e1 Mon Sep 17 00:00:00 2001 From: Pranshu Chittora Date: Thu, 24 Mar 2022 11:44:38 +0530 Subject: [PATCH 01/15] feat: unit label on graph tooltip --- frontend/src/components/Graph/index.tsx | 15 +++++++++++++++ .../MetricsApplication/Tabs/Application.tsx | 4 ++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Graph/index.tsx b/frontend/src/components/Graph/index.tsx index 0659f686e1..ca97298f20 100644 --- a/frontend/src/components/Graph/index.tsx +++ b/frontend/src/components/Graph/index.tsx @@ -103,6 +103,21 @@ function Graph({ legend: { display: false, }, + tooltip: { + callbacks: { + label(context) { + let label = context.dataset.label || ''; + + if (label) { + label += ': '; + } + if (context.parsed.y !== null) { + label += getYAxisFormattedValue(context.parsed.y, yAxisUnit); + } + return label; + }, + }, + }, }, layout: { padding: 0, diff --git a/frontend/src/container/MetricsApplication/Tabs/Application.tsx b/frontend/src/container/MetricsApplication/Tabs/Application.tsx index bc072d5c97..774d8d7118 100644 --- a/frontend/src/container/MetricsApplication/Tabs/Application.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/Application.tsx @@ -187,7 +187,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element { widget={getWidget([ { query: `sum(rate(signoz_latency_count{service_name="${servicename}", span_kind="SPAN_KIND_SERVER"}[2m]))`, - legend: 'Request per second', + legend: 'Requests', }, ])} yAxisUnit="reqps" @@ -222,7 +222,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element { widget={getWidget([ { query: `max(sum(rate(signoz_calls_total{service_name="${servicename}", span_kind="SPAN_KIND_SERVER", status_code="STATUS_CODE_ERROR"}[1m]) OR rate(signoz_calls_total{service_name="${servicename}", span_kind="SPAN_KIND_SERVER", http_status_code=~"5.."}[1m]))*100/sum(rate(signoz_calls_total{service_name="${servicename}", span_kind="SPAN_KIND_SERVER"}[1m]))) < 1000 OR vector(0)`, - legend: 'Error Percentage (%)', + legend: 'Error Percentage', }, ])} yAxisUnit="%" From 01bad0f18a6b727677c89a86b2c76d99e5582d02 Mon Sep 17 00:00:00 2001 From: palash-signoz Date: Thu, 24 Mar 2022 12:06:57 +0530 Subject: [PATCH 02/15] chore: eslint fix (#884) * chore: eslint is updated * chore: some eslint fixes are made * chore: some more eslint fix are updated * chore: some eslint fix is made * chore: styled components type is added * chore: some more eslint fix are made * chore: some more eslint fix are updated * chore: some more eslint fix are updated * fix: eslint fixes Co-authored-by: Pranshu Chittora --- frontend/.eslintrc.js | 17 ++ frontend/package.json | 1 + frontend/src/api/ErrorResponseHandler.ts | 11 +- frontend/src/assets/Dashboard/Value.tsx | 4 +- frontend/src/components/DatePicker/index.tsx | 2 + frontend/src/components/Graph/index.tsx | 20 +- frontend/src/components/Graph/xAxisConfig.ts | 78 ++++--- frontend/src/components/Graph/yAxisConfig.ts | 1 - frontend/src/components/Input/index.tsx | 20 +- frontend/src/components/Modal.tsx | 5 + frontend/src/components/RouteTab/index.tsx | 11 +- frontend/src/components/Spinner/index.tsx | 5 + frontend/src/components/TextToolTip/index.tsx | 5 +- .../TimePreferenceDropDown/index.tsx | 6 +- frontend/src/constants/app.ts | 2 +- frontend/src/constants/localStorage.ts | 2 +- frontend/src/constants/query.ts | 1 + .../AllAlertChannels/AlertChannels.tsx | 2 +- frontend/src/container/AppLayout/index.tsx | 12 +- .../container/CreateAlertChannels/index.tsx | 6 +- .../src/container/EditAlertChannels/index.tsx | 7 +- .../src/container/FormAlertChannels/index.tsx | 7 +- .../container/GantChart/SpanLength/index.tsx | 23 +- .../container/GantChart/SpanLength/styles.ts | 19 +- .../container/GantChart/SpanName/index.tsx | 13 +- .../src/container/GantChart/Trace/index.tsx | 40 ++-- .../src/container/GantChart/Trace/styles.ts | 41 +++- frontend/src/container/GantChart/index.tsx | 7 +- frontend/src/container/GantChart/utils.ts | 50 +++-- .../container/GeneralSettings/Retention.tsx | 3 +- .../src/container/GeneralSettings/index.tsx | 25 ++- .../container/GridGraphComponent/index.tsx | 12 +- .../Graph/FullView/EmptyGraph.tsx | 4 +- .../GridGraphLayout/Graph/FullView/index.tsx | 17 +- .../container/GridGraphLayout/Graph/index.tsx | 13 +- .../src/container/GridGraphLayout/index.tsx | 2 - .../container/Header/Breadcrumbs/index.tsx | 9 +- .../Header/CustomDateTimeModal/index.tsx | 6 +- .../Header/DateTimeSelection/config.ts | 36 ++-- .../Header/DateTimeSelection/index.tsx | 88 ++++---- frontend/src/container/Header/index.tsx | 4 +- .../container/ListAlertRules/DeleteAlert.tsx | 10 +- .../container/ListAlertRules/ListAlert.tsx | 2 +- .../TableComponents/DeleteButton.tsx | 10 +- .../ListOfDashboard/TableComponents/Name.tsx | 6 +- .../ListOfDashboard/TableComponents/Tags.tsx | 5 +- .../MetricsApplication/Tabs/External.tsx | 8 +- .../MetricsApplication/TopEndpointsTable.tsx | 21 +- .../MetricsTable/SkipOnBoardModal/index.tsx | 1 + frontend/src/container/MetricsTable/index.tsx | 8 +- .../ComponentsSlider/menuItems.ts | 8 +- .../LeftContainer/QuerySection/Query.tsx | 2 +- .../LeftContainer/QuerySection/index.tsx | 2 +- .../LeftContainer/WidgetGraph/WidgetGraph.tsx | 2 +- .../RightContainer/YAxisUnitSelector.tsx | 33 ++- .../NewWidget/RightContainer/index.tsx | 37 +--- .../NewWidget/RightContainer/timeItems.ts | 1 + frontend/src/container/NewWidget/index.tsx | 7 +- frontend/src/container/SideNav/index.tsx | 8 +- frontend/src/container/SideNav/styles.ts | 13 +- frontend/src/container/Timeline/index.tsx | 39 ++-- frontend/src/container/Timeline/utils.ts | 24 ++- .../Panel/PanelBody/Common/Checkbox.tsx | 80 +++---- .../Panel/PanelBody/CommonCheckBox/index.tsx | 6 +- .../Panel/PanelBody/Duration/index.tsx | 25 +-- .../Filters/Panel/PanelHeading/index.tsx | 47 ++-- .../Filters/Panel/PanelHeading/styles.ts | 5 +- .../container/Trace/Filters/Panel/index.tsx | 8 +- .../src/container/Trace/Filters/styles.ts | 2 +- frontend/src/container/Trace/Graph/config.ts | 10 +- frontend/src/container/Trace/Graph/styles.ts | 3 +- .../Trace/Search/AllTags/Tag/TagKey.tsx | 14 +- .../Trace/Search/AllTags/Tag/index.tsx | 78 +++---- frontend/src/container/Trace/Search/util.ts | 4 +- .../Trace/TraceGraphFilter/index.tsx | 55 ++--- .../src/container/Trace/TraceTable/index.tsx | 97 ++++----- .../SelectedSpanDetails/ErrorTag.tsx | 1 - .../TraceDetail/SelectedSpanDetails/index.tsx | 6 +- .../TraceDetail/SelectedSpanDetails/styles.ts | 2 +- frontend/src/container/TraceDetail/index.tsx | 7 +- frontend/src/container/TraceDetail/utils.ts | 6 +- .../src/container/TraceFlameGraph/index.tsx | 43 ++-- .../src/container/TriggeredAlerts/Filter.tsx | 75 ++++--- .../TriggeredAlerts/FilteredTable/index.tsx | 4 +- .../TriggeredAlerts/NoFilterTable.tsx | 2 +- .../TriggeredAlerts/TriggeredAlert.tsx | 4 +- frontend/src/lib/JSXtoHTML.ts | 4 +- .../lib/getStartAndEndTime/getMicroSeconds.ts | 4 +- .../src/lib/getStartAndEndTime/getMinAgo.ts | 4 +- frontend/src/lib/getStep.ts | 3 + frontend/src/lib/theme/getTheme.ts | 6 +- frontend/src/lib/theme/setTheme.ts | 4 +- .../src/modules/Servicemap/SelectService.tsx | 15 +- .../src/modules/Servicemap/ServiceMap.tsx | 9 +- frontend/src/modules/Servicemap/index.ts | 4 +- frontend/src/modules/Servicemap/utils.ts | 6 +- frontend/src/modules/Usage/UsageExplorer.tsx | 10 +- .../src/modules/Usage/UsageExplorerDef.tsx | 4 +- .../src/pages/AlertChannelCreate/index.tsx | 1 + frontend/src/pages/ChannelsEdit/index.tsx | 2 +- frontend/src/pages/DashboardWidget/index.tsx | 2 +- frontend/src/pages/EditRules/index.tsx | 4 +- frontend/src/pages/Trace/index.tsx | 38 ++-- .../src/store/actions/MetricsActions/index.ts | 3 - .../MetricsActions/metricsActionTypes.ts | 32 --- .../actions/MetricsActions/metricsActions.ts | 204 ------------------ .../MetricsActions/metricsInterfaces.ts | 98 --------- frontend/src/store/actions/index.ts | 2 - frontend/src/store/actions/serviceMap.ts | 34 +-- .../store/actions/trace/getInitialFilter.ts | 7 +- frontend/src/store/actions/trace/getSpans.ts | 8 +- .../actions/trace/parseFilter/minMaxTime.ts | 4 +- frontend/src/store/actions/trace/util.ts | 2 +- frontend/src/store/actions/traces.ts | 153 ------------- frontend/src/store/actions/types.ts | 6 +- frontend/src/store/actions/usage.ts | 12 +- frontend/src/store/reducers/dashboard.ts | 9 +- frontend/src/store/reducers/global.ts | 2 +- frontend/src/store/reducers/serviceMap.ts | 6 +- frontend/src/store/reducers/usage.ts | 7 +- frontend/src/types/actions/trace.ts | 4 - frontend/src/utils/getSpanTreeMetadata.ts | 10 +- frontend/src/utils/spanToTree.ts | 4 +- frontend/yarn.lock | 107 ++++++++- 124 files changed, 1037 insertions(+), 1265 deletions(-) delete mode 100644 frontend/src/store/actions/MetricsActions/index.ts delete mode 100644 frontend/src/store/actions/MetricsActions/metricsActionTypes.ts delete mode 100644 frontend/src/store/actions/MetricsActions/metricsActions.ts delete mode 100644 frontend/src/store/actions/MetricsActions/metricsInterfaces.ts delete mode 100644 frontend/src/store/actions/traces.ts diff --git a/frontend/.eslintrc.js b/frontend/.eslintrc.js index 13c64cf523..fb9d999579 100644 --- a/frontend/.eslintrc.js +++ b/frontend/.eslintrc.js @@ -84,6 +84,23 @@ module.exports = { tsx: 'never', }, ], + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], + 'jsx-a11y/label-has-associated-control': [ + 'error', + { + required: { + some: ['nesting', 'id'], + }, + }, + ], + 'jsx-a11y/label-has-for': [ + 'error', + { + required: { + some: ['nesting', 'id'], + }, + }, + ], // eslint rules need to remove 'no-shadow': 'off', diff --git a/frontend/package.json b/frontend/package.json index 1dc9a4d0e8..5a4f750a72 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -102,6 +102,7 @@ "@babel/preset-env": "^7.12.17", "@babel/preset-react": "^7.12.13", "@babel/preset-typescript": "^7.12.17", + "@jest/globals": "^27.5.1", "@testing-library/cypress": "^8.0.0", "@types/color": "^3.0.3", "@types/compression-webpack-plugin": "^9.0.0", diff --git a/frontend/src/api/ErrorResponseHandler.ts b/frontend/src/api/ErrorResponseHandler.ts index 5ece49e730..9356b7ee77 100644 --- a/frontend/src/api/ErrorResponseHandler.ts +++ b/frontend/src/api/ErrorResponseHandler.ts @@ -3,13 +3,14 @@ import { ErrorResponse } from 'types/api'; import { ErrorStatusCode } from 'types/common'; export function ErrorResponseHandler(error: AxiosError): ErrorResponse { - if (error.response) { + const { response, request } = error; + if (response) { // client received an error response (5xx, 4xx) // making the error status code as standard Error Status Code - const statusCode = error.response.status as ErrorStatusCode; + const statusCode = response.status as ErrorStatusCode; if (statusCode >= 400 && statusCode < 500) { - const { data } = error.response; + const { data } = response; if (statusCode === 404) { return { @@ -35,7 +36,7 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse { message: null, }; } - if (error.request) { + if (request) { // client never received a response, or request never left console.error('client never received a response, or request never left'); @@ -51,7 +52,7 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse { return { statusCode: 500, payload: null, - error: error.toString(), + error: String(error), message: null, }; } diff --git a/frontend/src/assets/Dashboard/Value.tsx b/frontend/src/assets/Dashboard/Value.tsx index 27718c0c0d..f901f6161d 100644 --- a/frontend/src/assets/Dashboard/Value.tsx +++ b/frontend/src/assets/Dashboard/Value.tsx @@ -1,6 +1,8 @@ import React from 'react'; function Value(props: ValueProps): JSX.Element { + const { fillColor } = props; + return ( ); diff --git a/frontend/src/components/DatePicker/index.tsx b/frontend/src/components/DatePicker/index.tsx index daad8c5e6f..57334e4c9b 100644 --- a/frontend/src/components/DatePicker/index.tsx +++ b/frontend/src/components/DatePicker/index.tsx @@ -1,5 +1,7 @@ import generatePicker from 'antd/es/date-picker/generatePicker'; import { Dayjs } from 'dayjs'; +// included in antd +// eslint-disable-next-line import/no-extraneous-dependencies import dayjsGenerateConfig from 'rc-picker/lib/generate/dayjs'; const DatePicker = generatePicker(dayjsGenerateConfig); diff --git a/frontend/src/components/Graph/index.tsx b/frontend/src/components/Graph/index.tsx index 0659f686e1..def806ff10 100644 --- a/frontend/src/components/Graph/index.tsx +++ b/frontend/src/components/Graph/index.tsx @@ -140,8 +140,11 @@ function Graph({ }, ticks: { // Include a dollar sign in the ticks - callback(value, index, ticks) { - return getYAxisFormattedValue(value, yAxisUnit); + callback(value) { + return getYAxisFormattedValue( + parseInt(value.toString(), 10), + yAxisUnit, + ); }, }, }, @@ -201,18 +204,25 @@ interface GraphProps { data: Chart['data']; title?: string; isStacked?: boolean; - label?: string[]; - onClickHandler?: graphOnClickHandler; + onClickHandler?: GraphOnClickHandler; name: string; yAxisUnit?: string; forceReRender?: boolean | null | number; } -export type graphOnClickHandler = ( +export type GraphOnClickHandler = ( event: ChartEvent, elements: ActiveElement[], chart: Chart, data: ChartData, ) => void; +Graph.defaultProps = { + animate: undefined, + title: undefined, + isStacked: undefined, + onClickHandler: undefined, + yAxisUnit: undefined, + forceReRender: undefined, +}; export default Graph; diff --git a/frontend/src/components/Graph/xAxisConfig.ts b/frontend/src/components/Graph/xAxisConfig.ts index 6b2dbeb1ea..565b60f7e0 100644 --- a/frontend/src/components/Graph/xAxisConfig.ts +++ b/frontend/src/components/Graph/xAxisConfig.ts @@ -68,6 +68,37 @@ const TIME_UNITS_CONFIG: IAxisTimeUintConfig[] = [ }, ]; +/** + * Finds the relevant time unit based on the input time stamps (in ms) + */ +export const convertTimeRange = ( + start: number, + end: number, +): IAxisTimeConfig => { + const MIN_INTERVALS = 6; + const range = end - start; + let relevantTimeUnit = TIME_UNITS_CONFIG[1]; + let stepSize = 1; + try { + for (let idx = TIME_UNITS_CONFIG.length - 1; idx >= 0; idx -= 1) { + const timeUnit = TIME_UNITS_CONFIG[idx]; + const units = range * timeUnit.multiplier; + const steps = units / MIN_INTERVALS; + if (steps >= 1) { + relevantTimeUnit = timeUnit; + stepSize = steps; + break; + } + } + } catch (error) { + console.error(error); + } + return { + unitName: relevantTimeUnit.unitName, + stepSize: Math.floor(stepSize) || 1, + }; +}; + /** * Accepts Chart.js data's data-structure and returns the relevant time unit for the axis based on the range of the data. */ @@ -77,10 +108,18 @@ export const useXAxisTimeUnit = (data: Chart['data']): IAxisTimeConfig => { try { let minTime = Number.POSITIVE_INFINITY; let maxTime = Number.NEGATIVE_INFINITY; - data?.labels?.forEach((timeStamp: string | number): void => { - if (typeof timeStamp === 'string') timeStamp = Date.parse(timeStamp); - minTime = Math.min(timeStamp, minTime); - maxTime = Math.max(timeStamp, maxTime); + data?.labels?.forEach((timeStamp: unknown): void => { + const getTimeStamp = (time: string | number): Date | number | string => { + if (typeof timeStamp === 'string') { + return Date.parse(timeStamp); + } + + return time; + }; + const time = getTimeStamp(timeStamp as string | number); + + minTime = Math.min(parseInt(time.toString(), 10), minTime); + maxTime = Math.max(parseInt(time.toString(), 10), maxTime); }); localTime = { @@ -113,34 +152,3 @@ export const useXAxisTimeUnit = (data: Chart['data']): IAxisTimeConfig => { return convertTimeRange(minTime, maxTime); }; - -/** - * Finds the relevant time unit based on the input time stamps (in ms) - */ -export const convertTimeRange = ( - start: number, - end: number, -): IAxisTimeConfig => { - const MIN_INTERVALS = 6; - const range = end - start; - let relevantTimeUnit = TIME_UNITS_CONFIG[1]; - let stepSize = 1; - try { - for (let idx = TIME_UNITS_CONFIG.length - 1; idx >= 0; idx--) { - const timeUnit = TIME_UNITS_CONFIG[idx]; - const units = range * timeUnit.multiplier; - const steps = units / MIN_INTERVALS; - if (steps >= 1) { - relevantTimeUnit = timeUnit; - stepSize = steps; - break; - } - } - } catch (error) { - console.error(error); - } - return { - unitName: relevantTimeUnit.unitName, - stepSize: Math.floor(stepSize) || 1, - }; -}; diff --git a/frontend/src/components/Graph/yAxisConfig.ts b/frontend/src/components/Graph/yAxisConfig.ts index bf2a1cc525..5434eeceb3 100644 --- a/frontend/src/components/Graph/yAxisConfig.ts +++ b/frontend/src/components/Graph/yAxisConfig.ts @@ -3,7 +3,6 @@ import { formattedValueToString, getValueFormat } from '@grafana/data'; export const getYAxisFormattedValue = ( value: number, format: string, - decimal?: number, ): string => { try { return formattedValueToString( diff --git a/frontend/src/components/Input/index.tsx b/frontend/src/components/Input/index.tsx index 210c8b8bfe..6516b6b209 100644 --- a/frontend/src/components/Input/index.tsx +++ b/frontend/src/components/Input/index.tsx @@ -1,4 +1,4 @@ -import { Form, Input, InputProps } from 'antd'; +import { Form, Input, InputProps, InputRef } from 'antd'; import React from 'react'; function InputComponent({ @@ -22,11 +22,12 @@ function InputComponent({ type={type} onChange={onChangeHandler} value={value} - ref={ref} + ref={ref as React.Ref} size={size} addonBefore={addonBefore} onBlur={onBlurHandler} onPressEnter={onPressEnterHandler} + // eslint-disable-next-line react/jsx-props-no-spreading {...props} /> @@ -38,7 +39,7 @@ interface InputComponentProps extends InputProps { type?: InputProps['type']; onChangeHandler?: React.ChangeEventHandler; placeholder?: InputProps['placeholder']; - ref?: React.LegacyRef; + ref?: React.LegacyRef; size?: InputProps['size']; onBlurHandler?: React.FocusEventHandler; onPressEnterHandler?: React.KeyboardEventHandler; @@ -47,4 +48,17 @@ interface InputComponentProps extends InputProps { addonBefore?: React.ReactNode; } +InputComponent.defaultProps = { + type: undefined, + onChangeHandler: undefined, + placeholder: undefined, + ref: undefined, + size: undefined, + onBlurHandler: undefined, + onPressEnterHandler: undefined, + label: undefined, + labelOnTop: undefined, + addonBefore: undefined, +}; + export default InputComponent; diff --git a/frontend/src/components/Modal.tsx b/frontend/src/components/Modal.tsx index 9ab4761896..cbc419875f 100644 --- a/frontend/src/components/Modal.tsx +++ b/frontend/src/components/Modal.tsx @@ -28,4 +28,9 @@ interface ModalProps { children: ReactElement; } +CustomModal.defaultProps = { + closable: undefined, + footer: undefined, +}; + export default CustomModal; diff --git a/frontend/src/components/RouteTab/index.tsx b/frontend/src/components/RouteTab/index.tsx index 4d6f42d6d9..4a565d84b9 100644 --- a/frontend/src/components/RouteTab/index.tsx +++ b/frontend/src/components/RouteTab/index.tsx @@ -10,8 +10,10 @@ function RouteTab({ onChangeHandler, ...rest }: RouteTabProps & TabsProps): JSX.Element { - const onChange = (activeRoute: string) => { - onChangeHandler && onChangeHandler(); + const onChange = (activeRoute: string): void => { + if (onChangeHandler) { + onChangeHandler(); + } const selectedRoute = routes.find((e) => e.name === activeRoute); @@ -25,6 +27,7 @@ function RouteTab({ onChange={onChange} destroyInactiveTabPane activeKey={activeKey} + // eslint-disable-next-line react/jsx-props-no-spreading {...rest} > {routes.map( @@ -48,4 +51,8 @@ interface RouteTabProps { onChangeHandler?: VoidFunction; } +RouteTab.defaultProps = { + onChangeHandler: undefined, +}; + export default RouteTab; diff --git a/frontend/src/components/Spinner/index.tsx b/frontend/src/components/Spinner/index.tsx index 622e8e2d43..160bfb75f5 100644 --- a/frontend/src/components/Spinner/index.tsx +++ b/frontend/src/components/Spinner/index.tsx @@ -17,5 +17,10 @@ interface SpinnerProps { tip?: SpinProps['tip']; height?: React.CSSProperties['height']; } +Spinner.defaultProps = { + size: undefined, + tip: undefined, + height: undefined, +}; export default Spinner; diff --git a/frontend/src/components/TextToolTip/index.tsx b/frontend/src/components/TextToolTip/index.tsx index 25edbf9b00..051d48c30d 100644 --- a/frontend/src/components/TextToolTip/index.tsx +++ b/frontend/src/components/TextToolTip/index.tsx @@ -1,11 +1,12 @@ +/* eslint-disable react/no-unstable-nested-components */ import { QuestionCircleFilled } from '@ant-design/icons'; import { Tooltip } from 'antd'; import React from 'react'; -function TextToolTip({ text, url }: TextToolTipProps) { +function TextToolTip({ text, url }: TextToolTipProps): JSX.Element { return ( { + overlay={(): JSX.Element => { return (
{`${text} `} diff --git a/frontend/src/components/TimePreferenceDropDown/index.tsx b/frontend/src/components/TimePreferenceDropDown/index.tsx index 497ae9e616..0f9a06bc10 100644 --- a/frontend/src/components/TimePreferenceDropDown/index.tsx +++ b/frontend/src/components/TimePreferenceDropDown/index.tsx @@ -1,5 +1,5 @@ import { Button, Dropdown, Menu, Typography } from 'antd'; -import timeItems, { +import TimeItems, { timePreferance, timePreferenceType, } from 'container/NewWidget/RightContainer/timeItems'; @@ -13,7 +13,7 @@ function TimePreference({ }: TimePreferenceDropDownProps): JSX.Element { const timeMenuItemOnChangeHandler = useCallback( (event: TimeMenuItemOnChangeHandlerEvent) => { - const selectedTime = timeItems.find((e) => e.enum === event.key); + const selectedTime = TimeItems.find((e) => e.enum === event.key); if (selectedTime !== undefined) { setSelectedTime(selectedTime); } @@ -26,7 +26,7 @@ function TimePreference({ - {timeItems.map((item) => ( + {TimeItems.map((item) => ( {item.name} diff --git a/frontend/src/constants/app.ts b/frontend/src/constants/app.ts index 0506378458..90d6222689 100644 --- a/frontend/src/constants/app.ts +++ b/frontend/src/constants/app.ts @@ -6,4 +6,4 @@ export const AUTH0_REDIRECT_PATH = '/redirect'; export const DEFAULT_AUTH0_APP_REDIRECTION_PATH = ROUTES.APPLICATION; -export const IS_SIDEBAR_COLLAPSED = 'isSideBarCollapsed' \ No newline at end of file +export const IS_SIDEBAR_COLLAPSED = 'isSideBarCollapsed'; diff --git a/frontend/src/constants/localStorage.ts b/frontend/src/constants/localStorage.ts index bef5bf33f7..86d879122d 100644 --- a/frontend/src/constants/localStorage.ts +++ b/frontend/src/constants/localStorage.ts @@ -1,3 +1,3 @@ -export enum LOCAL_STORAGE { +export enum LOCALSTORAGE { METRICS_TIME_IN_DURATION = 'metricsTimeDurations', } diff --git a/frontend/src/constants/query.ts b/frontend/src/constants/query.ts index 0f816d1605..29221e9f9c 100644 --- a/frontend/src/constants/query.ts +++ b/frontend/src/constants/query.ts @@ -1,3 +1,4 @@ +// eslint-disable-next-line @typescript-eslint/naming-convention export enum METRICS_PAGE_QUERY_PARAM { interval = 'interval', startTime = 'startTime', diff --git a/frontend/src/container/AllAlertChannels/AlertChannels.tsx b/frontend/src/container/AllAlertChannels/AlertChannels.tsx index e88ed0276d..f537e969e1 100644 --- a/frontend/src/container/AllAlertChannels/AlertChannels.tsx +++ b/frontend/src/container/AllAlertChannels/AlertChannels.tsx @@ -4,7 +4,7 @@ import { ColumnsType } from 'antd/lib/table'; import ROUTES from 'constants/routes'; import history from 'lib/history'; import React, { useCallback, useState } from 'react'; -import { generatePath } from 'react-router'; +import { generatePath } from 'react-router-dom'; import { Channels, PayloadProps } from 'types/api/channels/getAll'; import Delete from './Delete'; diff --git a/frontend/src/container/AppLayout/index.tsx b/frontend/src/container/AppLayout/index.tsx index 09a431e2d8..84f7d237e2 100644 --- a/frontend/src/container/AppLayout/index.tsx +++ b/frontend/src/container/AppLayout/index.tsx @@ -4,17 +4,19 @@ import SideNav from 'container/SideNav'; import history from 'lib/history'; import React, { ReactNode, useEffect, useState } from 'react'; import { useSelector } from 'react-redux'; +import { useLocation } from 'react-router-dom'; import { AppState } from 'store/reducers'; import AppReducer from 'types/reducer/app'; import { Content, Layout } from './styles'; -const AppLayout: React.FC = ({ children }) => { +function AppLayout(props: AppLayoutProps): JSX.Element { const { isLoggedIn } = useSelector((state) => state.app); + const { pathname } = useLocation(); - const [isSignUpPage, setIsSignUpPage] = useState( - ROUTES.SIGN_UP === location.pathname, - ); + const [isSignUpPage, setIsSignUpPage] = useState(ROUTES.SIGN_UP === pathname); + + const { children } = props; useEffect(() => { if (!isLoggedIn) { @@ -36,7 +38,7 @@ const AppLayout: React.FC = ({ children }) => { ); -}; +} interface AppLayoutProps { children: ReactNode; diff --git a/frontend/src/container/CreateAlertChannels/index.tsx b/frontend/src/container/CreateAlertChannels/index.tsx index 416f9e4cc4..8a3b3fe606 100644 --- a/frontend/src/container/CreateAlertChannels/index.tsx +++ b/frontend/src/container/CreateAlertChannels/index.tsx @@ -79,7 +79,7 @@ function CreateAlertChannels({ const onSaveHandler = useCallback( async (value: ChannelType) => { - if (value == 'slack') { + if (value === 'slack') { onSlackHandler(); } }, @@ -111,4 +111,8 @@ interface CreateAlertChannelsProps { preType?: ChannelType; } +CreateAlertChannels.defaultProps = { + preType: undefined, +}; + export default CreateAlertChannels; diff --git a/frontend/src/container/EditAlertChannels/index.tsx b/frontend/src/container/EditAlertChannels/index.tsx index dfe46f4971..2d8ac3576d 100644 --- a/frontend/src/container/EditAlertChannels/index.tsx +++ b/frontend/src/container/EditAlertChannels/index.tsx @@ -7,9 +7,8 @@ import { } from 'container/CreateAlertChannels/config'; import FormAlertChannels from 'container/FormAlertChannels'; import history from 'lib/history'; -import { Store } from 'rc-field-form/lib/interface'; import React, { useCallback, useState } from 'react'; -import { useParams } from 'react-router'; +import { useParams } from 'react-router-dom'; function EditAlertChannels({ initialValue, @@ -91,7 +90,9 @@ function EditAlertChannels({ } interface EditAlertChannelsProps { - initialValue: Store; + initialValue: { + [x: string]: unknown; + }; } export default EditAlertChannels; diff --git a/frontend/src/container/FormAlertChannels/index.tsx b/frontend/src/container/FormAlertChannels/index.tsx index 9db1261c42..573be68d00 100644 --- a/frontend/src/container/FormAlertChannels/index.tsx +++ b/frontend/src/container/FormAlertChannels/index.tsx @@ -1,12 +1,12 @@ import { Form, FormInstance, Input, Select, Typography } from 'antd'; import FormItem from 'antd/lib/form/FormItem'; +import { Store } from 'antd/lib/form/interface'; import ROUTES from 'constants/routes'; import { ChannelType, SlackChannel, } from 'container/CreateAlertChannels/config'; import history from 'lib/history'; -import { Store } from 'rc-field-form/lib/interface'; import React from 'react'; import SlackSettings from './Settings/Slack'; @@ -89,7 +89,6 @@ interface FormAlertChannelsProps { type: ChannelType; setSelectedConfig: React.Dispatch>>; onTypeChangeHandler: (value: ChannelType) => void; - onTestHandler: () => void; onSaveHandler: (props: ChannelType) => void; savingState: boolean; NotificationElement: React.ReactElement< @@ -101,4 +100,8 @@ interface FormAlertChannelsProps { nameDisable?: boolean; } +FormAlertChannels.defaultProps = { + nameDisable: undefined, +}; + export default FormAlertChannels; diff --git a/frontend/src/container/GantChart/SpanLength/index.tsx b/frontend/src/container/GantChart/SpanLength/index.tsx index b34784cc51..4ee15a9332 100644 --- a/frontend/src/container/GantChart/SpanLength/index.tsx +++ b/frontend/src/container/GantChart/SpanLength/index.tsx @@ -1,4 +1,3 @@ -import { Tooltip, Typography } from 'antd'; import { IIntervalUnit, resolveTimeFromInterval, @@ -13,21 +12,29 @@ interface SpanLengthProps { width: string; leftOffset: string; bgColor: string; - toolTipText: string; - id: string; inMsCount: number; intervalUnit: IIntervalUnit; } function SpanLength(props: SpanLengthProps): JSX.Element { - const { width, leftOffset, bgColor, intervalUnit } = props; + const { width, leftOffset, bgColor, intervalUnit, inMsCount } = props; const { isDarkMode } = useThemeMode(); return ( - - - {`${toFixed( - resolveTimeFromInterval(props.inMsCount, intervalUnit), + + + {`${toFixed( + resolveTimeFromInterval(inMsCount, intervalUnit), 2, )} ${intervalUnit.name}`} diff --git a/frontend/src/container/GantChart/SpanLength/styles.ts b/frontend/src/container/GantChart/SpanLength/styles.ts index 9ee22feab3..0af7b0a234 100644 --- a/frontend/src/container/GantChart/SpanLength/styles.ts +++ b/frontend/src/container/GantChart/SpanLength/styles.ts @@ -9,19 +9,19 @@ interface Props { } export const SpanLine = styled.div` - width: ${({ leftOffset }) => `${leftOffset}%`}; + width: ${({ leftOffset }): string => `${leftOffset}%`}; height: 0px; border-bottom: 0.1px solid - ${({ isDarkMode }) => (isDarkMode ? '#303030' : '#c0c0c0')}; + ${({ isDarkMode }): string => (isDarkMode ? '#303030' : '#c0c0c0')}; top: 50%; position: absolute; `; export const SpanBorder = styled.div` - background: ${({ bgColor }) => bgColor}; + background: ${({ bgColor }): string => bgColor}; border-radius: 5px; height: 0.625rem; - width: ${({ width }) => `${width}%`}; - left: ${({ leftOffset }) => `${leftOffset}%`}; + width: ${({ width }): string => `${width}%`}; + left: ${({ leftOffset }): string => `${leftOffset}%`}; top: 35%; position: absolute; `; @@ -45,13 +45,16 @@ export const SpanWrapper = styled.div` z-index: 0; } */ `; +interface SpanTextProps extends Pick { + isDarkMode: boolean; +} -export const SpanText = styled(Typography)>` +export const SpanText = styled(Typography)` &&& { - left: ${({ leftOffset }) => `${leftOffset}%`}; + left: ${({ leftOffset }): string => `${leftOffset}%`}; top: 65%; position: absolute; - color: ${({ isDarkMode }) => (isDarkMode ? '##ACACAC' : '#666')}; + color: ${({ isDarkMode }): string => (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 index f9496c12b1..47d58c3e5c 100644 --- a/frontend/src/container/GantChart/SpanName/index.tsx +++ b/frontend/src/container/GantChart/SpanName/index.tsx @@ -1,18 +1,11 @@ import React from 'react'; -import { - Container, - Service, - Span, - SpanConnector, - SpanName, - SpanWrapper, -} from './styles'; +import { Container, Service, Span, SpanWrapper } from './styles'; function SpanNameComponent({ name, serviceName, -}: SpanNameComponent): JSX.Element { +}: SpanNameComponentProps): JSX.Element { return ( @@ -23,7 +16,7 @@ function SpanNameComponent({ ); } -interface SpanNameComponent { +interface SpanNameComponentProps { name: string; serviceName: string; } diff --git a/frontend/src/container/GantChart/Trace/index.tsx b/frontend/src/container/GantChart/Trace/index.tsx index 06f356677f..a0c01cc00e 100644 --- a/frontend/src/container/GantChart/Trace/index.tsx +++ b/frontend/src/container/GantChart/Trace/index.tsx @@ -5,7 +5,7 @@ import { IIntervalUnit } from 'container/TraceDetail/utils'; import useThemeMode from 'hooks/useThemeMode'; import { SPAN_DETAILS_LEFT_COL_WIDTH } from 'pages/TraceDetail/constants'; import React, { useEffect, useRef, useState } from 'react'; -import { pushDStree } from 'store/actions'; +import { ITraceTree } from 'types/api/trace/getTraceItem'; import { ITraceMetaData } from '..'; import SpanLength from '../SpanLength'; @@ -38,6 +38,7 @@ function Trace(props: TraceProps): JSX.Element { activeSpanPath, isExpandAll, intervalUnit, + children, } = props; const { isDarkMode } = useThemeMode(); @@ -52,7 +53,7 @@ function Trace(props: TraceProps): JSX.Element { } else if (!isOpen) { setOpen(activeSpanPath[level] === id); } - }, [activeSpanPath, isOpen]); + }, [activeSpanPath, isOpen, id, level]); useEffect(() => { if (isExpandAll) { @@ -60,9 +61,9 @@ function Trace(props: TraceProps): JSX.Element { } else { setOpen(activeSpanPath[level] === id); } - }, [isExpandAll]); + }, [isExpandAll, activeSpanPath, id, level]); - const isOnlyChild = props.children.length === 1; + const isOnlyChild = children.length === 1; const [top, setTop] = useState(0); const ref = useRef(null); @@ -75,25 +76,27 @@ function Trace(props: TraceProps): JSX.Element { inline: 'nearest', }); } - }, [activeSelectedId]); + }, [activeSelectedId, id]); - const onMouseEnterHandler = () => { - setActiveHoverId(props.id); + const onMouseEnterHandler = (): void => { + setActiveHoverId(id); if (ref.current) { const { top } = getTopLeftFromBody(ref.current); setTop(top); } }; - const onMouseLeaveHandler = () => { + const onMouseLeaveHandler = (): void => { setActiveHoverId(''); }; - const onClick = () => { + const onClick = (): void => { setActiveSelectedId(id); }; - const onClickTreeExpansion = (event) => { + const onClickTreeExpansion: React.MouseEventHandler = ( + event, + ): void => { event.stopPropagation(); setOpen((state) => { localTreeExpandInteraction.current = !isOpen; @@ -113,6 +116,7 @@ function Trace(props: TraceProps): JSX.Element { onMouseLeave={onMouseLeaveHandler} isOnlyChild={isOnlyChild} ref={ref} + isDarkMode={isDarkMode} > {totalSpans !== 1 && ( - + {totalSpans} {isOpen ? : } @@ -144,7 +152,6 @@ function Trace(props: TraceProps): JSX.Element { leftOffset={nodeLeftOffset.toString()} width={width.toString()} bgColor={serviceColour} - id={id} inMsCount={inMsCount / 1e6} intervalUnit={intervalUnit} /> @@ -153,11 +160,12 @@ function Trace(props: TraceProps): JSX.Element { {isOpen && ( <> - {props.children.map((child) => ( + {children.map((child) => ( >; setActiveSelectedId: React.Dispatch>; diff --git a/frontend/src/container/GantChart/Trace/styles.ts b/frontend/src/container/GantChart/Trace/styles.ts index 16eb99305d..ccf139d6c2 100644 --- a/frontend/src/container/GantChart/Trace/styles.ts +++ b/frontend/src/container/GantChart/Trace/styles.ts @@ -1,4 +1,8 @@ -import styled, { css } from 'styled-components'; +import styled, { + css, + DefaultTheme, + ThemedCssFunction, +} from 'styled-components'; interface Props { isOnlyChild: boolean; @@ -13,9 +17,10 @@ export const Wrapper = styled.ul` z-index: 1; ul { - border-left: ${({ isOnlyChild }) => isOnlyChild && 'none'} !important; + border-left: ${({ isOnlyChild }): StyledCSS => + isOnlyChild && 'none'} !important; - ${({ isOnlyChild }) => + ${({ isOnlyChild }): StyledCSS => isOnlyChild && css` &:before { @@ -37,15 +42,27 @@ export const CardContainer = styled.li` cursor: pointer; `; -export const CardComponent = styled.div` - border: 1px solid ${({ isDarkMode }) => (isDarkMode ? '#434343' : '#333')}; +interface Props { + isDarkMode: boolean; +} + +export type StyledCSS = + | ReturnType> + | string + | false + | undefined; + +export const CardComponent = styled.div` + border: 1px solid + ${({ isDarkMode }): StyledCSS => (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')}; + background: ${({ isDarkMode }): StyledCSS => + isDarkMode ? '#1d1d1d' : '#ddd'}; height: 22px; `; @@ -61,13 +78,15 @@ interface HoverCardProps { } export const HoverCard = styled.div` - display: ${({ isSelected, isHovered }) => + display: ${({ isSelected, isHovered }): string => isSelected || isHovered ? 'block' : 'none'}; width: 200%; - background-color: ${({ isHovered, isDarkMode }) => - isHovered && (isDarkMode ? '#262626' : '#ddd')}; - background-color: ${({ isSelected, isDarkMode }) => - isSelected && (isDarkMode ? '#4f4f4f' : '#bbb')}; + background-color: ${({ isHovered, isDarkMode }): string => { + if (isHovered) { + return isDarkMode ? '#262626' : '#ddd'; + } + return isDarkMode ? '#4f4f4f' : '#bbb'; + }}; position: absolute; top: 0; left: -100%; diff --git a/frontend/src/container/GantChart/index.tsx b/frontend/src/container/GantChart/index.tsx index 32cd54c3d2..a25f4af228 100644 --- a/frontend/src/container/GantChart/index.tsx +++ b/frontend/src/container/GantChart/index.tsx @@ -26,13 +26,13 @@ function GanttChart(props: GanttChartProps): JSX.Element { useEffect(() => { setActiveSpanPath(getSpanPath(data, spanId)); - }, [spanId]); + }, [spanId, data]); useEffect(() => { setActiveSpanPath(getSpanPath(data, activeSelectedId)); - }, [activeSelectedId]); + }, [activeSelectedId, data]); - const handleCollapse = () => { + const handleCollapse = (): void => { setIsExpandAll((prev) => !prev); }; return ( @@ -50,6 +50,7 @@ function GanttChart(props: GanttChartProps): JSX.Element { activeSpanPath={activeSpanPath} setActiveHoverId={setActiveHoverId} key={data.id} + // eslint-disable-next-line react/jsx-props-no-spreading {...{ ...data, globalSpread, diff --git a/frontend/src/container/GantChart/utils.ts b/frontend/src/container/GantChart/utils.ts index c5aa327844..d229af9839 100644 --- a/frontend/src/container/GantChart/utils.ts +++ b/frontend/src/container/GantChart/utils.ts @@ -1,24 +1,33 @@ import { ITraceTree } from 'types/api/trace/getTraceItem'; -export const getMetaDataFromSpanTree = (treeData: ITraceTree) => { +interface GetTraceMetaData { + globalStart: number; + globalEnd: number; + spread: number; + totalSpans: number; + levels: number; +} +export const getMetaDataFromSpanTree = ( + treeData: ITraceTree, +): GetTraceMetaData => { let globalStart = Number.POSITIVE_INFINITY; let globalEnd = Number.NEGATIVE_INFINITY; let totalSpans = 0; let levels = 1; - const traverse = (treeNode: ITraceTree, level = 0) => { + const traverse = (treeNode: ITraceTree, level = 0): void => { if (!treeNode) { return; } - totalSpans++; + totalSpans += 1; levels = Math.max(levels, level); const { startTime } = treeNode; const endTime = startTime + treeNode.value; globalStart = Math.min(globalStart, startTime); globalEnd = Math.max(globalEnd, endTime); - for (const childNode of treeNode.children) { + treeNode.children.forEach((childNode) => { traverse(childNode, level + 1); - } + }); }; traverse(treeData, 1); @@ -34,7 +43,9 @@ export const getMetaDataFromSpanTree = (treeData: ITraceTree) => { }; }; -export function getTopLeftFromBody(elem: HTMLElement) { +export function getTopLeftFromBody( + elem: HTMLElement, +): { top: number; left: number } { const box = elem.getBoundingClientRect(); const { body } = document; @@ -57,18 +68,18 @@ export const getNodeById = ( treeData: ITraceTree, ): ITraceTree | undefined => { let foundNode: ITraceTree | undefined; - const traverse = (treeNode: ITraceTree, level = 0) => { + const traverse = (treeNode: ITraceTree, level = 0): void => { if (!treeNode) { return; } - if (searchingId == treeNode.id) { + if (searchingId === treeNode.id) { foundNode = treeNode; } - for (const childNode of treeNode.children) { + treeNode.children.forEach((childNode) => { traverse(childNode, level + 1); - } + }); }; traverse(treeData, 1); @@ -88,7 +99,7 @@ const getSpanWithoutChildren = ( tags: span.tags, time: span.time, value: span.value, - error: span.error, + event: span.event, hasError: span.hasError, }; }; @@ -101,10 +112,7 @@ export const isSpanPresentInSearchString = ( const stringifyTree = JSON.stringify(parsedTree); - if (stringifyTree.includes(searchedString)) { - return true; - } - return false; + return stringifyTree.includes(searchedString); }; export const isSpanPresent = ( @@ -117,7 +125,7 @@ export const isSpanPresent = ( treeNode: ITraceTree, level = 0, foundNode: ITraceTree[], - ) => { + ): void => { if (!treeNode) { return; } @@ -128,9 +136,9 @@ export const isSpanPresent = ( foundNode.push(treeNode); } - for (const childNode of treeNode.children) { + treeNode.children.forEach((childNode) => { traverse(childNode, level + 1, foundNode); - } + }); }; traverse(tree, 1, foundNode); @@ -140,7 +148,7 @@ export const isSpanPresent = ( export const getSpanPath = (tree: ITraceTree, spanId: string): string[] => { const spanPath: string[] = []; - const traverse = (treeNode: ITraceTree) => { + const traverse = (treeNode: ITraceTree): boolean => { if (!treeNode) { return false; } @@ -152,9 +160,9 @@ export const getSpanPath = (tree: ITraceTree, spanId: string): string[] => { } let foundInChild = false; - for (const childNode of treeNode.children) { + treeNode.children.forEach((childNode) => { if (traverse(childNode)) foundInChild = true; - } + }); if (!foundInChild) { spanPath.pop(); } diff --git a/frontend/src/container/GeneralSettings/Retention.tsx b/frontend/src/container/GeneralSettings/Retention.tsx index 93892b8251..b2f5cb5a09 100644 --- a/frontend/src/container/GeneralSettings/Retention.tsx +++ b/frontend/src/container/GeneralSettings/Retention.tsx @@ -1,6 +1,5 @@ import { DownOutlined } from '@ant-design/icons'; import { Button, Menu } from 'antd'; -import { MenuInfo } from 'rc-menu/lib/interface'; import React from 'react'; import { SettingPeroid } from '.'; @@ -35,7 +34,7 @@ function Retention({ ]; const onClickHandler = ( - e: MenuInfo, + e: { key: string }, func: React.Dispatch>, ): void => { const selected = e.key as SettingPeroid; diff --git a/frontend/src/container/GeneralSettings/index.tsx b/frontend/src/container/GeneralSettings/index.tsx index fa68fced4d..e741e81886 100644 --- a/frontend/src/container/GeneralSettings/index.tsx +++ b/frontend/src/container/GeneralSettings/index.tsx @@ -39,6 +39,10 @@ function GeneralSettings(): JSX.Element { const [isDefaultMetrics, setIsDefaultMetrics] = useState(false); const [isDefaultTrace, setIsDefaultTrace] = useState(false); + const onModalToggleHandler = (): void => { + setModal((modal) => !modal); + }; + const onClickSaveHandler = useCallback(() => { onModalToggleHandler(); }, []); @@ -48,10 +52,6 @@ function GeneralSettings(): JSX.Element { undefined >(getRetentionperoidApi, undefined); - const onModalToggleHandler = (): void => { - setModal((modal) => !modal); - }; - const checkMetricTraceDefault = (trace: number, metric: number): void => { if (metric === -1) { setIsDefaultMetrics(true); @@ -68,12 +68,15 @@ function GeneralSettings(): JSX.Element { useEffect(() => { if (!loading && payload !== undefined) { - const { metrics_ttl_duration_hrs, traces_ttl_duration_hrs } = payload; + const { + metrics_ttl_duration_hrs: metricTllDuration, + traces_ttl_duration_hrs: traceTllDuration, + } = payload; - checkMetricTraceDefault(traces_ttl_duration_hrs, metrics_ttl_duration_hrs); + checkMetricTraceDefault(traceTllDuration, metricTllDuration); - const traceValue = getSettingsPeroid(traces_ttl_duration_hrs); - const metricsValue = getSettingsPeroid(metrics_ttl_duration_hrs); + const traceValue = getSettingsPeroid(traceTllDuration); + const metricsValue = getSettingsPeroid(metricTllDuration); setRetentionPeroidTrace(traceValue.value.toString()); setSelectedTracePeroid(traceValue.peroid); @@ -171,11 +174,7 @@ function GeneralSettings(): JSX.Element { }; const isDisabledHandler = (): boolean => { - if (retentionPeroidTrace === '' || retentionPeroidMetrics === '') { - return true; - } - - return false; + return !!(retentionPeroidTrace === '' || retentionPeroidMetrics === ''); }; const errorText = getErrorText(); diff --git a/frontend/src/container/GridGraphComponent/index.tsx b/frontend/src/container/GridGraphComponent/index.tsx index 3ca7f4f544..9725957a43 100644 --- a/frontend/src/container/GridGraphComponent/index.tsx +++ b/frontend/src/container/GridGraphComponent/index.tsx @@ -1,6 +1,6 @@ import { Typography } from 'antd'; import { ChartData } from 'chart.js'; -import Graph, { graphOnClickHandler } from 'components/Graph'; +import Graph, { GraphOnClickHandler } from 'components/Graph'; import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig'; import ValueGraph from 'components/ValueGraph'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; @@ -77,9 +77,17 @@ export interface GridGraphComponentProps { title?: string; opacity?: string; isStacked?: boolean; - onClickHandler?: graphOnClickHandler; + onClickHandler?: GraphOnClickHandler; name: string; yAxisUnit?: string; } +GridGraphComponent.defaultProps = { + title: undefined, + opacity: undefined, + isStacked: undefined, + onClickHandler: undefined, + yAxisUnit: undefined, +}; + export default GridGraphComponent; diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx index 9f2cfc3e69..de4d563acb 100644 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx @@ -1,4 +1,4 @@ -import Graph, { graphOnClickHandler } from 'components/Graph'; +import Graph, { GraphOnClickHandler } from 'components/Graph'; import { timePreferance } from 'container/NewWidget/RightContainer/timeItems'; import GetMaxMinTime from 'lib/getMaxMinTime'; import { colors } from 'lib/getRandomColor'; @@ -84,7 +84,7 @@ function EmptyGraph({ interface EmptyGraphProps { selectedTime: timePreferance; widget: Widgets; - onClickHandler: graphOnClickHandler | undefined; + onClickHandler: GraphOnClickHandler | undefined; } export default EmptyGraph; diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx index 174caac5ac..0f0ce7b1fb 100644 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/index.tsx @@ -2,7 +2,7 @@ import { Button, Typography } from 'antd'; import getQueryResult from 'api/widgets/getQuery'; import { AxiosError } from 'axios'; import { ChartData } from 'chart.js'; -import { graphOnClickHandler } from 'components/Graph'; +import { GraphOnClickHandler } from 'components/Graph'; import Spinner from 'components/Spinner'; import TimePreference from 'components/TimePreferenceDropDown'; import GridGraphComponent from 'container/GridGraphComponent'; @@ -65,7 +65,9 @@ function FullView({ minTime, }); - const getMinMax = (time: timePreferenceType) => { + const getMinMax = ( + time: timePreferenceType, + ): { min: string | number; max: string | number } => { if (time === 'GLOBAL_TIME') { const minMax = GetMinMax(globalSelectedTime); return { @@ -142,7 +144,7 @@ function FullView({ loading: false, })); } - }, [widget, maxTime, minTime, selectedTime.enum]); + }, [widget, maxTime, minTime, selectedTime.enum, globalSelectedTime]); useEffect(() => { onFetchDataHandler(); @@ -240,10 +242,17 @@ interface FullViewState { interface FullViewProps { widget: Widgets; fullViewOptions?: boolean; - onClickHandler?: graphOnClickHandler; + onClickHandler?: GraphOnClickHandler; noDataGraph?: boolean; name: string; yAxisUnit?: string; } +FullView.defaultProps = { + fullViewOptions: undefined, + onClickHandler: undefined, + noDataGraph: undefined, + yAxisUnit: undefined, +}; + export default FullView; diff --git a/frontend/src/container/GridGraphLayout/Graph/index.tsx b/frontend/src/container/GridGraphLayout/Graph/index.tsx index 9559a3f7d6..0447cfca94 100644 --- a/frontend/src/container/GridGraphLayout/Graph/index.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/index.tsx @@ -124,6 +124,13 @@ function GridCardGraph({ [], ); + const onDeleteHandler = useCallback(() => { + deleteWidget({ widgetId: widget.id }); + onToggleModal(setDeletModal); + // eslint-disable-next-line no-param-reassign + isDeleted.current = true; + }, [deleteWidget, widget, onToggleModal, isDeleted]); + const getModals = (): JSX.Element => { return ( <> @@ -160,12 +167,6 @@ function GridCardGraph({ ); }; - const onDeleteHandler = useCallback(() => { - deleteWidget({ widgetId: widget.id }); - onToggleModal(setDeletModal); - isDeleted.current = true; - }, [deleteWidget, widget, onToggleModal, isDeleted]); - if (state.error) { return ( <> diff --git a/frontend/src/container/GridGraphLayout/index.tsx b/frontend/src/container/GridGraphLayout/index.tsx index 8f5ad14080..046c9473ad 100644 --- a/frontend/src/container/GridGraphLayout/index.tsx +++ b/frontend/src/container/GridGraphLayout/index.tsx @@ -6,11 +6,9 @@ import { notification } from 'antd'; import updateDashboardApi from 'api/dashboard/update'; import Spinner from 'components/Spinner'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; -import history from 'lib/history'; import React, { memo, useCallback, useEffect, useRef, useState } from 'react'; import { Layout } from 'react-grid-layout'; import { useSelector } from 'react-redux'; -import { useLocation } from 'react-router-dom'; import { AppState } from 'store/reducers'; import DashboardReducer from 'types/reducer/dashboards'; import { v4 } from 'uuid'; diff --git a/frontend/src/container/Header/Breadcrumbs/index.tsx b/frontend/src/container/Header/Breadcrumbs/index.tsx index ef4581e0c5..f1c295e1ff 100644 --- a/frontend/src/container/Header/Breadcrumbs/index.tsx +++ b/frontend/src/container/Header/Breadcrumbs/index.tsx @@ -1,12 +1,11 @@ import { Breadcrumb } from 'antd'; import ROUTES from 'constants/routes'; import React from 'react'; -import { RouteComponentProps, withRouter } from 'react-router'; -import { Link } from 'react-router-dom'; +import { Link, RouteComponentProps, withRouter } from 'react-router-dom'; const breadcrumbNameMap = { [ROUTES.APPLICATION]: 'Application', - [ROUTES.TRACES]: 'Traces', + [ROUTES.TRACE]: 'Traces', [ROUTES.SERVICE_MAP]: 'Service Map', [ROUTES.USAGE_EXPLORER]: 'Usage Explorer', [ROUTES.INSTRUMENTATION]: 'Add instrumentation', @@ -15,7 +14,9 @@ const breadcrumbNameMap = { }; function ShowBreadcrumbs(props: RouteComponentProps): JSX.Element { - const pathArray = props.location.pathname.split('/').filter((i) => i); + const { location } = props; + + const pathArray = location.pathname.split('/').filter((i) => i); const extraBreadcrumbItems = pathArray.map((_, index) => { const url = `/${pathArray.slice(0, index + 1).join('/')}`; diff --git a/frontend/src/container/Header/CustomDateTimeModal/index.tsx b/frontend/src/container/Header/CustomDateTimeModal/index.tsx index 8e7d34ad5a..1f192d2d0e 100644 --- a/frontend/src/container/Header/CustomDateTimeModal/index.tsx +++ b/frontend/src/container/Header/CustomDateTimeModal/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/jsx-no-bind */ import { Modal } from 'antd'; import DatePicker from 'components/DatePicker'; import dayjs, { Dayjs } from 'dayjs'; @@ -22,10 +23,7 @@ function CustomDateTimeModal({ } function disabledDate(current: Dayjs): boolean { - if (current > dayjs()) { - return true; - } - return false; + return current > dayjs(); } return ( diff --git a/frontend/src/container/Header/DateTimeSelection/config.ts b/frontend/src/container/Header/DateTimeSelection/config.ts index 500267ac1c..29d031e25b 100644 --- a/frontend/src/container/Header/DateTimeSelection/config.ts +++ b/frontend/src/container/Header/DateTimeSelection/config.ts @@ -1,25 +1,25 @@ import ROUTES from 'constants/routes'; -type fiveMin = '5min'; -type fifteenMin = '15min'; -type thrityMin = '30min'; -type oneMin = '1min'; -type sixHour = '6hr'; -type oneHour = '1hr'; -type oneDay = '1day'; -type oneWeek = '1week'; -type custom = 'custom'; +type FiveMin = '5min'; +type FifteenMin = '15min'; +type ThirtyMin = '30min'; +type OneMin = '1min'; +type SixHour = '6hr'; +type OneHour = '1hr'; +type OneDay = '1day'; +type OneWeek = '1week'; +type Custom = 'custom'; export type Time = - | fiveMin - | fifteenMin - | thrityMin - | oneMin - | sixHour - | oneHour - | custom - | oneWeek - | oneDay; + | FiveMin + | FifteenMin + | ThirtyMin + | OneMin + | SixHour + | OneHour + | Custom + | OneWeek + | OneDay; export const Options: Option[] = [ { value: '5min', label: 'Last 5 min' }, diff --git a/frontend/src/container/Header/DateTimeSelection/index.tsx b/frontend/src/container/Header/DateTimeSelection/index.tsx index 34af09422c..c5df866842 100644 --- a/frontend/src/container/Header/DateTimeSelection/index.tsx +++ b/frontend/src/container/Header/DateTimeSelection/index.tsx @@ -1,12 +1,12 @@ import { Button, Select as DefaultSelect } from 'antd'; import getLocalStorageKey from 'api/browser/localstorage/get'; import setLocalStorageKey from 'api/browser/localstorage/set'; -import { LOCAL_STORAGE } from 'constants/localStorage'; +import { LOCALSTORAGE } from 'constants/localStorage'; import dayjs, { Dayjs } from 'dayjs'; import getTimeString from 'lib/getTimeString'; import React, { useCallback, useEffect, useState } from 'react'; import { connect, useSelector } from 'react-redux'; -import { RouteComponentProps, withRouter } from 'react-router'; +import { RouteComponentProps, withRouter } from 'react-router-dom'; import { bindActionCreators, Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; import { GlobalTimeLoading, UpdateTimeInterval } from 'store/actions'; @@ -26,7 +26,7 @@ function DateTimeSelection({ updateTimeInterval, globalTimeLoading, }: Props): JSX.Element { - const [form_dtselector] = Form.useForm(); + const [formSelector] = Form.useForm(); const params = new URLSearchParams(location.search); const searchStartTime = params.get('startTime'); @@ -72,10 +72,27 @@ function DateTimeSelection({ GlobalReducer >((state) => state.globalTime); + const getInputLabel = ( + startTime?: Dayjs, + endTime?: Dayjs, + timeInterval: Time = '15min', + ): string | Time => { + if (startTime && endTime && timeInterval === 'custom') { + const format = 'YYYY/MM/DD HH:mm'; + + const startString = startTime.format(format); + const endString = endTime.format(format); + + return `${startString} - ${endString}`; + } + + return timeInterval; + }; + const getDefaultTime = (pathName: string): Time => { const defaultSelectedOption = getDefaultOption(pathName); - const routes = getLocalStorageKey(LOCAL_STORAGE.METRICS_TIME_IN_DURATION); + const routes = getLocalStorageKey(LOCALSTORAGE.METRICS_TIME_IN_DURATION); if (routes !== null) { const routesObject = JSON.parse(routes || '{}'); @@ -94,7 +111,7 @@ function DateTimeSelection({ ); const updateLocalStorageForRoutes = (value: Time): void => { - const preRoutes = getLocalStorageKey(LOCAL_STORAGE.METRICS_TIME_IN_DURATION); + const preRoutes = getLocalStorageKey(LOCALSTORAGE.METRICS_TIME_IN_DURATION); if (preRoutes !== null) { const preRoutesObject = JSON.parse(preRoutes); @@ -104,46 +121,12 @@ function DateTimeSelection({ preRoute[location.pathname] = value; setLocalStorageKey( - LOCAL_STORAGE.METRICS_TIME_IN_DURATION, + LOCALSTORAGE.METRICS_TIME_IN_DURATION, JSON.stringify(preRoute), ); } }; - const onSelectHandler = (value: Time): void => { - if (value !== 'custom') { - updateTimeInterval(value); - const selectedLabel = getInputLabel(undefined, undefined, value); - setSelectedTimeInterval(selectedLabel as Time); - updateLocalStorageForRoutes(value); - } else { - setRefreshButtonHidden(true); - setCustomDTPickerVisible(true); - } - }; - - const onRefreshHandler = (): void => { - onSelectHandler(selectedTimeInterval); - onLastRefreshHandler(); - }; - - const getInputLabel = ( - startTime?: Dayjs, - endTime?: Dayjs, - timeInterval: Time = '15min', - ): string | Time => { - if (startTime && endTime && timeInterval === 'custom') { - const format = 'YYYY/MM/DD HH:mm'; - - const startString = startTime.format(format); - const endString = endTime.format(format); - - return `${startString} - ${endString}`; - } - - return timeInterval; - }; - const onLastRefreshHandler = useCallback(() => { const currentTime = dayjs(); @@ -177,6 +160,23 @@ function DateTimeSelection({ return `Last refresh - ${secondsDiff} sec ago`; }, [maxTime, minTime, selectedTimeInterval]); + const onSelectHandler = (value: Time): void => { + if (value !== 'custom') { + updateTimeInterval(value); + const selectedLabel = getInputLabel(undefined, undefined, value); + setSelectedTimeInterval(selectedLabel as Time); + updateLocalStorageForRoutes(value); + } else { + setRefreshButtonHidden(true); + setCustomDTPickerVisible(true); + } + }; + + const onRefreshHandler = (): void => { + onSelectHandler(selectedTimeInterval); + onLastRefreshHandler(); + }; + const onCustomDateHandler = (dateTimeRange: DateTimeRangeType): void => { if (dateTimeRange !== null) { const [startTimeMoment, endTimeMoment] = dateTimeRange; @@ -199,12 +199,12 @@ function DateTimeSelection({ // this is triggred when we change the routes and based on that we are changing the default options useEffect(() => { const metricsTimeDuration = getLocalStorageKey( - LOCAL_STORAGE.METRICS_TIME_IN_DURATION, + LOCALSTORAGE.METRICS_TIME_IN_DURATION, ); if (metricsTimeDuration === null) { setLocalStorageKey( - LOCAL_STORAGE.METRICS_TIME_IN_DURATION, + LOCALSTORAGE.METRICS_TIME_IN_DURATION, JSON.stringify({}), ); } @@ -252,12 +252,12 @@ function DateTimeSelection({ return (
onSelectHandler(value as Time)} + onSelect={(value: unknown): void => onSelectHandler(value as Time)} value={getInputLabel(startTime, endTime, selectedTime)} data-testid="dropDown" > diff --git a/frontend/src/container/Header/index.tsx b/frontend/src/container/Header/index.tsx index d019afcf10..b78275e28b 100644 --- a/frontend/src/container/Header/index.tsx +++ b/frontend/src/container/Header/index.tsx @@ -2,7 +2,7 @@ import { Col } from 'antd'; import ROUTES from 'constants/routes'; import history from 'lib/history'; import React from 'react'; -import { matchPath, useLocation } from 'react-router-dom'; +import { matchPath } from 'react-router-dom'; import ShowBreadcrumbs from './Breadcrumbs'; import DateTimeSelector from './DateTimeSelection'; @@ -21,7 +21,7 @@ function TopNav(): JSX.Element | null { } const checkRouteExists = (currentPath: string): boolean => { - for (let i = 0; i < routesToSkip.length; ++i) { + for (let i = 0; i < routesToSkip.length; i += 1) { if ( matchPath(currentPath, { path: routesToSkip[i], exact: true, strict: true }) ) { diff --git a/frontend/src/container/ListAlertRules/DeleteAlert.tsx b/frontend/src/container/ListAlertRules/DeleteAlert.tsx index b571183e12..f479de38ab 100644 --- a/frontend/src/container/ListAlertRules/DeleteAlert.tsx +++ b/frontend/src/container/ListAlertRules/DeleteAlert.tsx @@ -21,6 +21,8 @@ function DeleteAlert({ payload: undefined, }); + const defaultErrorMessage = 'Something went wrong'; + const onDeleteHandler = async (id: number): Promise => { try { setDeleteAlertState((state) => ({ @@ -48,11 +50,11 @@ function DeleteAlert({ ...state, loading: false, error: true, - errorMessage: response.error || 'Something went wrong', + errorMessage: response.error || defaultErrorMessage, })); notifications.error({ - message: response.error || 'Something went wrong', + message: response.error || defaultErrorMessage, }); } } catch (error) { @@ -60,11 +62,11 @@ function DeleteAlert({ ...state, loading: false, error: true, - errorMessage: 'Something went wrong', + errorMessage: defaultErrorMessage, })); notifications.error({ - message: 'Something went wrong', + message: defaultErrorMessage, }); } }; diff --git a/frontend/src/container/ListAlertRules/ListAlert.tsx b/frontend/src/container/ListAlertRules/ListAlert.tsx index 98099add31..5bff7041c8 100644 --- a/frontend/src/container/ListAlertRules/ListAlert.tsx +++ b/frontend/src/container/ListAlertRules/ListAlert.tsx @@ -8,7 +8,7 @@ import ROUTES from 'constants/routes'; import useInterval from 'hooks/useInterval'; import history from 'lib/history'; import React, { useCallback, useState } from 'react'; -import { generatePath } from 'react-router'; +import { generatePath } from 'react-router-dom'; import { Alerts } from 'types/api/alerts/getAll'; import DeleteAlert from './DeleteAlert'; diff --git a/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx b/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx index 854deefd3a..4848fa37da 100644 --- a/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx +++ b/frontend/src/container/ListOfDashboard/TableComponents/DeleteButton.tsx @@ -40,10 +40,18 @@ const WrapperDeleteButton = connect(null, mapDispatchToProps)(DeleteButton); // This is to avoid the type collision function Wrapper(props: Data): JSX.Element { + const { createdBy, description, id, key, lastUpdatedTime, name, tags } = props; + return ( ); diff --git a/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx b/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx index 342dcac336..fa2ff98991 100644 --- a/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx +++ b/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx @@ -7,10 +7,12 @@ import { generatePath } from 'react-router-dom'; import { Data } from '..'; function Name(name: Data['name'], data: Data): JSX.Element { - const onClickHandler = () => { + const onClickHandler = (): void => { + const { id: DashboardId } = data; + history.push( generatePath(ROUTES.DASHBOARD, { - dashboardId: data.id, + dashboardId: DashboardId, }), ); }; diff --git a/frontend/src/container/ListOfDashboard/TableComponents/Tags.tsx b/frontend/src/container/ListOfDashboard/TableComponents/Tags.tsx index 781e688e0a..40ecbe7c65 100644 --- a/frontend/src/container/ListOfDashboard/TableComponents/Tags.tsx +++ b/frontend/src/container/ListOfDashboard/TableComponents/Tags.tsx @@ -1,12 +1,13 @@ +/* eslint-disable react/destructuring-assignment */ import { Tag } from 'antd'; import React from 'react'; import { Data } from '../index'; -function Tags(props: Data['tags']): JSX.Element { +function Tags(data: Data['tags']): JSX.Element { return ( <> - {props.map((e) => ( + {data.map((e) => ( {e} ))} diff --git a/frontend/src/container/MetricsApplication/Tabs/External.tsx b/frontend/src/container/MetricsApplication/Tabs/External.tsx index 40d4981dd6..6497c7a7da 100644 --- a/frontend/src/container/MetricsApplication/Tabs/External.tsx +++ b/frontend/src/container/MetricsApplication/Tabs/External.tsx @@ -9,6 +9,8 @@ import { Card, GraphContainer, GraphTitle, Row } from '../styles'; function External({ getWidget }: ExternalProps): JSX.Element { const { servicename } = useParams<{ servicename?: string }>(); + const legend = '{{http_url}}'; + return ( <> @@ -23,7 +25,7 @@ function External({ getWidget }: ExternalProps): JSX.Element { widget={getWidget([ { query: `max((sum(rate(signoz_external_call_latency_count{service_name="${servicename}", status_code="STATUS_CODE_ERROR"}[1m]) OR rate(signoz_external_call_latency_count{service_name="${servicename}", http_status_code=~"5.."}[1m]) OR vector(0)) by (http_url))*100/sum(rate(signoz_external_call_latency_count{service_name="${servicename}"}[1m])) by (http_url)) < 1000 OR vector(0)`, - legend: '{{http_url}}', + legend, }, ])} yAxisUnit="%" @@ -65,7 +67,7 @@ function External({ getWidget }: ExternalProps): JSX.Element { widget={getWidget([ { query: `sum(rate(signoz_external_call_latency_count{service_name="${servicename}"}[5m])) by (http_url)`, - legend: '{{http_url}}', + legend, }, ])} yAxisUnit="reqps" @@ -85,7 +87,7 @@ function External({ getWidget }: ExternalProps): JSX.Element { widget={getWidget([ { query: `(sum(rate(signoz_external_call_latency_sum{service_name="${servicename}"}[5m])) by (http_url))/(sum(rate(signoz_external_call_latency_count{service_name="${servicename}"}[5m])) by (http_url))`, - legend: '{{http_url}}', + legend, }, ])} yAxisUnit="ms" diff --git a/frontend/src/container/MetricsApplication/TopEndpointsTable.tsx b/frontend/src/container/MetricsApplication/TopEndpointsTable.tsx index 07961ad8d2..1f1cbba643 100644 --- a/frontend/src/container/MetricsApplication/TopEndpointsTable.tsx +++ b/frontend/src/container/MetricsApplication/TopEndpointsTable.tsx @@ -2,19 +2,20 @@ import { Button, Table, Tooltip } from 'antd'; import { ColumnsType } from 'antd/lib/table'; import { METRICS_PAGE_QUERY_PARAM } from 'constants/query'; import ROUTES from 'constants/routes'; +import history from 'lib/history'; import React from 'react'; import { useSelector } from 'react-redux'; import { useParams } from 'react-router-dom'; -import { topEndpointListItem } from 'store/actions/MetricsActions'; import { AppState } from 'store/reducers'; import { GlobalReducer } from 'types/reducer/globalTime'; -import history from 'lib/history'; function TopEndpointsTable(props: TopEndpointsTableProps): JSX.Element { const { minTime, maxTime } = useSelector( (state) => state.globalTime, ); + const { data } = props; + const params = useParams<{ servicename: string }>(); const handleOnClick = (operation: string): void => { @@ -80,7 +81,7 @@ function TopEndpointsTable(props: TopEndpointsTableProps): JSX.Element { title: 'Number of Calls', dataIndex: 'numCalls', key: 'numCalls', - sorter: (a: topEndpointListItem, b: topEndpointListItem): number => + sorter: (a: TopEndpointListItem, b: TopEndpointListItem): number => a.numCalls - b.numCalls, }, ]; @@ -91,7 +92,7 @@ function TopEndpointsTable(props: TopEndpointsTableProps): JSX.Element { title={(): string => { return 'Top Endpoints'; }} - dataSource={props.data} + dataSource={data} columns={columns} pagination={false} rowKey="name" @@ -99,10 +100,18 @@ function TopEndpointsTable(props: TopEndpointsTableProps): JSX.Element { ); } -type DataProps = topEndpointListItem; +interface TopEndpointListItem { + p50: number; + p95: number; + p99: number; + numCalls: number; + name: string; +} + +type DataProps = TopEndpointListItem; interface TopEndpointsTableProps { - data: topEndpointListItem[]; + data: TopEndpointListItem[]; } export default TopEndpointsTable; diff --git a/frontend/src/container/MetricsTable/SkipOnBoardModal/index.tsx b/frontend/src/container/MetricsTable/SkipOnBoardModal/index.tsx index 2e9328bd0f..b50c0ac9fb 100644 --- a/frontend/src/container/MetricsTable/SkipOnBoardModal/index.tsx +++ b/frontend/src/container/MetricsTable/SkipOnBoardModal/index.tsx @@ -22,6 +22,7 @@ function SkipOnBoardingModal({ onContinueClick }: Props): JSX.Element { frameBorder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowFullScreen + title="youtube_video" />
No instrumentation data. diff --git a/frontend/src/container/MetricsTable/index.tsx b/frontend/src/container/MetricsTable/index.tsx index ce39047593..de9fa4976a 100644 --- a/frontend/src/container/MetricsTable/index.tsx +++ b/frontend/src/container/MetricsTable/index.tsx @@ -6,8 +6,8 @@ import ROUTES from 'constants/routes'; import React, { useState } from 'react'; import { useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; -import { servicesListItem } from 'store/actions/MetricsActions/metricsInterfaces'; import { AppState } from 'store/reducers'; +import { ServicesList } from 'types/api/metrics/getService'; import MetricReducer from 'types/reducer/metrics'; import SkipBoardModal from './SkipOnBoardModal'; @@ -27,10 +27,6 @@ function Metrics(): JSX.Element { setSkipOnboarding(true); }; - const onClickHandler = (to: string): void => { - window.open(to, '_blank'); - }; - if ( services.length === 0 && loading === false && @@ -88,6 +84,6 @@ function Metrics(): JSX.Element { ); } -type DataProps = servicesListItem; +type DataProps = ServicesList; export default Metrics; diff --git a/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.ts b/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.ts index c8ee593185..d820142baa 100644 --- a/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.ts +++ b/frontend/src/container/NewDashboard/ComponentsSlider/menuItems.ts @@ -1,6 +1,4 @@ -import TimeSeries, { - TimeSeriesProps as IconProps, -} from 'assets/Dashboard/TimeSeries'; +import TimeSeries from 'assets/Dashboard/TimeSeries'; import ValueIcon from 'assets/Dashboard/Value'; const Items: ItemsProps[] = [ @@ -24,4 +22,8 @@ interface ItemsProps { display: string; } +interface IconProps { + fillColor: React.CSSProperties['color']; +} + export default Items; diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx index 1bc4a2ba90..42b22fe206 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx @@ -4,7 +4,7 @@ import TextToolTip from 'components/TextToolTip'; import { timePreferance } from 'container/NewWidget/RightContainer/timeItems'; import React, { useCallback, useState } from 'react'; import { connect } from 'react-redux'; -import { useLocation } from 'react-router'; +import { useLocation } from 'react-router-dom'; import { bindActionCreators, Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; import { DeleteQuery } from 'store/actions'; diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx index f4935ba533..c0ad837b9c 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/index.tsx @@ -2,7 +2,7 @@ import { PlusOutlined } from '@ant-design/icons'; import { timePreferance } from 'container/NewWidget/RightContainer/timeItems'; import React, { useCallback, useMemo } from 'react'; import { connect, useSelector } from 'react-redux'; -import { useLocation } from 'react-router'; +import { useLocation } from 'react-router-dom'; import { bindActionCreators, Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; import { CreateQuery, CreateQueryProps } from 'store/actions'; diff --git a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.tsx b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.tsx index 9c11b15bc4..2a6fd02a00 100644 --- a/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/WidgetGraph/WidgetGraph.tsx @@ -4,7 +4,7 @@ import { NewWidgetProps } from 'container/NewWidget'; import getChartData from 'lib/getChartData'; import React from 'react'; import { useSelector } from 'react-redux'; -import { useLocation } from 'react-router'; +import { useLocation } from 'react-router-dom'; import { AppState } from 'store/reducers'; import DashboardReducer from 'types/reducer/dashboards'; diff --git a/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx b/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx index 1af32aff45..0401069b2e 100644 --- a/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx +++ b/frontend/src/container/NewWidget/RightContainer/YAxisUnitSelector.tsx @@ -4,12 +4,24 @@ import React from 'react'; import { flattenedCategories } from './dataFormatCategories'; -const findCategoryById = (searchValue) => - find(flattenedCategories, (option) => option.id == searchValue); -const findCategoryByName = (searchValue) => - find(flattenedCategories, (option) => option.name == searchValue); +const findCategoryById = ( + searchValue: string, +): Record | undefined => + find(flattenedCategories, (option) => option.id === searchValue); +const findCategoryByName = ( + searchValue: string, +): Record | undefined => + find(flattenedCategories, (option) => option.name === searchValue); -function YAxisUnitSelector({ defaultValue, onSelect, fieldLabel }): JSX.Element { +function YAxisUnitSelector({ + defaultValue, + onSelect, + fieldLabel, +}: { + defaultValue: string; + onSelect: (e: string | undefined) => void; + fieldLabel: string; +}): JSX.Element { const onSelectHandler = (selectedValue: string): void => { onSelect(findCategoryByName(selectedValue)?.id); }; @@ -26,9 +38,14 @@ function YAxisUnitSelector({ defaultValue, onSelect, fieldLabel }): JSX.Element options={options} defaultValue={findCategoryById(defaultValue)?.name} onSelect={onSelectHandler} - filterOption={(inputValue, option): boolean => - option!.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1 - } + filterOption={(inputValue, option): boolean => { + if (option) { + return ( + option.value.toUpperCase().indexOf(inputValue.toUpperCase()) !== -1 + ); + } + return false; + }} > diff --git a/frontend/src/container/NewWidget/RightContainer/index.tsx b/frontend/src/container/NewWidget/RightContainer/index.tsx index dc9f79f0c5..f1c9460fd0 100644 --- a/frontend/src/container/NewWidget/RightContainer/index.tsx +++ b/frontend/src/container/NewWidget/RightContainer/index.tsx @@ -1,23 +1,11 @@ -import { - // Button, - Input, - // Slider, - // Switch, - // Typography, -} from 'antd'; +import { Input } from 'antd'; import InputComponent from 'components/Input'; import TimePreference from 'components/TimePreferenceDropDown'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import GraphTypes from 'container/NewDashboard/ComponentsSlider/menuItems'; import React, { useCallback } from 'react'; -import { dataTypeCategories } from './dataFormatCategories'; -import { - Container, - // NullButtonContainer, TextContainer, - Title, -} from './styles'; -// import {ca} from '@grafana/data' +import { Container, Title } from './styles'; import { timePreferance } from './timeItems'; import YAxisUnitSelector from './YAxisUnitSelector'; @@ -25,14 +13,8 @@ const { TextArea } = Input; function RightContainer({ description, - // opacity, - // selectedNullZeroValue, setDescription, - // setOpacity, - // setSelectedNullZeroValue, - // setStacked, setTitle, - // stacked, title, selectedGraph, setSelectedTime, @@ -47,21 +29,6 @@ function RightContainer({ [], ); - // const nullValueButtons = [ - // { - // check: 'zero', - // name: 'Zero', - // }, - // { - // check: 'interpolate', - // name: 'Interpolate', - // }, - // { - // check: 'blank', - // name: 'Blank', - // }, - // ]; - const selectedGraphType = GraphTypes.find((e) => e.name === selectedGraph)?.display || ''; diff --git a/frontend/src/container/NewWidget/RightContainer/timeItems.ts b/frontend/src/container/NewWidget/RightContainer/timeItems.ts index 6ceb175d71..1a2ecfeb5a 100644 --- a/frontend/src/container/NewWidget/RightContainer/timeItems.ts +++ b/frontend/src/container/NewWidget/RightContainer/timeItems.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ export const timeItems: timePreferance[] = [ { name: 'Global Time', diff --git a/frontend/src/container/NewWidget/index.tsx b/frontend/src/container/NewWidget/index.tsx index 42abe26911..4943948abe 100644 --- a/frontend/src/container/NewWidget/index.tsx +++ b/frontend/src/container/NewWidget/index.tsx @@ -5,8 +5,7 @@ import history from 'lib/history'; import { DashboardWidgetPageParams } from 'pages/DashboardWidget'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { connect, useSelector } from 'react-redux'; -import { useLocation, useParams } from 'react-router'; -import { generatePath } from 'react-router-dom'; +import { generatePath, useLocation, useParams } from 'react-router-dom'; import { bindActionCreators, Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; import { ApplySettingsToPanel, ApplySettingsToPanelProps } from 'store/actions'; @@ -30,7 +29,7 @@ import { GlobalReducer } from 'types/reducer/globalTime'; import LeftContainer from './LeftContainer'; import RightContainer from './RightContainer'; -import timeItems, { timePreferance } from './RightContainer/timeItems'; +import TimeItems, { timePreferance } from './RightContainer/timeItems'; import { ButtonContainer, Container, @@ -91,7 +90,7 @@ function NewWidget({ const getSelectedTime = useCallback( () => - timeItems.find( + TimeItems.find( (e) => e.enum === (selectedWidget?.timePreferance || 'GLOBAL_TIME'), ), [selectedWidget], diff --git a/frontend/src/container/SideNav/index.tsx b/frontend/src/container/SideNav/index.tsx index 8292cc5283..4902986dbd 100644 --- a/frontend/src/container/SideNav/index.tsx +++ b/frontend/src/container/SideNav/index.tsx @@ -3,7 +3,7 @@ import getLocalStorageKey from 'api/browser/localstorage/get'; import { IS_SIDEBAR_COLLAPSED } from 'constants/app'; import ROUTES from 'constants/routes'; import history from 'lib/history'; -import setTheme from 'lib/theme/setTheme'; +import setTheme, { AppMode } from 'lib/theme/setTheme'; import React, { useCallback, useLayoutEffect, useState } from 'react'; import { connect, useDispatch, useSelector } from 'react-redux'; import { NavLink, useLocation } from 'react-router-dom'; @@ -36,10 +36,10 @@ function SideNav({ toggleDarkMode }: Props): JSX.Element { const { pathname } = useLocation(); const toggleTheme = useCallback(() => { - const preMode: appMode = isDarkMode ? 'lightMode' : 'darkMode'; + const preMode: AppMode = isDarkMode ? 'lightMode' : 'darkMode'; setTheme(preMode); - const id: appMode = preMode; + const id: AppMode = preMode; const { head } = document; const link = document.createElement('link'); link.rel = 'stylesheet'; @@ -115,8 +115,6 @@ function SideNav({ toggleDarkMode }: Props): JSX.Element { ); } -type appMode = 'darkMode' | 'lightMode'; - interface DispatchProps { toggleDarkMode: () => void; } diff --git a/frontend/src/container/SideNav/styles.ts b/frontend/src/container/SideNav/styles.ts index 33792a2904..0066d2affd 100644 --- a/frontend/src/container/SideNav/styles.ts +++ b/frontend/src/container/SideNav/styles.ts @@ -1,4 +1,5 @@ -import { Layout, Menu, Switch, Typography } from 'antd'; +import { Layout, Switch, Typography } from 'antd'; +import { StyledCSS } from 'container/GantChart/Trace/styles'; import styled, { css } from 'styled-components'; const { Sider: SiderComponent } = Layout; @@ -37,7 +38,7 @@ interface DarkModeProps { export const ToggleButton = styled(Switch)` &&& { - background: ${({ checked }) => checked === false && 'grey'}; + background: ${({ checked }): string => (checked === false ? 'grey' : '')}; } `; @@ -51,11 +52,11 @@ export const SlackMenuItemContainer = styled.div` position: fixed; bottom: 48px; background: #262626; - width: ${({ collapsed }) => (!collapsed ? '200px' : '80px')}; + width: ${({ collapsed }): string => (!collapsed ? '200px' : '80px')}; &&& { li { - ${({ collapsed }) => + ${({ collapsed }): StyledCSS => collapsed && css` padding-left: 24px; @@ -63,9 +64,9 @@ export const SlackMenuItemContainer = styled.div` } svg { - margin-left: ${({ collapsed }) => (collapsed ? '0' : '24px')}; + margin-left: ${({ collapsed }): string => (collapsed ? '0' : '24px')}; - ${({ collapsed }) => + ${({ collapsed }): StyledCSS => collapsed && css` height: 100%; diff --git a/frontend/src/container/Timeline/index.tsx b/frontend/src/container/Timeline/index.tsx index 19aa63e15a..a8a12927bb 100644 --- a/frontend/src/container/Timeline/index.tsx +++ b/frontend/src/container/Timeline/index.tsx @@ -1,15 +1,15 @@ import { StyledDiv } from 'components/Styled'; import { IIntervalUnit, INTERVAL_UNITS } from 'container/TraceDetail/utils'; import useThemeMode from 'hooks/useThemeMode'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { useMeasure } from 'react-use'; import { styles, Svg, TimelineInterval } from './styles'; import { Interval } from './types'; import { getIntervals, getIntervalSpread } from './utils'; -const Timeline_Height = 22; -const Timeline_H_Spacing = 0; +const TimelineHeight = 22; +const TimelineHSpacing = 0; function Timeline({ traceMetaData, @@ -19,6 +19,10 @@ function Timeline({ const [ref, { width }] = useMeasure(); const { isDarkMode } = useThemeMode(); + const asd = useRef(''); + + asd.current = '1'; + const [intervals, setIntervals] = useState(null); useEffect(() => { @@ -32,10 +36,10 @@ function Timeline({ }); let intervalUnit = INTERVAL_UNITS[0]; - for (let idx = 0; idx < INTERVAL_UNITS.length; idx++) { - const standard_interval = INTERVAL_UNITS[idx]; - if (baseSpread * standard_interval.multiplier < 1) { - const index = parseInt(idx, 10); + for (let idx = 0; idx < INTERVAL_UNITS.length; idx += 1) { + const standardInterval = INTERVAL_UNITS[idx]; + if (baseSpread * standardInterval.multiplier < 1) { + const index = idx; if (index > 1) intervalUnit = INTERVAL_UNITS[index - 1]; break; } @@ -54,16 +58,16 @@ function Timeline({ }, [traceMetaData, globalTraceMetadata, setIntervalUnit]); return ( - + @@ -71,8 +75,8 @@ function Timeline({ intervals.map((interval, index) => ( @@ -80,8 +84,8 @@ function Timeline({ {interval.label} @@ -101,7 +105,6 @@ interface TimelineProps { levels: number; }; globalTraceMetadata: Record; - intervalUnit: IIntervalUnit; setIntervalUnit: React.Dispatch>; } diff --git a/frontend/src/container/Timeline/utils.ts b/frontend/src/container/Timeline/utils.ts index cf2509bc4a..60bec06331 100644 --- a/frontend/src/container/Timeline/utils.ts +++ b/frontend/src/container/Timeline/utils.ts @@ -1,5 +1,5 @@ import { - INTERVAL_UNITS, + IIntervalUnit, resolveTimeFromInterval, } from 'container/TraceDetail/utils'; import { isEqual } from 'lodash-es'; @@ -7,9 +7,14 @@ import { toFixed } from 'utils/toFixed'; import { Interval } from './types'; +type TMetaDataType = Record; + export const getIntervalSpread = ({ localTraceMetaData, globalTraceMetadata, +}: { + localTraceMetaData: TMetaDataType; + globalTraceMetadata: TMetaDataType; }): { baseInterval: number; baseSpread: number; @@ -46,6 +51,11 @@ export const getIntervals = ({ baseSpread, intervalSpreadNormalized, intervalUnit, +}: { + baseInterval: number; + baseSpread: number; + intervalSpreadNormalized: number; + intervalUnit: IIntervalUnit; }): Interval[] => { const intervals: Interval[] = [ { @@ -60,21 +70,21 @@ export const getIntervals = ({ let elapsedIntervals = 0; while (tempBaseSpread && intervals.length < 20) { - let interval_time; + let intervalTime; if (tempBaseSpread <= 1.5 * intervalSpreadNormalized) { - interval_time = elapsedIntervals + tempBaseSpread; + intervalTime = elapsedIntervals + tempBaseSpread; tempBaseSpread = 0; } else { - interval_time = elapsedIntervals + intervalSpreadNormalized; + intervalTime = elapsedIntervals + intervalSpreadNormalized; tempBaseSpread -= intervalSpreadNormalized; } - elapsedIntervals = interval_time; + elapsedIntervals = intervalTime; const interval: Interval = { label: `${toFixed( - resolveTimeFromInterval(interval_time + baseInterval, intervalUnit), + resolveTimeFromInterval(intervalTime + baseInterval, intervalUnit), 2, )}${intervalUnit.name}`, - percentage: (interval_time / baseSpread) * 100, + percentage: (intervalTime / baseSpread) * 100, }; intervals.push(interval); } diff --git a/frontend/src/container/Trace/Filters/Panel/PanelBody/Common/Checkbox.tsx b/frontend/src/container/Trace/Filters/Panel/PanelBody/Common/Checkbox.tsx index d2b588066e..e177f1b4b3 100644 --- a/frontend/src/container/Trace/Filters/Panel/PanelBody/Common/Checkbox.tsx +++ b/frontend/src/container/Trace/Filters/Panel/PanelBody/Common/Checkbox.tsx @@ -2,10 +2,8 @@ import { Checkbox, notification, Typography } from 'antd'; import getFilters from 'api/trace/getFilters'; import { AxiosError } from 'axios'; import React, { useState } from 'react'; -import { connect, useDispatch, useSelector } from 'react-redux'; -import { bindActionCreators, Dispatch } from 'redux'; -import { ThunkDispatch } from 'redux-thunk'; -import { SelectedTraceFilter } from 'store/actions/trace/selectTraceFilter'; +import { useDispatch, useSelector } from 'react-redux'; +import { Dispatch } from 'redux'; import { getFilter, updateURL } from 'store/actions/trace/util'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; @@ -30,17 +28,18 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element { const globalTime = useSelector( (state) => state.globalTime, ); + const { keyValue, name, value } = props; const dispatch = useDispatch>(); const [isLoading, setIsLoading] = useState(false); const isUserSelected = - (userSelectedFilter.get(props.name) || []).find( - (e) => e === props.keyValue, - ) !== undefined; + (userSelectedFilter.get(name) || []).find((e) => e === keyValue) !== + undefined; - const onCheckHandler = async () => { + // eslint-disable-next-line sonarjs/cognitive-complexity + const onCheckHandler = async (): Promise => { try { setIsLoading(true); @@ -48,48 +47,46 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element { const preUserSelectedMap = new Map(userSelectedFilter); const preIsFilterExclude = new Map(isFilterExclude); - const isTopicPresent = preUserSelectedMap.get(props.name); + const isTopicPresent = preUserSelectedMap.get(name); // append the value if (!isTopicPresent) { - preUserSelectedMap.set(props.name, [props.keyValue]); + preUserSelectedMap.set(name, [keyValue]); } else { const isValuePresent = - isTopicPresent.find((e) => e === props.keyValue) !== undefined; + isTopicPresent.find((e) => e === keyValue) !== undefined; // check the value if present then remove the value or isChecked if (isValuePresent) { preUserSelectedMap.set( - props.name, - isTopicPresent.filter((e) => e !== props.keyValue), + name, + isTopicPresent.filter((e) => e !== keyValue), ); } else { // if not present add into the array of string - preUserSelectedMap.set(props.name, [...isTopicPresent, props.keyValue]); + preUserSelectedMap.set(name, [...isTopicPresent, keyValue]); } } - if (newSelectedMap.get(props.name)?.find((e) => e === props.keyValue)) { - newSelectedMap.set(props.name, [ - ...(newSelectedMap.get(props.name) || []).filter( - (e) => e !== props.keyValue, - ), + if (newSelectedMap.get(name)?.find((e) => e === keyValue)) { + newSelectedMap.set(name, [ + ...(newSelectedMap.get(name) || []).filter((e) => e !== keyValue), ]); } else { - newSelectedMap.set(props.name, [ - ...new Set([...(newSelectedMap.get(props.name) || []), props.keyValue]), + newSelectedMap.set(name, [ + ...new Set([...(newSelectedMap.get(name) || []), keyValue]), ]); } - if (preIsFilterExclude.get(props.name) !== false) { - preIsFilterExclude.set(props.name, true); + if (preIsFilterExclude.get(name) !== false) { + preIsFilterExclude.set(name, true); } const response = await getFilters({ other: Object.fromEntries(newSelectedMap), end: String(globalTime.maxTime), start: String(globalTime.minTime), - getFilters: filterToFetchData.filter((e) => e !== props.name), + getFilters: filterToFetchData.filter((e) => e !== name), isFilterExclude: preIsFilterExclude, }); @@ -97,15 +94,15 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element { const updatedFilter = getFilter(response.payload); updatedFilter.forEach((value, key) => { - if (key !== 'duration' && props.name !== key) { + if (key !== 'duration' && name !== key) { preUserSelectedMap.set(key, Object.keys(value)); } }); - updatedFilter.set(props.name, { - [`${props.keyValue}`]: '-1', - ...(filter.get(props.name) || {}), - ...(updatedFilter.get(props.name) || {}), + updatedFilter.set(name, { + [`${keyValue}`]: '-1', + ...(filter.get(name) || {}), + ...(updatedFilter.get(name) || {}), }); dispatch({ @@ -156,12 +153,12 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element { onClick={onCheckHandler} checked={isCheckBoxSelected} defaultChecked - key={props.keyValue} + key={keyValue} > - {props.keyValue} + {keyValue} {isCheckBoxSelected ? ( - {props.value} + {value} ) : ( - )} @@ -169,23 +166,10 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element { ); } -interface DispatchProps { - selectedTraceFilter: (props: { - topic: TraceFilterEnum; - value: string; - }) => void; -} - -interface CheckBoxProps extends DispatchProps { +interface CheckBoxProps { keyValue: string; - value: string; name: TraceFilterEnum; + value: string; } -const mapDispatchToProps = ( - dispatch: ThunkDispatch, -): DispatchProps => ({ - selectedTraceFilter: bindActionCreators(SelectedTraceFilter, dispatch), -}); - -export default connect(null, mapDispatchToProps)(CheckBoxComponent); +export default CheckBoxComponent; diff --git a/frontend/src/container/Trace/Filters/Panel/PanelBody/CommonCheckBox/index.tsx b/frontend/src/container/Trace/Filters/Panel/PanelBody/CommonCheckBox/index.tsx index 82e20c4ecc..161bb6f8ac 100644 --- a/frontend/src/container/Trace/Filters/Panel/PanelBody/CommonCheckBox/index.tsx +++ b/frontend/src/container/Trace/Filters/Panel/PanelBody/CommonCheckBox/index.tsx @@ -10,7 +10,9 @@ function CommonCheckBox(props: CommonCheckBoxProps): JSX.Element { (state) => state.traces, ); - const status = filter.get(props.name) || {}; + const { name } = props; + + const status = filter.get(name) || {}; const statusObj = Object.keys(status); @@ -20,7 +22,7 @@ function CommonCheckBox(props: CommonCheckBoxProps): JSX.Element { { +const getMs = (value: string): string => { return dayjs .duration({ milliseconds: parseInt(value, 10) / 1000000, @@ -42,7 +43,9 @@ function Duration(): JSX.Element { (state) => state.globalTime, ); - const getDuration = () => { + const getDuration = (): + | { maxDuration: string; minDuration: string } + | Record => { const selectedDuration = selectedFilter.get('duration'); if (selectedDuration) { @@ -65,7 +68,7 @@ function Duration(): JSX.Element { const defaultValue = [parseFloat(minDuration), parseFloat(maxDuration)]; - const updatedUrl = async (min: number, max: number) => { + const updatedUrl = async (min: number, max: number): Promise => { const preSelectedFilter = new Map(selectedFilter); const preUserSelected = new Map(userSelectedFilter); @@ -114,7 +117,7 @@ function Duration(): JSX.Element { } }; - const onRangeSliderHandler = (number: [number, number]) => { + const onRangeSliderHandler = (number: [number, number]): void => { const [min, max] = number; setLocalMin(min.toString()); @@ -124,11 +127,10 @@ function Duration(): JSX.Element { const debouncedFunction = useDebouncedFn( (min, max) => { console.log('debounce function'); - updatedUrl(min, max); + updatedUrl(min as number, max as number); }, 500, undefined, - [], ); const onChangeMaxHandler: React.ChangeEventHandler = ( @@ -187,21 +189,16 @@ function Duration(): JSX.Element { min={parseFloat((filter.get('duration') || {}).minDuration)} max={parseFloat((filter.get('duration') || {}).maxDuration)} range - tipFormatter={(value) => { + tipFormatter={(value): JSX.Element => { if (value === undefined) { - return ''; + return
; } return
{`${getMs(value.toString())}ms`}
; }} - onChange={([min, max]) => { + onChange={([min, max]): void => { onRangeSliderHandler([min, max]); }} onAfterChange={onRangeHandler} - // onAfterChange={([min, max]) => { - // const returnFunction = debounce((min, max) => updatedUrl(min, max)); - - // returnFunction(min, max); - // }} value={[parseFloat(localMin), parseFloat(localMax)]} /> diff --git a/frontend/src/container/Trace/Filters/Panel/PanelHeading/index.tsx b/frontend/src/container/Trace/Filters/Panel/PanelHeading/index.tsx index 26ba4f899f..50686d1b78 100644 --- a/frontend/src/container/Trace/Filters/Panel/PanelHeading/index.tsx +++ b/frontend/src/container/Trace/Filters/Panel/PanelHeading/index.tsx @@ -38,8 +38,10 @@ function PanelHeading(props: PanelHeadingProps): JSX.Element { userSelectedFilter, } = useSelector((state) => state.traces); + const { name: PanelName, isOpen: IsPanelOpen } = props; + const isDefaultOpen = - filterToFetchData.find((e) => e === props.name) !== undefined; + filterToFetchData.find((e) => e === PanelName) !== undefined; const [isLoading, setIsLoading] = useState(false); @@ -49,6 +51,9 @@ function PanelHeading(props: PanelHeadingProps): JSX.Element { const dispatch = useDispatch>(); + const defaultErrorMessage = 'Something went wrong'; + + // eslint-disable-next-line sonarjs/cognitive-complexity const onExpandHandler: React.MouseEventHandler = async (e) => { try { e.preventDefault(); @@ -60,14 +65,14 @@ function PanelHeading(props: PanelHeadingProps): JSX.Element { const getPreUserSelected = new Map(userSelectedFilter); if (!isDefaultOpen) { - updatedFilterData = [props.name]; + updatedFilterData = [PanelName]; } else { // removing the selected filter updatedFilterData = [ - ...filterToFetchData.filter((name) => name !== props.name), + ...filterToFetchData.filter((name) => name !== PanelName), ]; - getprepdatedSelectedFilter.delete(props.name); - getPreUserSelected.delete(props.name); + getprepdatedSelectedFilter.delete(PanelName); + getPreUserSelected.delete(PanelName); } const response = await getFilters({ @@ -89,11 +94,11 @@ function PanelHeading(props: PanelHeadingProps): JSX.Element { // ); getPreUserSelected.set( - props.name, - Object.keys(updatedFilter.get(props.name) || {}), + PanelName, + Object.keys(updatedFilter.get(PanelName) || {}), ); - updatedFilterData = [...filterToFetchData, props.name]; + updatedFilterData = [...filterToFetchData, PanelName]; } // now append the non prop.name trace filter enum over the list @@ -104,12 +109,12 @@ function PanelHeading(props: PanelHeadingProps): JSX.Element { // }); getPreUserSelected.forEach((value, key) => { - if (key !== props.name) { + if (key !== PanelName) { getPreUserSelected.set(key, value); } }); filter.forEach((value, key) => { - if (key !== props.name) { + if (key !== PanelName) { updatedFilter.set(key, value); } }); @@ -138,30 +143,30 @@ function PanelHeading(props: PanelHeadingProps): JSX.Element { ); } else { notification.error({ - message: response.error || 'Something went wrong', + message: response.error || defaultErrorMessage, }); } setIsLoading(false); } catch (error) { notification.error({ - message: (error as AxiosError).toString() || 'Something went wrong', + message: (error as AxiosError).toString() || defaultErrorMessage, }); } }; - const onClearAllHandler = async () => { + const onClearAllHandler = async (): Promise => { try { setIsLoading(true); const updatedFilter = new Map(selectedFilter); const preUserSelected = new Map(userSelectedFilter); - updatedFilter.delete(props.name); - preUserSelected.delete(props.name); + updatedFilter.delete(PanelName); + preUserSelected.delete(PanelName); const postIsFilterExclude = new Map(isFilterExclude); - postIsFilterExclude.set(props.name, false); + postIsFilterExclude.set(PanelName, false); const response = await getFilters({ end: String(global.maxTime), @@ -267,25 +272,25 @@ function PanelHeading(props: PanelHeadingProps): JSX.Element { return ( <> - {props.name !== 'duration' && } + {PanelName !== 'duration' && } - {!props.isOpen ? : } + {!IsPanelOpen ? : } - {AllPanelHeading.find((e) => e.key === props.name)?.displayValue || ''} + {AllPanelHeading.find((e) => e.key === PanelName)?.displayValue || ''} - {props.name !== 'duration' && ( + {PanelName !== 'duration' && ( {/* ` padding-left: 0.5rem; min-height: 5vh; - cursor: ${({ disabled }) => disabled && 'not-allowed'}; + cursor: ${({ disabled }): string => (disabled ? 'not-allowed' : '')}; - ${({ disabled }) => + ${({ disabled }): StyledCSS => disabled && css` opacity: 0.5; diff --git a/frontend/src/container/Trace/Filters/Panel/index.tsx b/frontend/src/container/Trace/Filters/Panel/index.tsx index d46db26091..b044d57ea0 100644 --- a/frontend/src/container/Trace/Filters/Panel/index.tsx +++ b/frontend/src/container/Trace/Filters/Panel/index.tsx @@ -9,14 +9,16 @@ import PanelHeading from './PanelHeading'; function Panel(props: PanelProps): JSX.Element { const traces = useSelector((state) => state.traces); + const { name } = props; + const isDefaultOpen = - traces.filterToFetchData.find((e) => e === props.name) !== undefined; + traces.filterToFetchData.find((e) => e === name) !== undefined; return ( <> - + - {isDefaultOpen && } + {isDefaultOpen && } ); } diff --git a/frontend/src/container/Trace/Filters/styles.ts b/frontend/src/container/Trace/Filters/styles.ts index a5a63ab931..de3d83afa1 100644 --- a/frontend/src/container/Trace/Filters/styles.ts +++ b/frontend/src/container/Trace/Filters/styles.ts @@ -1,4 +1,4 @@ -import { Button, Input } from 'antd'; +import { Input } from 'antd'; import styled from 'styled-components'; export const DurationContainer = styled.div` diff --git a/frontend/src/container/Trace/Graph/config.ts b/frontend/src/container/Trace/Graph/config.ts index 2c3387a834..de6408354c 100644 --- a/frontend/src/container/Trace/Graph/config.ts +++ b/frontend/src/container/Trace/Graph/config.ts @@ -1,17 +1,17 @@ -import { ChartData, ChartDataset, ChartDatasetProperties } from 'chart.js'; +import { ChartData, ChartDatasetProperties } from 'chart.js'; import dayjs from 'dayjs'; import { colors } from 'lib/getRandomColor'; import { keys } from 'lodash-es'; import { TraceReducer } from 'types/reducer/trace'; -function transposeArray(array: number[][], arrayLength: number) { +function transposeArray(array: number[][], arrayLength: number): number[][] { const newArray: number[][] = []; - for (let i = 0; i < array.length; i++) { + for (let i = 0; i < array.length; i += 1) { newArray.push([]); } - for (let i = 0; i < array.length; i++) { - for (let j = 0; j < arrayLength; j++) { + for (let i = 0; i < array.length; i += 1) { + for (let j = 0; j < arrayLength; j += 1) { newArray[j]?.push(array[i][j]); } } diff --git a/frontend/src/container/Trace/Graph/styles.ts b/frontend/src/container/Trace/Graph/styles.ts index 617a7837d7..16878bf6af 100644 --- a/frontend/src/container/Trace/Graph/styles.ts +++ b/frontend/src/container/Trace/Graph/styles.ts @@ -1,3 +1,4 @@ +import { StyledCSS } from 'container/GantChart/Trace/styles'; import React from 'react'; import styled, { css } from 'styled-components'; @@ -13,7 +14,7 @@ export const Container = styled.div` overflow: auto; width: 100% !important; - ${({ center }) => + ${({ center }): StyledCSS => center && css` display: flex; diff --git a/frontend/src/container/Trace/Search/AllTags/Tag/TagKey.tsx b/frontend/src/container/Trace/Search/AllTags/Tag/TagKey.tsx index e8ed0a97c7..aa6f95a4e6 100644 --- a/frontend/src/container/Trace/Search/AllTags/Tag/TagKey.tsx +++ b/frontend/src/container/Trace/Search/AllTags/Tag/TagKey.tsx @@ -12,7 +12,9 @@ function TagsKey(props: TagsKeysProps): JSX.Element { (state) => state.globalTime, ); - const [selectedKey, setSelectedKey] = useState(props.tag.Key[0] || ''); + const { index, setLocalSelectedTags, tag } = props; + + const [selectedKey, setSelectedKey] = useState(tag.Key[0] || ''); const traces = useSelector((state) => state.traces); @@ -77,14 +79,14 @@ function TagsKey(props: TagsKeysProps): JSX.Element { if (options && options.find((option) => option.value === value)) { setSelectedKey(value); - props.setLocalSelectedTags((tags) => [ - ...tags.slice(0, props.index), + setLocalSelectedTags((tags) => [ + ...tags.slice(0, index), { Key: [value], - Operator: props.tag.Operator, - Values: props.tag.Values, + Operator: tag.Operator, + Values: tag.Values, }, - ...tags.slice(props.index + 1, tags.length), + ...tags.slice(index + 1, tags.length), ]); } else { setSelectedKey(''); diff --git a/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx b/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx index 74bfca6906..e6ad17956f 100644 --- a/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx +++ b/frontend/src/container/Trace/Search/AllTags/Tag/index.tsx @@ -1,13 +1,8 @@ import { CloseOutlined } from '@ant-design/icons'; import { Select } from 'antd'; -import { SelectValue } from 'antd/lib/select'; import React from 'react'; -import { connect, useSelector } from 'react-redux'; -import { bindActionCreators } from 'redux'; -import { ThunkDispatch } from 'redux-thunk'; -import { UpdateSelectedTags } from 'store/actions/trace/updateTagsSelected'; +import { useSelector } from 'react-redux'; import { AppState } from 'store/reducers'; -import AppActions from 'types/actions'; import { TraceReducer } from 'types/reducer/trace'; import { @@ -22,7 +17,12 @@ const { Option } = Select; type Tags = FlatArray['Operator']; -const AllMenu: AllMenu[] = [ +interface AllMenuProps { + key: Tags | ''; + value: string; +} + +const AllMenu: AllMenuProps[] = [ { key: 'in', value: 'IN', @@ -33,41 +33,40 @@ const AllMenu: AllMenu[] = [ }, ]; -interface AllMenu { - key: Tags | ''; - value: string; -} - function SingleTags(props: AllTagsProps): JSX.Element { const traces = useSelector((state) => state.traces); + + const { tag, onCloseHandler, setLocalSelectedTags, index } = props; const { Key: selectedKey, Operator: selectedOperator, Values: selectedValues, - } = props.tag; + } = tag; const onDeleteTagHandler = (index: number): void => { - props.onCloseHandler(index); + onCloseHandler(index); }; - const onChangeOperatorHandler = (key: SelectValue): void => { - props.setLocalSelectedTags([ - ...traces.selectedTags.slice(0, props.index), - { - Key: selectedKey, - Values: selectedValues, - Operator: key as Tags, - }, - ...traces.selectedTags.slice(props.index + 1, traces.selectedTags.length), - ]); + const onChangeOperatorHandler = (key: unknown): void => { + if (typeof key === 'string') { + setLocalSelectedTags([ + ...traces.selectedTags.slice(0, index), + { + Key: selectedKey, + Values: selectedValues, + Operator: key as Tags, + }, + ...traces.selectedTags.slice(index + 1, traces.selectedTags.length), + ]); + } }; return ( { - props.setLocalSelectedTags((tags) => [ - ...tags.slice(0, props.index), + setLocalSelectedTags((tags) => [ + ...tags.slice(0, index), { Key: selectedKey, Operator: selectedOperator, Values: value as string[], }, - ...tags.slice(props.index + 1, tags.length), + ...tags.slice(index + 1, tags.length), ]); }} mode="tags" /> - onDeleteTagHandler(props.index)} - > + onDeleteTagHandler(index)}> ); } -interface DispatchProps { - updateSelectedTags: (props: TraceReducer['selectedTags']) => void; -} - -const mapDispatchToProps = ( - dispatch: ThunkDispatch, -): DispatchProps => ({ - updateSelectedTags: bindActionCreators(UpdateSelectedTags, dispatch), -}); - -interface AllTagsProps extends DispatchProps { +interface AllTagsProps { onCloseHandler: (index: number) => void; index: number; tag: FlatArray; @@ -126,4 +112,4 @@ interface AllTagsProps extends DispatchProps { >; } -export default connect(null, mapDispatchToProps)(SingleTags); +export default SingleTags; diff --git a/frontend/src/container/Trace/Search/util.ts b/frontend/src/container/Trace/Search/util.ts index 91e235b4a1..cda64d9b72 100644 --- a/frontend/src/container/Trace/Search/util.ts +++ b/frontend/src/container/Trace/Search/util.ts @@ -20,7 +20,9 @@ export const parseQueryToTags = (query: string): PayloadProps => { isError = true; } - const splitBy = isNotInPresent ? 'not in' : isInPresent ? 'in' : ''; + const isPresentSplit = isInPresent ? 'in' : ''; + + const splitBy = isNotInPresent ? 'not in' : isPresentSplit; if (splitBy.length === 0) { isError = true; diff --git a/frontend/src/container/Trace/TraceGraphFilter/index.tsx b/frontend/src/container/Trace/TraceGraphFilter/index.tsx index c7b97c6dc4..002fedee66 100644 --- a/frontend/src/container/Trace/TraceGraphFilter/index.tsx +++ b/frontend/src/container/Trace/TraceGraphFilter/index.tsx @@ -1,5 +1,4 @@ -import { SelectProps, Space } from 'antd'; -import { SelectValue } from 'antd/lib/select'; +import { Space } from 'antd'; import React from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Dispatch } from 'redux'; @@ -23,42 +22,43 @@ function TraceGraphFilter(): JSX.Element { >((state) => state.traces); const dispatch = useDispatch>(); - const onClickSelectedFunctionHandler: SelectProps['onChange'] = ( - ev, - ) => { - const selected = functions.find((e) => e.key === ev); - if (selected) { - dispatch({ - type: UPDATE_SELECTED_FUNCTION, - payload: { - selectedFunction: selected.key, - yAxisUnit: selected.yAxisUnit, - }, - }); + const onClickSelectedFunctionHandler = (ev: unknown): void => { + if (typeof ev === 'string') { + const selected = functions.find((e) => e.key === ev); + if (selected) { + dispatch({ + type: UPDATE_SELECTED_FUNCTION, + payload: { + selectedFunction: selected.key, + yAxisUnit: selected.yAxisUnit, + }, + }); + } } }; - const onClickSelectedGroupByHandler: SelectProps['onChange'] = ( - ev, - ) => { - const selected = groupBy.find((e) => e.key === ev); - if (selected) { - dispatch({ - type: UPDATE_SELECTED_GROUP_BY, - payload: { - selectedGroupBy: selected.key, - }, - }); + const onClickSelectedGroupByHandler = (ev: unknown): void => { + if (typeof ev === 'string') { + const selected = groupBy.find((e) => e.key === ev); + if (selected) { + dispatch({ + type: UPDATE_SELECTED_GROUP_BY, + payload: { + selectedGroupBy: selected.key, + }, + }); + } } }; return ( - + selectedFunction === e.key)?.displayValue} onChange={onClickSelectedFunctionHandler} > @@ -69,9 +69,10 @@ function TraceGraphFilter(): JSX.Element { ))} - + selectedGroupBy === e.key)?.displayValue} onChange={onClickSelectedGroupByHandler} diff --git a/frontend/src/container/Trace/TraceTable/index.tsx b/frontend/src/container/Trace/TraceTable/index.tsx index 8d7e19f6dd..944afddb45 100644 --- a/frontend/src/container/Trace/TraceTable/index.tsx +++ b/frontend/src/container/Trace/TraceTable/index.tsx @@ -39,6 +39,32 @@ function TraceTable({ getSpansAggregate }: TraceProps): JSX.Element { return `${ROUTES.TRACE}/${record.traceID}?spanId=${record.spanID}`; }; + const getValue = (value: string, record: TableType): JSX.Element => { + return ( + + {value} + + ); + }; + + const getHttpMethodOrStatus = ( + value: TableType['httpMethod'], + record: TableType, + ): JSX.Element => { + if (value.length === 0) { + return ( + + - + + ); + } + return ( + + {value} + + ); + }; + const columns: ColumnsType = [ { title: 'Date', @@ -58,25 +84,13 @@ function TraceTable({ getSpansAggregate }: TraceProps): JSX.Element { title: 'Service', dataIndex: 'serviceName', key: 'serviceName', - render: (value, record): JSX.Element => { - return ( - - {value} - - ); - }, + render: getValue, }, { title: 'Operation', dataIndex: 'operation', key: 'operation', - render: (value, record): JSX.Element => { - return ( - - {value} - - ); - }, + render: getValue, }, { title: 'Duration', @@ -96,39 +110,13 @@ function TraceTable({ getSpansAggregate }: TraceProps): JSX.Element { title: 'Method', dataIndex: 'httpMethod', key: 'httpMethod', - render: (value: TableType['httpMethod'], record): JSX.Element => { - if (value.length === 0) { - return ( - - - - - ); - } - return ( - - {value} - - ); - }, + render: getHttpMethodOrStatus, }, { title: 'Status Code', dataIndex: 'httpCode', key: 'httpCode', - render: (value: TableType['httpMethod'], record): JSX.Element => { - if (value.length === 0) { - return ( - - - - - ); - } - return ( - - {value} - - ); - }, + render: getHttpMethodOrStatus, }, ]; @@ -137,18 +125,19 @@ function TraceTable({ getSpansAggregate }: TraceProps): JSX.Element { _, sort, ) => { - const { order = 'ascend' } = sort; - - if (props.current && props.pageSize) { - getSpansAggregate({ - maxTime: globalTime.maxTime, - minTime: globalTime.minTime, - selectedFilter, - current: props.current, - pageSize: props.pageSize, - selectedTags, - order: order === 'ascend' ? 'ascending' : 'descending', - }); + if (!Array.isArray(sort)) { + const { order = 'ascend' } = sort; + if (props.current && props.pageSize) { + getSpansAggregate({ + maxTime: globalTime.maxTime, + minTime: globalTime.minTime, + selectedFilter, + current: props.current, + pageSize: props.pageSize, + selectedTags, + order: order === 'ascend' ? 'ascending' : 'descending', + }); + } } }; diff --git a/frontend/src/container/TraceDetail/SelectedSpanDetails/ErrorTag.tsx b/frontend/src/container/TraceDetail/SelectedSpanDetails/ErrorTag.tsx index d4e163cb93..d2c3cfb988 100644 --- a/frontend/src/container/TraceDetail/SelectedSpanDetails/ErrorTag.tsx +++ b/frontend/src/container/TraceDetail/SelectedSpanDetails/ErrorTag.tsx @@ -32,7 +32,6 @@ function ErrorTag({ event }: ErrorTagProps): JSX.Element { key={`${name}${JSON.stringify(attributeMap)}`} defaultActiveKey={[name || attributeMap.event]} expandIconPosition="right" - key={name} > ; + return
; } const { name, tags, serviceName } = tree; @@ -79,4 +79,8 @@ interface SelectedSpanDetailsProps { tree?: ITraceTree; } +SelectedSpanDetails.defaultProps = { + tree: undefined, +}; + export default SelectedSpanDetails; diff --git a/frontend/src/container/TraceDetail/SelectedSpanDetails/styles.ts b/frontend/src/container/TraceDetail/SelectedSpanDetails/styles.ts index 17a00d09f7..dc5bdc03e9 100644 --- a/frontend/src/container/TraceDetail/SelectedSpanDetails/styles.ts +++ b/frontend/src/container/TraceDetail/SelectedSpanDetails/styles.ts @@ -29,7 +29,7 @@ interface CustomSubTextProps { export const CustomSubText = styled(Paragraph)` &&& { - background: ${({ isDarkMode }) => (isDarkMode ? '#444' : '#ddd')}; + background: ${({ isDarkMode }): string => (isDarkMode ? '#444' : '#ddd')}; font-size: 12px; padding: 6px 8px; word-break: break-all; diff --git a/frontend/src/container/TraceDetail/index.tsx b/frontend/src/container/TraceDetail/index.tsx index b05cde4c4f..3207feee73 100644 --- a/frontend/src/container/TraceDetail/index.tsx +++ b/frontend/src/container/TraceDetail/index.tsx @@ -49,7 +49,10 @@ function TraceDetail({ response }: TraceDetailProps): JSX.Element { const { treeData: tree, ...traceMetaData } = useMemo(() => { const tree = getSortedData(treeData); - return getSpanTreeMetadata(tree, spanServiceColors); + // Note: Handle undefined + /*eslint-disable */ + return getSpanTreeMetadata(tree as ITraceTree, spanServiceColors); + /* eslint-enable */ }, [treeData, spanServiceColors]); const [globalTraceMetadata] = useState>({ @@ -73,7 +76,7 @@ function TraceDetail({ response }: TraceDetailProps): JSX.Element { // setSearchSpanString(value); // setTreeData(spanToTreeUtil(response[0].events)); // }; - const onFocusSelectedSpanHandler = () => { + const onFocusSelectedSpanHandler = (): void => { const treeNode = getNodeById(activeSelectedId, tree); if (treeNode) { setTreeData(treeNode); diff --git a/frontend/src/container/TraceDetail/utils.ts b/frontend/src/container/TraceDetail/utils.ts index dcad26dd6e..22cb741293 100644 --- a/frontend/src/container/TraceDetail/utils.ts +++ b/frontend/src/container/TraceDetail/utils.ts @@ -45,11 +45,13 @@ export const getSortedData = (treeData: ITraceTree): undefined | ITraceTree => { return; } + // need this rule to disable + // eslint-disable-next-line no-param-reassign treeNode.children = sortBy(treeNode.children, (e) => e.startTime); - for (const childNode of treeNode.children) { + treeNode.children.forEach((childNode) => { traverse(childNode, level + 1); - } + }); }; traverse(treeData, 1); diff --git a/frontend/src/container/TraceFlameGraph/index.tsx b/frontend/src/container/TraceFlameGraph/index.tsx index 8bdd657ff7..6490a4c435 100644 --- a/frontend/src/container/TraceFlameGraph/index.tsx +++ b/frontend/src/container/TraceFlameGraph/index.tsx @@ -1,4 +1,6 @@ +/* eslint-disable react/no-unstable-nested-components */ import Color from 'color'; +import { ITraceMetaData } from 'container/GantChart'; import { IIntervalUnit, resolveTimeFromInterval, @@ -14,7 +16,7 @@ import { TraceFlameGraphContainer, } from './styles'; -interface SpanItem { +interface SpanItemProps { topOffset: number; leftOffset: number; width: number; @@ -36,7 +38,7 @@ function SpanItem({ onSpanHover, hoveredSpanId, selectedSpanId, -}: SpanItem): JSX.Element { +}: SpanItemProps): JSX.Element { const { serviceColour } = spanData; const [isSelected, setIsSelected] = useState(false); // const [isLocalHover, setIsLocalHover] = useState(false); @@ -92,18 +94,20 @@ function SpanItem({ function TraceFlameGraph(props: { treeData: ITraceTree; traceMetaData: ITraceMetaData; - onSpanHover: SpanItem['onSpanHover']; - onSpanSelect: SpanItem['onSpanSelect']; + onSpanHover: SpanItemProps['onSpanHover']; + onSpanSelect: SpanItemProps['onSpanSelect']; hoveredSpanId: string; selectedSpanId: string; intervalUnit: IIntervalUnit; }): JSX.Element { - if (!props.treeData || props.treeData.id === 'empty' || !props.traceMetaData) { - return <>; - } - const { intervalUnit } = props; + const { treeData, traceMetaData, onSpanHover } = props; - const { globalStart, spread, levels } = props.traceMetaData; + if (!treeData || treeData.id === 'empty' || !traceMetaData) { + return
; + } + const { intervalUnit, onSpanSelect, hoveredSpanId, selectedSpanId } = props; + + const { globalStart, spread, levels } = traceMetaData; function RenderSpanRecursive({ level = 0, spanData, @@ -114,15 +118,15 @@ function TraceFlameGraph(props: { selectedSpanId, }: { spanData: ITraceTree; - level?: number; - parentLeftOffset?: number; - onSpanHover: SpanItem['onSpanHover']; - onSpanSelect: SpanItem['onSpanSelect']; + level: number; + parentLeftOffset: number; + onSpanHover: SpanItemProps['onSpanHover']; + onSpanSelect: SpanItemProps['onSpanSelect']; hoveredSpanId: string; selectedSpanId: string; }): JSX.Element { if (!spanData) { - return <>; + return
; } const leftOffset = ((spanData.startTime - globalStart) * 100) / spread; @@ -160,14 +164,15 @@ function TraceFlameGraph(props: { ); } + return ( ); diff --git a/frontend/src/container/TriggeredAlerts/Filter.tsx b/frontend/src/container/TriggeredAlerts/Filter.tsx index 701687f381..ae61fbc35a 100644 --- a/frontend/src/container/TriggeredAlerts/Filter.tsx +++ b/frontend/src/container/TriggeredAlerts/Filter.tsx @@ -1,3 +1,5 @@ +/* eslint-disable react/no-unstable-nested-components */ +import type { SelectProps } from 'antd'; import { Tag } from 'antd'; import React, { useCallback, useMemo } from 'react'; import { Alerts } from 'types/api/alerts/getAll'; @@ -12,23 +14,27 @@ function Filter({ selectedFilter, }: FilterProps): JSX.Element { const onChangeSelectGroupHandler = useCallback( - (value: string[]) => { - setSelectedGroup( - value.map((e) => ({ - value: e, - })), - ); + (value: unknown) => { + if (typeof value === 'object' && Array.isArray(value)) { + setSelectedGroup( + value.map((e) => ({ + value: e, + })), + ); + } }, [setSelectedGroup], ); const onChangeSelectedFilterHandler = useCallback( - (value: string[]) => { - setSelectedFilter( - value.map((e) => ({ - value: e, - })), - ); + (value: unknown) => { + if (typeof value === 'object' && Array.isArray(value)) { + setSelectedFilter( + value.map((e) => ({ + value: e, + })), + ); + } }, [setSelectedFilter], ); @@ -36,7 +42,7 @@ function Filter({ const uniqueLabels: Array = useMemo(() => { const allLabelsSet = new Set(); allAlerts.forEach((e) => - Object.keys(e.labels).map((e) => { + Object.keys(e.labels).forEach((e) => { allLabelsSet.add(e); }), ); @@ -47,6 +53,21 @@ function Filter({ value: e, })); + const getTags: SelectProps['tagRender'] = (props): JSX.Element => { + const { closable, onClose, label } = props; + + return ( + + {label} + + ); + }; + return ( e.value)} showArrow placeholder="Group by any tag" - tagRender={(props): JSX.Element => { - const { label, closable, onClose } = props; - return ( - - {label} - - ); - }} + tagRender={(props): JSX.Element => getTags(props)} options={options} /> diff --git a/frontend/src/container/TriggeredAlerts/FilteredTable/index.tsx b/frontend/src/container/TriggeredAlerts/FilteredTable/index.tsx index f4ba163bfd..e6e8c0e7f9 100644 --- a/frontend/src/container/TriggeredAlerts/FilteredTable/index.tsx +++ b/frontend/src/container/TriggeredAlerts/FilteredTable/index.tsx @@ -1,5 +1,5 @@ -import { Dictionary } from 'lodash'; -import groupBy from 'lodash/groupBy'; +import { Dictionary } from 'cypress/types/lodash'; +import groupBy from 'lodash-es/groupBy'; import React, { useMemo } from 'react'; import { Alerts } from 'types/api/alerts/getAll'; diff --git a/frontend/src/container/TriggeredAlerts/NoFilterTable.tsx b/frontend/src/container/TriggeredAlerts/NoFilterTable.tsx index 5579ab86a1..9d5183e5e8 100644 --- a/frontend/src/container/TriggeredAlerts/NoFilterTable.tsx +++ b/frontend/src/container/TriggeredAlerts/NoFilterTable.tsx @@ -31,7 +31,7 @@ function NoFilterTable({ dataIndex: 'labels', key: 'alertName', sorter: (a, b): number => - a.labels?.alertname?.length - b.labels?.alertname?.length, + (a.labels?.alertname?.length || 0) - (b.labels?.alertname?.length || 0), render: (data): JSX.Element => { const name = data?.alertname || ''; return {name}; diff --git a/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx b/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx index f68a2ece74..df3b6ff012 100644 --- a/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx +++ b/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx @@ -54,7 +54,7 @@ function TriggeredAlerts({ allAlerts }: TriggeredAlertsProps): JSX.Element { /> ) : ( - <> +
{selectedFilter.length !== 0 && selectedGroup.length === 0 ? ( )} - +
)}
); diff --git a/frontend/src/lib/JSXtoHTML.ts b/frontend/src/lib/JSXtoHTML.ts index 48a758d085..bdd2207354 100644 --- a/frontend/src/lib/JSXtoHTML.ts +++ b/frontend/src/lib/JSXtoHTML.ts @@ -1,9 +1,9 @@ import { renderToString } from 'react-dom/server'; -const JSXtoHTML = function (str: JSX.Element): HTMLElement { +function JSXtoHTML(str: JSX.Element): HTMLElement { const parser = new DOMParser(); const doc = parser.parseFromString(renderToString(str), 'text/html'); return doc.body.firstChild as HTMLElement; -}; +} export default JSXtoHTML; diff --git a/frontend/src/lib/getStartAndEndTime/getMicroSeconds.ts b/frontend/src/lib/getStartAndEndTime/getMicroSeconds.ts index 584ab40dae..8593ffb7de 100644 --- a/frontend/src/lib/getStartAndEndTime/getMicroSeconds.ts +++ b/frontend/src/lib/getStartAndEndTime/getMicroSeconds.ts @@ -1,8 +1,8 @@ -const getMicroSeconds = ({ time }: getMicroSecondsProps): string => { +const getMicroSeconds = ({ time }: GetMicroSecondsProps): string => { return (time / 1000).toString(); }; -interface getMicroSecondsProps { +interface GetMicroSecondsProps { time: number; } diff --git a/frontend/src/lib/getStartAndEndTime/getMinAgo.ts b/frontend/src/lib/getStartAndEndTime/getMinAgo.ts index dcae1c0cf7..d58da001d0 100644 --- a/frontend/src/lib/getStartAndEndTime/getMinAgo.ts +++ b/frontend/src/lib/getStartAndEndTime/getMinAgo.ts @@ -1,10 +1,10 @@ -const getMinAgo = ({ minutes }: getMinAgoProps): Date => { +const getMinAgo = ({ minutes }: GetMinAgoProps): Date => { const currentDate = new Date(); return new Date(currentDate.getTime() - minutes * 60000); }; -interface getMinAgoProps { +interface GetMinAgoProps { minutes: number; } diff --git a/frontend/src/lib/getStep.ts b/frontend/src/lib/getStep.ts index c0ba74950b..c7388bbe06 100644 --- a/frontend/src/lib/getStep.ts +++ b/frontend/src/lib/getStep.ts @@ -23,6 +23,9 @@ const convertToMs = ( return timestamp * 1; case 'ns': return timestamp / 1e6; + default: { + throw new Error('invalid format'); + } } }; diff --git a/frontend/src/lib/theme/getTheme.ts b/frontend/src/lib/theme/getTheme.ts index e9e72f2b51..24750e0616 100644 --- a/frontend/src/lib/theme/getTheme.ts +++ b/frontend/src/lib/theme/getTheme.ts @@ -1,6 +1,8 @@ import getLocalStorageKey from 'api/browser/localstorage/get'; -const getTheme = (): appMode => { +import { AppMode } from './setTheme'; + +const getTheme = (): AppMode => { const userTheme = getLocalStorageKey('theme'); if (userTheme === null || userTheme === 'darkMode') { return 'darkMode'; @@ -9,6 +11,4 @@ const getTheme = (): appMode => { return 'lightMode'; }; -type appMode = 'darkMode' | 'lightMode'; - export default getTheme; diff --git a/frontend/src/lib/theme/setTheme.ts b/frontend/src/lib/theme/setTheme.ts index e46790ad3f..26a4910de9 100644 --- a/frontend/src/lib/theme/setTheme.ts +++ b/frontend/src/lib/theme/setTheme.ts @@ -1,9 +1,9 @@ import setLocalStorageKey from 'api/browser/localstorage/set'; -const setTheme = (value: appMode): void => { +const setTheme = (value: AppMode): void => { setLocalStorageKey('theme', value); }; -type appMode = 'darkMode' | 'lightMode'; +export type AppMode = 'darkMode' | 'lightMode'; export default setTheme; diff --git a/frontend/src/modules/Servicemap/SelectService.tsx b/frontend/src/modules/Servicemap/SelectService.tsx index 69b389ddea..30f5c2ce09 100644 --- a/frontend/src/modules/Servicemap/SelectService.tsx +++ b/frontend/src/modules/Servicemap/SelectService.tsx @@ -1,8 +1,11 @@ +/* eslint-disable */ +//@ts-nocheck + import { InfoCircleOutlined } from '@ant-design/icons'; import { Select } from 'antd'; import { cloneDeep } from 'lodash-es'; import React, { useState } from 'react'; -import { servicesItem } from 'store/actions'; +import { ServicesItem } from 'store/actions'; import styled from 'styled-components'; const { Option } = Select; @@ -25,7 +28,7 @@ const Container = styled.div` `; interface SelectServiceProps { - services: servicesItem[]; + services: ServicesItem[]; zoomToService: (arg0: string) => void; zoomToDefault: () => void; } @@ -38,9 +41,9 @@ function SelectService(props: SelectServiceProps): JSX.Element { const [selectedVal, setSelectedVal] = useState( defaultOption.serviceName, ); - const { zoomToService, zoomToDefault } = props; - const services = cloneDeep(props.services); - services.unshift(defaultOption); + const { zoomToService, zoomToDefault, services } = props; + const service = cloneDeep(services); + service.unshift(defaultOption); const handleSelect = (value: string): void => { if (value === defaultOption.serviceName) { @@ -58,7 +61,7 @@ function SelectService(props: SelectServiceProps): JSX.Element { onChange={handleSelect} value={selectedVal} > - {services.map(({ serviceName }) => ( + {service.map(({ serviceName }) => ( diff --git a/frontend/src/modules/Servicemap/ServiceMap.tsx b/frontend/src/modules/Servicemap/ServiceMap.tsx index cd40b3a9f5..9d07892fa5 100644 --- a/frontend/src/modules/Servicemap/ServiceMap.tsx +++ b/frontend/src/modules/Servicemap/ServiceMap.tsx @@ -1,13 +1,12 @@ +/* eslint-disable */ +//@ts-nocheck + import Spinner from 'components/Spinner'; import React, { useEffect, useRef } from 'react'; import { ForceGraph2D } from 'react-force-graph'; import { connect } from 'react-redux'; import { RouteComponentProps, withRouter } from 'react-router-dom'; -import { - getDetailedServiceMapItems, - getServiceMapItems, - serviceMapStore, -} from 'store/actions'; +import { getDetailedServiceMapItems, getServiceMapItems } from 'store/actions'; import { AppState } from 'store/reducers'; import styled from 'styled-components'; import { GlobalTime } from 'types/actions/globalTime'; diff --git a/frontend/src/modules/Servicemap/index.ts b/frontend/src/modules/Servicemap/index.ts index 72b3a591d5..d654a54383 100644 --- a/frontend/src/modules/Servicemap/index.ts +++ b/frontend/src/modules/Servicemap/index.ts @@ -1 +1,3 @@ -export { default } from './ServiceMap'; +import ServiceMap from './ServiceMap'; + +export default ServiceMap; diff --git a/frontend/src/modules/Servicemap/utils.ts b/frontend/src/modules/Servicemap/utils.ts index d26e46c123..de94109d61 100644 --- a/frontend/src/modules/Servicemap/utils.ts +++ b/frontend/src/modules/Servicemap/utils.ts @@ -1,5 +1,7 @@ +/*eslint-disable*/ +//@ts-nocheck + import { cloneDeep, find, maxBy, uniq, uniqBy } from 'lodash-es'; -import { serviceMapStore } from 'store/actions'; import { graphDataType } from './ServiceMap'; @@ -16,7 +18,7 @@ export const getDimensions = (num, highest) => { }; }; -export const getGraphData = (serviceMap: serviceMapStore): graphDataType => { +export const getGraphData = (serviceMap): graphDataType => { const { items, services } = serviceMap; const highestCallCount = maxBy(items, (e) => e.callCount).callCount; const highestCallRate = maxBy(services, (e) => e.callRate).callRate; diff --git a/frontend/src/modules/Usage/UsageExplorer.tsx b/frontend/src/modules/Usage/UsageExplorer.tsx index f52924bea0..1790343210 100644 --- a/frontend/src/modules/Usage/UsageExplorer.tsx +++ b/frontend/src/modules/Usage/UsageExplorer.tsx @@ -1,9 +1,11 @@ +/* eslint-disable */ +//@ts-nocheck + import { Select, Space } from 'antd'; import Graph from 'components/Graph'; import React, { useEffect, useState } from 'react'; import { connect, useSelector } from 'react-redux'; -import { GetService, getUsageData, usageDataItem } from 'store/actions'; -import { servicesListItem } from 'store/actions/MetricsActions'; +import { GetService, getUsageData, UsageDataItem } from 'store/actions'; import { AppState } from 'store/reducers'; import { GlobalTime } from 'types/actions/globalTime'; import { GlobalReducer } from 'types/reducer/globalTime'; @@ -15,7 +17,7 @@ import { Card } from './styles'; const { Option } = Select; interface UsageExplorerProps { - usageData: usageDataItem[]; + usageData: UsageDataItem[]; getUsageData: ( minTime: number, maxTime: number, @@ -198,7 +200,7 @@ const mapStateToProps = ( ): { totalCount: number; globalTime: GlobalTime; - usageData: usageDataItem[]; + usageData: UsageDataItem[]; } => { let totalCount = 0; for (const item of state.usageDate) { diff --git a/frontend/src/modules/Usage/UsageExplorerDef.tsx b/frontend/src/modules/Usage/UsageExplorerDef.tsx index 9454b7c3dd..0837e30033 100644 --- a/frontend/src/modules/Usage/UsageExplorerDef.tsx +++ b/frontend/src/modules/Usage/UsageExplorerDef.tsx @@ -1 +1,3 @@ -export { UsageExplorer as default } from './UsageExplorer'; +import { UsageExplorer } from './UsageExplorer'; + +export default UsageExplorer; diff --git a/frontend/src/pages/AlertChannelCreate/index.tsx b/frontend/src/pages/AlertChannelCreate/index.tsx index bcdc83a798..49032941f2 100644 --- a/frontend/src/pages/AlertChannelCreate/index.tsx +++ b/frontend/src/pages/AlertChannelCreate/index.tsx @@ -1,3 +1,4 @@ +/* eslint-disable react/no-unstable-nested-components */ import RouteTab from 'components/RouteTab'; import ROUTES from 'constants/routes'; import CreateAlertChannels from 'container/CreateAlertChannels'; diff --git a/frontend/src/pages/ChannelsEdit/index.tsx b/frontend/src/pages/ChannelsEdit/index.tsx index 4a6630f21a..60500cc04e 100644 --- a/frontend/src/pages/ChannelsEdit/index.tsx +++ b/frontend/src/pages/ChannelsEdit/index.tsx @@ -5,7 +5,7 @@ import { SlackChannel } from 'container/CreateAlertChannels/config'; import EditAlertChannels from 'container/EditAlertChannels'; import useFetch from 'hooks/useFetch'; import React from 'react'; -import { useParams } from 'react-router'; +import { useParams } from 'react-router-dom'; import { PayloadProps, Props } from 'types/api/channels/get'; function ChannelsEdit(): JSX.Element { diff --git a/frontend/src/pages/DashboardWidget/index.tsx b/frontend/src/pages/DashboardWidget/index.tsx index 216e020c55..e4eedd4b24 100644 --- a/frontend/src/pages/DashboardWidget/index.tsx +++ b/frontend/src/pages/DashboardWidget/index.tsx @@ -3,6 +3,7 @@ import Spinner from 'components/Spinner'; import ROUTES from 'constants/routes'; import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider'; import NewWidget from 'container/NewWidget'; +import history from 'lib/history'; import React, { useEffect, useRef, useState } from 'react'; import { connect, useSelector } from 'react-redux'; import { generatePath, useLocation, useParams } from 'react-router-dom'; @@ -12,7 +13,6 @@ import { GetDashboard, GetDashboardProps } from 'store/actions'; import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import DashboardReducer from 'types/reducer/dashboards'; -import history from 'lib/history'; function DashboardWidget({ getDashboard }: NewDashboardProps): JSX.Element { const { search } = useLocation(); diff --git a/frontend/src/pages/EditRules/index.tsx b/frontend/src/pages/EditRules/index.tsx index d6d27c6e33..30cdbd312e 100644 --- a/frontend/src/pages/EditRules/index.tsx +++ b/frontend/src/pages/EditRules/index.tsx @@ -3,7 +3,7 @@ import Spinner from 'components/Spinner'; import EditRulesContainer from 'container/EditRules'; import useFetch from 'hooks/useFetch'; import React from 'react'; -import { useParams } from 'react-router'; +import { useParams } from 'react-router-dom'; import { PayloadProps, Props } from 'types/api/alerts/get'; function EditRules(): JSX.Element { @@ -13,7 +13,7 @@ function EditRules(): JSX.Element { PayloadProps, Props >(get, { - id: parseInt(ruleId), + id: parseInt(ruleId, 10), }); if (error) { diff --git a/frontend/src/pages/Trace/index.tsx b/frontend/src/pages/Trace/index.tsx index b34145ab24..acdc32aeb1 100644 --- a/frontend/src/pages/Trace/index.tsx +++ b/frontend/src/pages/Trace/index.tsx @@ -63,8 +63,17 @@ function Trace({ current: spansAggregate.currentPage, pageSize: spansAggregate.pageSize, selectedTags, + order: 'ascending', }); - }, [selectedTags, selectedFilter, maxTime, minTime]); + }, [ + selectedTags, + selectedFilter, + maxTime, + minTime, + getSpansAggregate, + spansAggregate.currentPage, + spansAggregate.pageSize, + ]); useEffect(() => { getSpans({ @@ -84,28 +93,33 @@ function Trace({ selectedTags, maxTime, minTime, + isFilterExclude, + getSpans, ]); useEffect(() => { - return () => { + return (): void => { dispatch({ type: RESET_TRACE_FILTER, }); }; - }, []); + }, [dispatch]); - const onClickHandler = useCallback((e) => { - e.preventDefault(); - e.stopPropagation(); + const onClickHandler = useCallback( + (e) => { + e.preventDefault(); + e.stopPropagation(); - history.replace(ROUTES.TRACE); + history.replace(ROUTES.TRACE); - dispatch({ - type: RESET_TRACE_FILTER, - }); + dispatch({ + type: RESET_TRACE_FILTER, + }); - setIsChanged((state) => !state); - }, []); + setIsChanged((state) => !state); + }, + [dispatch], + ); return ( <> diff --git a/frontend/src/store/actions/MetricsActions/index.ts b/frontend/src/store/actions/MetricsActions/index.ts deleted file mode 100644 index 20e63772a2..0000000000 --- a/frontend/src/store/actions/MetricsActions/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './metricsActions'; -export * from './metricsActionTypes'; -export * from './metricsInterfaces'; diff --git a/frontend/src/store/actions/MetricsActions/metricsActionTypes.ts b/frontend/src/store/actions/MetricsActions/metricsActionTypes.ts deleted file mode 100644 index 371b881874..0000000000 --- a/frontend/src/store/actions/MetricsActions/metricsActionTypes.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { - externalErrCodeMetricsActions, - externalMetricsAvgDurationAction, - getDbOverViewMetricsAction, - getExternalMetricsAction, - getFilteredTraceMetricsAction, - getServiceMetricsAction, - getServicesListAction, - getTopEndpointsAction, -} from './metricsInterfaces'; - -export enum MetricsActionTypes { - updateInput = 'UPDATE_INPUT', - getServicesList = 'GET_SERVICE_LIST', - getServiceMetrics = 'GET_SERVICE_METRICS', - getAvgDurationMetrics = 'GET_AVG_DURATION_METRICS', - getErrCodeMetrics = 'GET_ERR_CODE_METRICS', - getDbOverviewMetrics = 'GET_DB_OVERVIEW_METRICS', - getExternalMetrics = 'GET_EXTERNAL_METRICS', - getTopEndpoints = 'GET_TOP_ENDPOINTS', - getFilteredTraceMetrics = 'GET_FILTERED_TRACE_METRICS', -} - -export type MetricsActions = - | getServicesListAction - | getServiceMetricsAction - | getTopEndpointsAction - | getFilteredTraceMetricsAction - | getExternalMetricsAction - | externalErrCodeMetricsActions - | getDbOverViewMetricsAction - | externalMetricsAvgDurationAction; diff --git a/frontend/src/store/actions/MetricsActions/metricsActions.ts b/frontend/src/store/actions/MetricsActions/metricsActions.ts deleted file mode 100644 index f6968f8e15..0000000000 --- a/frontend/src/store/actions/MetricsActions/metricsActions.ts +++ /dev/null @@ -1,204 +0,0 @@ -import api from 'api'; -import { Dispatch } from 'redux'; -import { GlobalTime } from 'types/actions/globalTime'; -import { toUTCEpoch } from 'utils/timeUtils'; - -import { MetricsActionTypes } from './metricsActionTypes'; -import * as MetricsInterfaces from './metricsInterfaces'; - -export const getServicesList = (globalTime: GlobalTime) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/services?start=${globalTime.minTime}&end=${globalTime.maxTime}`; - - const response = await api.get( - request_string, - ); - - dispatch({ - type: MetricsActionTypes.getServicesList, - payload: response.data, - }); - }; -}; - -export const getDbOverViewMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/service/dbOverview?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - const response = await api.get( - request_string, - ); - dispatch({ - type: MetricsActionTypes.getDbOverviewMetrics, - payload: response.data, - }); - }; -}; - -export const getExternalMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/service/external?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - const response = await api.get( - request_string, - ); - dispatch({ - type: MetricsActionTypes.getExternalMetrics, - payload: response.data, - }); - }; -}; - -export const getExternalAvgDurationMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/service/externalAvgDuration?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - - const response = await api.get< - MetricsInterfaces.externalMetricsAvgDurationItem[] - >(request_string); - dispatch({ - type: MetricsActionTypes.getAvgDurationMetrics, - payload: response.data, - }); - }; -}; -export const getExternalErrCodeMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/service/externalErrors?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - const response = await api.get< - MetricsInterfaces.externalErrCodeMetricsItem[] - >(request_string); - - dispatch({ - type: MetricsActionTypes.getErrCodeMetrics, - payload: response.data, - }); - }; -}; - -export const getServicesMetrics = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/service/overview?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - const response = await api.get( - request_string, - ); - - dispatch({ - type: MetricsActionTypes.getServiceMetrics, - payload: response.data, - }); - }; -}; - -export const getTopEndpoints = ( - serviceName: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/service/top_endpoints?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}`; - const response = await api.get( - request_string, - ); - - dispatch({ - type: MetricsActionTypes.getTopEndpoints, - payload: response.data, - }); - }; -}; - -export const getFilteredTraceMetrics = ( - filter_params: string, - globalTime: GlobalTime, -) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `/spans/aggregates?start=${toUTCEpoch( - globalTime.minTime, - )}&end=${toUTCEpoch(globalTime.maxTime)}&${filter_params}`; - const response = await api.get( - request_string, - ); - - dispatch({ - type: MetricsActionTypes.getFilteredTraceMetrics, - payload: response.data, - }); - }; -}; - -export const getInitialMerticData = ({ - serviceName, - globalTime, -}: getInitialMerticDataProps) => { - return async (dispatch: Dispatch): Promise => { - try { - const dbOverviewString = `/service/dbOverview?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - - const externalServicesString = `/service/external?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - - const topEndPointsString = `/service/top_endpoints?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}`; - - const avgExternalDurationString = `/service/externalAvgDuration?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - - const serviceOverviewString = `/service/overview?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - - const externalErrorCodeMetricsString = `/service/externalErrors?service=${serviceName}&start=${globalTime.minTime}&end=${globalTime.maxTime}&step=60`; - - dispatch({ - type: 'UPDATE_INITIAL_VALUE_START', - }); - - const [ - dbResponse, - externalServiceResponse, - topEndPointsResponse, - avgExternalDurationResponse, - serviceOverViewResponse, - externalErrorCodeMetricsResponse, - ] = await Promise.all([ - api.get(dbOverviewString), - api.get(externalServicesString), - api.get(topEndPointsString), - api.get( - avgExternalDurationString, - ), - api.get(serviceOverviewString), - api.get( - externalErrorCodeMetricsString, - ), - ]); - - dispatch({ - type: 'UPDATE_INITIAL_VALUE', - payload: { - serviceOverViewResponse: serviceOverViewResponse.data, - topEndPointsResponse: topEndPointsResponse.data, - dbResponse: dbResponse.data, - externalServiceResponse: externalServiceResponse.data, - avgExternalDurationResponse: avgExternalDurationResponse.data, - externalErrorCodeMetricsResponse: externalErrorCodeMetricsResponse.data, - }, - }); - } catch (error) { - console.error(error); - } - }; -}; - -export interface getInitialMerticDataProps { - serviceName: string; - globalTime: GlobalTime; -} diff --git a/frontend/src/store/actions/MetricsActions/metricsInterfaces.ts b/frontend/src/store/actions/MetricsActions/metricsInterfaces.ts deleted file mode 100644 index 77451484d2..0000000000 --- a/frontend/src/store/actions/MetricsActions/metricsInterfaces.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { MetricsActionTypes } from './metricsActionTypes'; - -export interface servicesListItem { - serviceName: string; - p99: number; - avgDuration: number; - numCalls: number; - callRate: number; - numErrors: number; - errorRate: number; -} - -export interface metricItem { - timestamp: number; - p50: number; - p95: number; - p99: number; - numCalls: number; - callRate: number; - numErrors: number; - errorRate: number; -} - -export interface externalMetricsAvgDurationItem { - avgDuration: number; - timestamp: number; -} - -export interface externalErrCodeMetricsItem { - externalHttpUrl: string; - numCalls: number; - timestamp: number; - callRate: number; -} -export interface topEndpointListItem { - p50: number; - p95: number; - p99: number; - numCalls: number; - name: string; -} - -export interface externalMetricsItem { - avgDuration: number; - callRate: number; - externalHttpUrl: string; - numCalls: number; - timestamp: number; -} - -export interface dbOverviewMetricsItem { - avgDuration: number; - callRate: number; - dbSystem: string; - numCalls: number; - timestamp: number; -} - -export interface customMetricsItem { - timestamp: number; - value: number; -} - -export interface getServicesListAction { - type: MetricsActionTypes.getServicesList; - payload: servicesListItem[]; -} - -export interface externalErrCodeMetricsActions { - type: MetricsActionTypes.getErrCodeMetrics; - payload: externalErrCodeMetricsItem[]; -} -export interface externalMetricsAvgDurationAction { - type: MetricsActionTypes.getAvgDurationMetrics; - payload: externalMetricsAvgDurationItem[]; -} -export interface getServiceMetricsAction { - type: MetricsActionTypes.getServiceMetrics; - payload: metricItem[]; -} -export interface getExternalMetricsAction { - type: MetricsActionTypes.getExternalMetrics; - payload: externalMetricsItem[]; -} - -export interface getDbOverViewMetricsAction { - type: MetricsActionTypes.getDbOverviewMetrics; - payload: dbOverviewMetricsItem[]; -} -export interface getTopEndpointsAction { - type: MetricsActionTypes.getTopEndpoints; - payload: topEndpointListItem[]; -} - -export interface getFilteredTraceMetricsAction { - type: MetricsActionTypes.getFilteredTraceMetrics; - payload: customMetricsItem[]; -} diff --git a/frontend/src/store/actions/index.ts b/frontend/src/store/actions/index.ts index 403f685057..7281693e13 100644 --- a/frontend/src/store/actions/index.ts +++ b/frontend/src/store/actions/index.ts @@ -2,8 +2,6 @@ export * from './app'; export * from './dashboard'; export * from './global'; export * from './metrics'; -export * from './MetricsActions'; export * from './serviceMap'; -export * from './traces'; export * from './types'; export * from './usage'; diff --git a/frontend/src/store/actions/serviceMap.ts b/frontend/src/store/actions/serviceMap.ts index 5a2185d074..be5a84a239 100644 --- a/frontend/src/store/actions/serviceMap.ts +++ b/frontend/src/store/actions/serviceMap.ts @@ -4,12 +4,12 @@ import { GlobalTime } from 'types/actions/globalTime'; import { ActionTypes } from './types'; -export interface serviceMapStore { - items: servicesMapItem[]; - services: servicesItem[]; +export interface ServiceMapStore { + items: ServicesMapItem[]; + services: ServicesItem[]; } -export interface servicesItem { +export interface ServicesItem { serviceName: string; p99: number; avgDuration: number; @@ -21,34 +21,34 @@ export interface servicesItem { fourXXRate: number; } -export interface servicesMapItem { +export interface ServicesMapItem { parent: string; child: string; callCount: number; } -export interface serviceMapItemAction { +export interface ServiceMapItemAction { type: ActionTypes.getServiceMapItems; - payload: servicesMapItem[]; + payload: ServicesMapItem[]; } -export interface servicesAction { +export interface ServicesAction { type: ActionTypes.getServices; - payload: servicesItem[]; + payload: ServicesItem[]; } export const getServiceMapItems = (globalTime: GlobalTime) => { return async (dispatch: Dispatch): Promise => { - dispatch({ + dispatch({ type: ActionTypes.getServiceMapItems, payload: [], }); - const request_string = `/serviceMapDependencies?start=${globalTime.minTime}&end=${globalTime.maxTime}`; + const requestString = `/serviceMapDependencies?start=${globalTime.minTime}&end=${globalTime.maxTime}`; - const response = await api.get(request_string); + const response = await api.get(requestString); - dispatch({ + dispatch({ type: ActionTypes.getServiceMapItems, payload: response.data, }); @@ -57,16 +57,16 @@ export const getServiceMapItems = (globalTime: GlobalTime) => { export const getDetailedServiceMapItems = (globalTime: GlobalTime) => { return async (dispatch: Dispatch): Promise => { - dispatch({ + dispatch({ type: ActionTypes.getServices, payload: [], }); - const request_string = `/services?start=${globalTime.minTime}&end=${globalTime.maxTime}`; + const requestString = `/services?start=${globalTime.minTime}&end=${globalTime.maxTime}`; - const response = await api.get(request_string); + const response = await api.get(requestString); - dispatch({ + dispatch({ type: ActionTypes.getServices, payload: response.data, }); diff --git a/frontend/src/store/actions/trace/getInitialFilter.ts b/frontend/src/store/actions/trace/getInitialFilter.ts index 7954b0f1ba..ab0a49f79e 100644 --- a/frontend/src/store/actions/trace/getInitialFilter.ts +++ b/frontend/src/store/actions/trace/getInitialFilter.ts @@ -29,9 +29,10 @@ export const GetInitialTraceFilter = ( dispatch: Dispatch, getState: Store['getState'], ) => void) => { + // eslint-disable-next-line sonarjs/cognitive-complexity return async (dispatch, getState): Promise => { try { - const query = location.search; + const query = window.location.search; const { traces, globalTime } = getState(); @@ -100,12 +101,12 @@ export const GetInitialTraceFilter = ( ? traces.filterToFetchData : xor(traces.filterToFetchData, getFilterToFetchData.currentValue); - Object.keys(response.payload).map((key) => { + Object.keys(response.payload).forEach((key) => { const value = response.payload[key]; Object.keys(value) // remove maxDuration and minDuration filter from initial selection logic .filter((e) => !['maxDuration', 'minDuration'].includes(e)) - .map((preKey) => { + .forEach((preKey) => { if (isTraceFilterEnum(key) && diff.find((v) => v === key)) { // const preValue = preSelectedFilter?.get(key) || []; const preValue = getUserSelected.currentValue?.get(key) || []; diff --git a/frontend/src/store/actions/trace/getSpans.ts b/frontend/src/store/actions/trace/getSpans.ts index 1f323206bb..d907cde7c7 100644 --- a/frontend/src/store/actions/trace/getSpans.ts +++ b/frontend/src/store/actions/trace/getSpans.ts @@ -16,6 +16,8 @@ export const GetSpans = ( dispatch: Dispatch, getState: Store['getState'], ) => void) => { + const defaultMessage = 'Something went wrong'; + return async (dispatch, getState): Promise => { try { const { traces, globalTime } = getState(); @@ -71,13 +73,13 @@ export const GetSpans = ( }); } else { notification.error({ - message: response.error || 'Something went wrong', + message: response.error || defaultMessage, }); dispatch({ type: UPDATE_TRACE_GRAPH_ERROR, payload: { error: true, - errorMessage: response.error || 'Something went wrong', + errorMessage: response.error || defaultMessage, }, }); } @@ -86,7 +88,7 @@ export const GetSpans = ( type: UPDATE_TRACE_GRAPH_ERROR, payload: { error: true, - errorMessage: (error as Error)?.toString() || 'Something went wrong', + errorMessage: (error as Error)?.toString() || defaultMessage, }, }); } diff --git a/frontend/src/store/actions/trace/parseFilter/minMaxTime.ts b/frontend/src/store/actions/trace/parseFilter/minMaxTime.ts index 9953fb18c6..aa763089e6 100644 --- a/frontend/src/store/actions/trace/parseFilter/minMaxTime.ts +++ b/frontend/src/store/actions/trace/parseFilter/minMaxTime.ts @@ -9,8 +9,8 @@ export const parseMinMaxTime = (query: string): GlobalTime => { const urlMinTime = url.get('maxTime'); if (urlMaxTime && urlMinTime) { - maxTime = parseInt(urlMaxTime); - minTime = parseInt(urlMinTime); + maxTime = parseInt(urlMaxTime, 10); + minTime = parseInt(urlMinTime, 10); } return { diff --git a/frontend/src/store/actions/trace/util.ts b/frontend/src/store/actions/trace/util.ts index f89d8e7525..63d91216f7 100644 --- a/frontend/src/store/actions/trace/util.ts +++ b/frontend/src/store/actions/trace/util.ts @@ -24,7 +24,7 @@ export const updateURL = ( isFilterExclude: TraceReducer['isFilterExclude'], userSelectedFilter: TraceReducer['userSelectedFilter'], ): void => { - const search = new URLSearchParams(location.search); + const search = new URLSearchParams(window.location.search); const preResult: { key: string; value: string }[] = []; const keyToSkip = [ diff --git a/frontend/src/store/actions/traces.ts b/frontend/src/store/actions/traces.ts deleted file mode 100644 index 0c4f3c24a0..0000000000 --- a/frontend/src/store/actions/traces.ts +++ /dev/null @@ -1,153 +0,0 @@ -import api from 'api'; -import { Dispatch } from 'redux'; -import { GlobalTime } from 'types/actions/globalTime'; -import { toUTCEpoch } from 'utils/timeUtils'; - -import { ActionTypes } from './types'; - -// PNOTE -// define trace interface - what it should return -// define action creator to show list of traces on component mount -- use useEffect ( , []) -> Mounts when loaded first time -// Date() - takes number of milliseconds as input, our API takes in microseconds -// Sample API call for traces - https://api.signoz.io/api/traces?end=1606968273667000&limit=20&lookback=2d&maxDuration=&minDuration=&service=driver&operation=&start=1606968100867000 - -export interface Tree { - name: string; - value: number; - children?: Tree[]; -} - -export interface RefItem { - refType: string; - traceID: string; - spanID: string; -} - -export interface TraceTagItem { - key: string; - // type: string; - value: string; -} - -export interface ProcessItem { - serviceName: string; - tags: TraceTagItem[]; -} - -// PNOTE - Temp DS for converting span to tree which can be consumed by flamegraph -export interface pushDStree { - id: string; - name: string; - value: number; - time: number; - startTime: number; - tags: TraceTagItem[]; - children: pushDStree[]; - parent: pushDStree; - serviceName: string; - serviceColour: string; - hasError: boolean; -} - -export interface spanItem { - traceID: string; // index 0 - spanID: string; // index 1 - operationName: string; // index 2 - startTime: number; // index 3 - duration: number; // index 4 - references: RefItem[]; // index 5 - tags: []; // index 6 - logs: []; // index 7 - processID: string; // index 8 - warnings: []; // index 9 - children: pushDStree[]; // index 10 // PNOTE - added this as we are adding extra field in span item to convert trace to tree. - // Should this field be optional? -} - -// let mapped_array :{ [id: string] : spanItem; } = {}; - -export interface traceItem { - traceID: string; - spans: spanItem[]; - processes: { [id: string]: ProcessItem }; - warnings: []; -} - -export interface traceResponse { - data: traceItem[]; - total: number; - limit: number; - offset: number; - error: []; -} - -export type span = [ - number, - string, - string, - string, - string, - string, - string, - string | string[], - string | string[], - string | string[], - pushDStree[], -]; - -export interface spanList { - events: span[]; - segmentID: string; - columns: string[]; -} - -// export interface traceResponseNew{ -// [id: string] : spanList; -// } -export interface traceResponseNew { - [id: string]: spanList; -} - -export interface spansWSameTraceIDResponse { - [id: string]: spanList; -} - -export interface FetchTracesAction { - type: ActionTypes.fetchTraces; - payload: traceResponseNew; -} - -export interface FetchTraceItemAction { - type: ActionTypes.fetchTraceItem; - payload: spansWSameTraceIDResponse; -} - -export const fetchTraces = (globalTime: GlobalTime, filter_params: string) => { - return async (dispatch: Dispatch): Promise => { - if (globalTime) { - const request_string = `/spans?limit=100&lookback=2d&start=${toUTCEpoch( - globalTime.minTime, - )}&end=${toUTCEpoch(globalTime.maxTime)}&${filter_params}`; - const response = await api.get(request_string); - - dispatch({ - type: ActionTypes.fetchTraces, - payload: response.data, - // PNOTE - response.data in the axios response has the actual API response? - }); - } - }; -}; - -export const fetchTraceItem = (traceID: string) => { - return async (dispatch: Dispatch): Promise => { - const request_string = `${'/traces' + '/'}${traceID}`; - const response = await api.get(request_string); - - dispatch({ - type: ActionTypes.fetchTraceItem, - payload: response.data, - // PNOTE - response.data in the axios response has the actual API response? - }); - }; -}; diff --git a/frontend/src/store/actions/types.ts b/frontend/src/store/actions/types.ts index 2aaa38f9c3..c15ea00286 100644 --- a/frontend/src/store/actions/types.ts +++ b/frontend/src/store/actions/types.ts @@ -1,5 +1,5 @@ -import { serviceMapItemAction, servicesAction } from './serviceMap'; -import { getUsageDataAction } from './usage'; +import { ServiceMapItemAction, ServicesAction } from './serviceMap'; +import { GetUsageDataAction } from './usage'; export enum ActionTypes { updateTraceFilters = 'UPDATE_TRACES_FILTER', @@ -11,4 +11,4 @@ export enum ActionTypes { fetchTraceItem = 'FETCH_TRACE_ITEM', } -export type Action = getUsageDataAction | servicesAction | serviceMapItemAction; +export type Action = GetUsageDataAction | ServicesAction | ServiceMapItemAction; diff --git a/frontend/src/store/actions/usage.ts b/frontend/src/store/actions/usage.ts index 60367fd925..f343426bb3 100644 --- a/frontend/src/store/actions/usage.ts +++ b/frontend/src/store/actions/usage.ts @@ -4,14 +4,14 @@ import { toUTCEpoch } from 'utils/timeUtils'; import { ActionTypes } from './types'; -export interface usageDataItem { +export interface UsageDataItem { timestamp: number; count: number; } -export interface getUsageDataAction { +export interface GetUsageDataAction { type: ActionTypes.getUsageData; - payload: usageDataItem[]; + payload: UsageDataItem[]; } export const getUsageData = ( @@ -21,13 +21,13 @@ export const getUsageData = ( service: string, ) => { return async (dispatch: Dispatch): Promise => { - const request_string = `/usage?start=${toUTCEpoch(minTime)}&end=${toUTCEpoch( + const requesString = `/usage?start=${toUTCEpoch(minTime)}&end=${toUTCEpoch( maxTime, )}&step=${step}&service=${service || ''}`; // Step can only be multiple of 3600 - const response = await api.get(request_string); + const response = await api.get(requesString); - dispatch({ + dispatch({ type: ActionTypes.getUsageData, payload: response.data, // PNOTE - response.data in the axios response has the actual API response diff --git a/frontend/src/store/reducers/dashboard.ts b/frontend/src/store/reducers/dashboard.ts index 44d1cb44d1..ef15a2b55c 100644 --- a/frontend/src/store/reducers/dashboard.ts +++ b/frontend/src/store/reducers/dashboard.ts @@ -35,15 +35,10 @@ const InitialValue: InitialValueTypes = { const dashboard = ( state = InitialValue, action: DashboardActions, + // eslint-disable-next-line sonarjs/cognitive-complexity ): InitialValueTypes => { switch (action.type) { - case GET_ALL_DASHBOARD_LOADING_START: { - return { - ...state, - loading: true, - }; - } - + case GET_ALL_DASHBOARD_LOADING_START: case GET_DASHBOARD_LOADING_START: { return { ...state, diff --git a/frontend/src/store/reducers/global.ts b/frontend/src/store/reducers/global.ts index bb0e1fb764..1ba2e246e7 100644 --- a/frontend/src/store/reducers/global.ts +++ b/frontend/src/store/reducers/global.ts @@ -10,7 +10,7 @@ const intitalState: GlobalReducer = { maxTime: Date.now() * 1000000, minTime: (Date.now() - 15 * 60 * 1000) * 1000000, loading: true, - selectedTime: getDefaultOption(location.pathname), + selectedTime: getDefaultOption(window.location.pathname), }; const globalTimeReducer = ( diff --git a/frontend/src/store/reducers/serviceMap.ts b/frontend/src/store/reducers/serviceMap.ts index b81178a47b..ef7cd21496 100644 --- a/frontend/src/store/reducers/serviceMap.ts +++ b/frontend/src/store/reducers/serviceMap.ts @@ -1,6 +1,6 @@ -import { Action, ActionTypes, serviceMapStore } from 'store/actions'; +import { Action, ActionTypes, ServiceMapStore } from 'store/actions'; -const initialState: serviceMapStore = { +const initialState: ServiceMapStore = { items: [], services: [], }; @@ -8,7 +8,7 @@ const initialState: serviceMapStore = { export const ServiceMapReducer = ( state = initialState, action: Action, -): serviceMapStore => { +): ServiceMapStore => { switch (action.type) { case ActionTypes.getServiceMapItems: return { diff --git a/frontend/src/store/reducers/usage.ts b/frontend/src/store/reducers/usage.ts index eaaface3f1..66b54e3197 100644 --- a/frontend/src/store/reducers/usage.ts +++ b/frontend/src/store/reducers/usage.ts @@ -1,9 +1,10 @@ -import { Action, ActionTypes, usageDataItem } from 'store/actions'; +/* eslint-disable sonarjs/no-small-switch */ +import { Action, ActionTypes, UsageDataItem } from 'store/actions'; export const usageDataReducer = ( - state: usageDataItem[] = [{ timestamp: 0, count: 0 }], + state: UsageDataItem[] = [{ timestamp: 0, count: 0 }], action: Action, -): usageDataItem[] => { +): UsageDataItem[] => { switch (action.type) { case ActionTypes.getUsageData: return action.payload; diff --git a/frontend/src/types/actions/trace.ts b/frontend/src/types/actions/trace.ts index 5ea4b85357..9c22a55220 100644 --- a/frontend/src/types/actions/trace.ts +++ b/frontend/src/types/actions/trace.ts @@ -149,10 +149,6 @@ export interface UpdateSpans { }; } -export interface ResetTraceFilter { - type: typeof RESET_TRACE_FILTER; -} - export type TraceActions = | UpdateFilter | GetTraceFilter diff --git a/frontend/src/utils/getSpanTreeMetadata.ts b/frontend/src/utils/getSpanTreeMetadata.ts index 1719c1ab7c..3cce2667d2 100644 --- a/frontend/src/utils/getSpanTreeMetadata.ts +++ b/frontend/src/utils/getSpanTreeMetadata.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-param-reassign */ import { errorColor } from 'lib/getRandomColor'; import { ITraceTree } from 'types/api/trace/getTraceItem'; /** @@ -16,7 +17,7 @@ export const getSpanTreeMetadata = ( if (!treeNode) { return; } - totalSpans++; + totalSpans += 1; levels = Math.max(levels, level); const { startTime } = treeNode; const endTime = startTime + treeNode.value / 1e6; @@ -24,10 +25,11 @@ export const getSpanTreeMetadata = ( 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); } + treeNode.serviceColour = spanServiceColours[treeNode.serviceName]; + treeNode.children.forEach((childNode) => { + traverse(childNode, level + 1); + }); }; traverse(treeData, 1); diff --git a/frontend/src/utils/spanToTree.ts b/frontend/src/utils/spanToTree.ts index 3b35e49806..8b82671060 100644 --- a/frontend/src/utils/spanToTree.ts +++ b/frontend/src/utils/spanToTree.ts @@ -1,6 +1,8 @@ +/* eslint-disable */ +// @ts-nocheck + import { cloneDeep } from 'lodash-es'; import { ITraceTree, Span } from 'types/api/trace/getTraceItem'; -// PNOTE - should the data be taken from redux or only through props? - Directly as arguments export const spanToTreeUtil = (originalList: Span[]): ITraceTree => { // Initializing tree. What should be returned is trace is empty? We should have better error handling diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 2896ef19ef..311f773c08 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -80,7 +80,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.16.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": version "7.16.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== @@ -1337,6 +1337,16 @@ "@types/node" "*" jest-mock "^26.6.2" +"@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== + dependencies: + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + "@jest/fake-timers@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" @@ -1349,6 +1359,18 @@ jest-mock "^26.6.2" jest-util "^26.6.2" +"@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + "@jest/globals@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" @@ -1358,6 +1380,15 @@ "@jest/types" "^26.6.2" expect "^26.6.2" +"@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + "@jest/reporters@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" @@ -1452,6 +1483,17 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@jridgewell/resolve-uri@^3.0.3": version "3.0.5" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" @@ -1559,6 +1601,13 @@ dependencies: "@sinonjs/commons" "^1.7.0" +"@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + "@testing-library/cypress@^8.0.0": version "8.0.2" resolved "https://registry.yarnpkg.com/@testing-library/cypress/-/cypress-8.0.2.tgz#b13f0ff2424dec4368b6670dfbfb7e43af8eefc9" @@ -2369,6 +2418,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + "@types/yauzl@^2.9.1": version "2.9.2" resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" @@ -6025,6 +6081,16 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" +expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== + dependencies: + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + express@^4.17.1: version "4.17.3" resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" @@ -7646,7 +7712,7 @@ jest-matcher-utils@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-matcher-utils@^27.0.0: +jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== @@ -7671,6 +7737,21 @@ jest-message-util@^26.6.2: slash "^3.0.0" stack-utils "^2.0.2" +jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + jest-mock@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" @@ -7679,6 +7760,14 @@ jest-mock@^26.6.2: "@jest/types" "^26.6.2" "@types/node" "*" +jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-pnp-resolver@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" @@ -7813,6 +7902,18 @@ jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" +jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + jest-validate@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" @@ -11436,7 +11537,7 @@ stack-generator@^2.0.5: dependencies: stackframe "^1.1.1" -stack-utils@^2.0.2: +stack-utils@^2.0.2, stack-utils@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.5.tgz#d25265fca995154659dbbfba3b49254778d2fdd5" integrity sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA== From 78b1a750faa2bf90c57e23c6771ed85d5b966dc1 Mon Sep 17 00:00:00 2001 From: palash-signoz Date: Thu, 24 Mar 2022 15:06:57 +0530 Subject: [PATCH 03/15] husky: pre-commit hook is added (#904) --- frontend/.husky/pre-commit | 4 + frontend/package.json | 13 +- frontend/yarn.lock | 242 ++++++++++++++++--------------------- 3 files changed, 115 insertions(+), 144 deletions(-) create mode 100755 frontend/.husky/pre-commit diff --git a/frontend/.husky/pre-commit b/frontend/.husky/pre-commit new file mode 100755 index 0000000000..d801fab930 --- /dev/null +++ b/frontend/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +cd frontend && yarn lint-staged diff --git a/frontend/package.json b/frontend/package.json index 5a4f750a72..75453c759e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -13,7 +13,9 @@ "cypress:run": "cypress run", "jest": "jest", "jest:coverage": "jest --coverage", - "jest:watch": "jest --watch" + "jest:watch": "jest --watch", + "postinstall": "yarn husky:configure", + "husky:configure": "cd .. && husky install frontend/.husky" }, "engines": { "node": ">=12.13.0" @@ -146,9 +148,9 @@ "eslint-plugin-react-hooks": "^4.3.0", "eslint-plugin-simple-import-sort": "^7.0.0", "eslint-plugin-sonarjs": "^0.12.0", - "husky": "4.3.8", + "husky": "^7.0.4", "less-plugin-npm-import": "^2.1.0", - "lint-staged": "10.5.3", + "lint-staged": "^12.3.7", "portfinder-sync": "^0.0.2", "prettier": "2.2.1", "react-hot-loader": "^4.13.0", @@ -156,5 +158,10 @@ "typescript-plugin-css-modules": "^3.4.0", "webpack-bundle-analyzer": "^4.5.0", "webpack-cli": "^4.5.0" + }, + "lint-staged": { + "*.(js|jsx|ts|tsx)": [ + "eslint --fix" + ] } } diff --git a/frontend/yarn.lock b/frontend/yarn.lock index 311f773c08..13f9bd136c 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -2907,6 +2907,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3" + integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== + antd@4.19.2: version "4.19.2" resolved "https://registry.yarnpkg.com/antd/-/antd-4.19.2.tgz#5438478aedf61bf670784611cba077387ff0f1b3" @@ -3983,6 +3988,14 @@ cli-truncate@^2.1.0: slice-ansi "^3.0.0" string-width "^4.2.0" +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + cliui@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" @@ -4101,16 +4114,16 @@ commander@^5.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== -commander@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - commander@^7.0.0, commander@^7.2.0: version "7.2.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + common-tags@^1.8.0: version "1.8.2" resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" @@ -4121,11 +4134,6 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -compare-versions@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" - integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== - component-emitter@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -5186,7 +5194,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2: +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -5233,11 +5241,6 @@ decompress-response@^3.3.0: dependencies: mimic-response "^1.0.0" -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= - deep-assign@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/deep-assign/-/deep-assign-2.0.0.tgz#ebe06b1f07f08dae597620e3dd1622f371a1c572" @@ -5499,6 +5502,11 @@ duplexer@^0.1.2: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -6001,7 +6009,7 @@ exec-sh@^0.3.2: resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== -execa@4.1.0, execa@^4.0.0, execa@^4.1.0: +execa@4.1.0, execa@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== @@ -6029,7 +6037,7 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^5.0.0: +execa@^5.0.0, execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== @@ -6344,21 +6352,6 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -find-up@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -find-versions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" - integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== - dependencies: - semver-regex "^3.1.2" - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" @@ -6528,11 +6521,6 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" -get-own-enumerable-property-symbols@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" - integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== - get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -6929,21 +6917,10 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -husky@4.3.8: - version "4.3.8" - resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" - integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== - dependencies: - chalk "^4.0.0" - ci-info "^2.0.0" - compare-versions "^3.6.0" - cosmiconfig "^7.0.0" - find-versions "^4.0.0" - opencollective-postinstall "^2.0.2" - pkg-dir "^5.0.0" - please-upgrade-node "^3.2.0" - slash "^3.0.0" - which-pm-runs "^1.0.0" +husky@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" + integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== hyphenate-style-name@^1.0.2: version "1.0.4" @@ -7273,6 +7250,11 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + is-function@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" @@ -7322,7 +7304,7 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.0, is-obj@^1.0.1: +is-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= @@ -7367,11 +7349,6 @@ is-regex@^1.0.4, is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-regexp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" - integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= - is-shared-array-buffer@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" @@ -8248,7 +8225,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.4, lilconfig@^2.0.3, lilconfig@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== @@ -8258,28 +8235,27 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lint-staged@10.5.3: - version "10.5.3" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-10.5.3.tgz#c682838b3eadd4c864d1022da05daa0912fb1da5" - integrity sha512-TanwFfuqUBLufxCc3RUtFEkFraSPNR3WzWcGF39R3f2J7S9+iF9W0KTVLfSy09lYGmZS5NDCxjNvhGMSJyFCWg== +lint-staged@^12.3.7: + version "12.3.7" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.7.tgz#ad0e2014302f704f9cf2c0ebdb97ac63d0f17be0" + integrity sha512-/S4D726e2GIsDVWIk1XGvheCaDm1SJRQp8efamZFWJxQMVEbOwSysp7xb49Oo73KYCdy97mIWinhlxcoNqIfIQ== dependencies: - chalk "^4.1.0" - cli-truncate "^2.1.0" - commander "^6.2.0" - cosmiconfig "^7.0.0" - debug "^4.2.0" - dedent "^0.7.0" - enquirer "^2.3.6" - execa "^4.1.0" - listr2 "^3.2.2" - log-symbols "^4.0.0" - micromatch "^4.0.2" + cli-truncate "^3.1.0" + colorette "^2.0.16" + commander "^8.3.0" + debug "^4.3.3" + execa "^5.1.1" + lilconfig "2.0.4" + listr2 "^4.0.1" + micromatch "^4.0.4" normalize-path "^3.0.0" - please-upgrade-node "^3.2.0" - string-argv "0.3.1" - stringify-object "^3.3.0" + object-inspect "^1.12.0" + pidtree "^0.5.0" + string-argv "^0.3.1" + supports-color "^9.2.1" + yaml "^1.10.2" -listr2@^3.2.2, listr2@^3.8.3: +listr2@^3.8.3: version "3.14.0" resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== @@ -8293,6 +8269,20 @@ listr2@^3.2.2, listr2@^3.8.3: through "^2.3.8" wrap-ansi "^7.0.0" +listr2@^4.0.1: + version "4.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" + integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.5" + through "^2.3.8" + wrap-ansi "^7.0.0" + load-bmfont@^1.2.3: version "1.4.1" resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9" @@ -8363,13 +8353,6 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - lodash-es@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" @@ -8982,7 +8965,7 @@ object-copy@^0.1.0: define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.11.0, object-inspect@^1.9.0: +object-inspect@^1.11.0, object-inspect@^1.12.0, object-inspect@^1.9.0: version "1.12.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== @@ -9130,11 +9113,6 @@ open@^8.0.9: is-docker "^2.1.1" is-wsl "^2.2.0" -opencollective-postinstall@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== - opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" @@ -9193,7 +9171,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2, p-limit@^3.1.0: +p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -9221,13 +9199,6 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -9436,6 +9407,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.0: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidtree@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.5.0.tgz#ad5fbc1de78b8a5f99d6fbdd4f6e4eee21d1aca1" + integrity sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA== + pify@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -9465,20 +9441,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.0.0" - -please-upgrade-node@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" - integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== - dependencies: - semver-compare "^1.0.0" - polished@4: version "4.1.4" resolved "https://registry.yarnpkg.com/polished/-/polished-4.1.4.tgz#640293ba834109614961a700fdacbb6599fb12d0" @@ -10969,7 +10931,7 @@ rxjs@7.5.1: dependencies: tslib "^2.1.0" -rxjs@^7.5.1: +rxjs@^7.5.1, rxjs@^7.5.5: version "7.5.5" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== @@ -11094,16 +11056,6 @@ selfsigned@^2.0.0: dependencies: node-forge "^1.2.0" -semver-compare@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" - integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= - -semver-regex@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.3.tgz#b2bcc6f97f63269f286994e297e229b6245d0dc3" - integrity sha512-Aqi54Mk9uYTjVexLnR67rTyBusmwd04cLkHy9hNvk3+G3nT2Oyg7E0l4XVbOaNwIvQ3hHeYxGcyEy+mKreyBFQ== - "semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -11325,6 +11277,14 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -11596,7 +11556,7 @@ strict-uri-encode@^1.0.0: resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= -string-argv@0.3.1: +string-argv@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== @@ -11623,6 +11583,15 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string-width@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.matchall@^4.0.6: version "4.0.7" resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz#8e6ecb0d8a1fb1fda470d81acecb2dba057a481d" @@ -11667,15 +11636,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -stringify-object@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" - integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== - dependencies: - get-own-enumerable-property-symbols "^3.0.0" - is-obj "^1.0.1" - is-regexp "^1.0.0" - strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -11690,7 +11650,7 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-ansi@^7.0.0: +strip-ansi@^7.0.0, strip-ansi@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== @@ -11811,6 +11771,11 @@ supports-color@^8.0.0, supports-color@^8.1.1: dependencies: has-flag "^4.0.0" +supports-color@^9.2.1: + version "9.2.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.1.tgz#599dc9d45acf74c6176e0d880bab1d7d718fe891" + integrity sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ== + supports-hyperlinks@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" @@ -12740,11 +12705,6 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which-pm-runs@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" - integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== - which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" From ac70240b72855668a164d040526c7e667fb8438b Mon Sep 17 00:00:00 2001 From: Palash gupta Date: Thu, 24 Mar 2022 15:39:33 +0530 Subject: [PATCH 04/15] chore: some tsc fix --- .../src/components/NotFound/NotFound.test.tsx | 1 + frontend/src/components/Styled/types.ts | 2 +- .../container/GantChart/SpanLength/index.tsx | 2 +- .../src/container/ListOfDashboard/index.tsx | 2 +- .../LeftContainer/QuerySection/Query.tsx | 25 +++++++++++++++++-- frontend/src/container/Trace/Graph/index.tsx | 2 +- frontend/src/hooks/useFetch.ts | 2 +- frontend/src/lib/__tests__/getStep.test.ts | 1 + frontend/src/pages/DashboardWidget/index.tsx | 7 +++++- 9 files changed, 36 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/NotFound/NotFound.test.tsx b/frontend/src/components/NotFound/NotFound.test.tsx index e00ecc939f..c8aab78ef7 100644 --- a/frontend/src/components/NotFound/NotFound.test.tsx +++ b/frontend/src/components/NotFound/NotFound.test.tsx @@ -1,3 +1,4 @@ +import { expect } from '@jest/globals'; import { render } from '@testing-library/react'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; diff --git a/frontend/src/components/Styled/types.ts b/frontend/src/components/Styled/types.ts index fb829fb394..4a02884334 100644 --- a/frontend/src/components/Styled/types.ts +++ b/frontend/src/components/Styled/types.ts @@ -1,5 +1,5 @@ import { FlattenSimpleInterpolation } from 'styled-components'; export interface IStyledClass { - styledclass?: FlattenSimpleInterpolation[]; + styledclass: FlattenSimpleInterpolation[]; } diff --git a/frontend/src/container/GantChart/SpanLength/index.tsx b/frontend/src/container/GantChart/SpanLength/index.tsx index 4ee15a9332..4e27e6e624 100644 --- a/frontend/src/container/GantChart/SpanLength/index.tsx +++ b/frontend/src/container/GantChart/SpanLength/index.tsx @@ -33,7 +33,7 @@ function SpanLength(props: SpanLengthProps): JSX.Element { leftOffset={leftOffset} width={width} /> - {`${toFixed( + {`${toFixed( resolveTimeFromInterval(inMsCount, intervalUnit), 2, )} ${intervalUnit.name}`} diff --git a/frontend/src/container/ListOfDashboard/index.tsx b/frontend/src/container/ListOfDashboard/index.tsx index 8828d748f2..492da5c846 100644 --- a/frontend/src/container/ListOfDashboard/index.tsx +++ b/frontend/src/container/ListOfDashboard/index.tsx @@ -157,7 +157,7 @@ function ListOfAllDashboard(): JSX.Element { diff --git a/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx b/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx index 42b22fe206..97aa24d180 100644 --- a/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx +++ b/frontend/src/container/NewWidget/LeftContainer/QuerySection/Query.tsx @@ -2,8 +2,8 @@ import { Button, Divider } from 'antd'; import Input from 'components/Input'; import TextToolTip from 'components/TextToolTip'; import { timePreferance } from 'container/NewWidget/RightContainer/timeItems'; -import React, { useCallback, useState } from 'react'; -import { connect } from 'react-redux'; +import React, { useCallback, useMemo, useState } from 'react'; +import { connect, useSelector } from 'react-redux'; import { useLocation } from 'react-router-dom'; import { bindActionCreators, Dispatch } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; @@ -12,8 +12,11 @@ import { UpdateQuery, UpdateQueryProps, } from 'store/actions/dashboard/updateQuery'; +import { AppState } from 'store/reducers'; import AppActions from 'types/actions'; import { DeleteQueryProps } from 'types/actions/dashboard'; +import { Widgets } from 'types/api/dashboard/getAll'; +import DashboardReducer from 'types/reducer/dashboards'; import { ButtonContainer, @@ -32,10 +35,27 @@ function Query({ const [promqlQuery, setPromqlQuery] = useState(preQuery); const [legendFormat, setLegendFormat] = useState(preLegend); const { search } = useLocation(); + const { dashboards } = useSelector( + (state) => state.dashboards, + ); + + const [selectedDashboards] = dashboards; + const { widgets } = selectedDashboards.data; const query = new URLSearchParams(search); const widgetId = query.get('widgetId') || ''; + const urlQuery = useMemo(() => { + return new URLSearchParams(search); + }, [search]); + + const getWidget = useCallback(() => { + const widgetId = urlQuery.get('widgetId'); + return widgets?.find((e) => e.id === widgetId); + }, [widgets, urlQuery]); + + const selectedWidget = getWidget() as Widgets; + const onChangeHandler = useCallback( (setFunc: React.Dispatch>, value: string) => { setFunc(value); @@ -49,6 +69,7 @@ function Query({ legend: legendFormat, query: promqlQuery, widgetId, + yAxisUnit: selectedWidget.yAxisUnit, }); }; diff --git a/frontend/src/container/Trace/Graph/index.tsx b/frontend/src/container/Trace/Graph/index.tsx index 01630d4711..179ff792de 100644 --- a/frontend/src/container/Trace/Graph/index.tsx +++ b/frontend/src/container/Trace/Graph/index.tsx @@ -43,7 +43,7 @@ function TraceGraph(): JSX.Element { } return ( - + ( loading: false, success: false, error: true, - errorMessage: error, + errorMessage: error as string, }); } return (): void => { diff --git a/frontend/src/lib/__tests__/getStep.test.ts b/frontend/src/lib/__tests__/getStep.test.ts index 638c21cf4e..399f0cfbc6 100644 --- a/frontend/src/lib/__tests__/getStep.test.ts +++ b/frontend/src/lib/__tests__/getStep.test.ts @@ -1,3 +1,4 @@ +import { expect } from '@jest/globals'; import dayjs from 'dayjs'; import getStep, { DefaultStepSize } from 'lib/getStep'; diff --git a/frontend/src/pages/DashboardWidget/index.tsx b/frontend/src/pages/DashboardWidget/index.tsx index e4eedd4b24..7e9f4e8f73 100644 --- a/frontend/src/pages/DashboardWidget/index.tsx +++ b/frontend/src/pages/DashboardWidget/index.tsx @@ -74,7 +74,12 @@ function DashboardWidget({ getDashboard }: NewDashboardProps): JSX.Element { ); } - return ; + return ( + + ); } export interface DashboardWidgetPageParams { From cc47f02ebf31ecf7647b264de998eeed30f4ed81 Mon Sep 17 00:00:00 2001 From: Pranshu Chittora Date: Fri, 25 Mar 2022 12:03:57 +0530 Subject: [PATCH 05/15] fix: tsc fixes --- .../src/components/Graph/Plugin/Legend.ts | 20 +++++++++++++++---- frontend/src/components/Styled/index.ts | 4 ++-- frontend/src/components/Styled/styles.ts | 13 ++++++------ frontend/src/components/Styled/types.ts | 2 +- .../src/container/AllAlertChannels/Delete.tsx | 2 +- .../Graph/FullView/EmptyGraph.tsx | 1 + .../src/container/GridGraphLayout/index.tsx | 3 ++- .../RightContainer/YAxisUnitSelector.tsx | 4 ++-- frontend/src/container/Timeline/index.tsx | 8 ++++---- frontend/src/container/Timeline/utils.ts | 7 +++---- frontend/src/container/TraceDetail/index.tsx | 5 ++--- .../src/container/TraceFlameGraph/index.tsx | 2 ++ .../actions/dashboard/deleteDashboard.ts | 3 ++- .../store/actions/dashboard/getDashboard.ts | 3 ++- .../actions/dashboard/updateDashboardTitle.ts | 3 ++- ...e-fns.ts => chartjs-adapter-date-fns.d.ts} | 0 .../src/typings/{d3-tip.ts => d3-tip.d.ts} | 0 frontend/tsconfig.json | 3 ++- 18 files changed, 51 insertions(+), 32 deletions(-) rename frontend/src/typings/{chartjs-adapter-date-fns.ts => chartjs-adapter-date-fns.d.ts} (100%) rename frontend/src/typings/{d3-tip.ts => d3-tip.d.ts} (100%) diff --git a/frontend/src/components/Graph/Plugin/Legend.ts b/frontend/src/components/Graph/Plugin/Legend.ts index 2f03db40ac..b8ec2facf9 100644 --- a/frontend/src/components/Graph/Plugin/Legend.ts +++ b/frontend/src/components/Graph/Plugin/Legend.ts @@ -1,5 +1,6 @@ import { Chart, ChartType, Plugin } from 'chart.js'; import { colors } from 'lib/getRandomColor'; +import { get } from 'lodash-es'; const getOrCreateLegendList = ( chart: Chart, @@ -40,9 +41,20 @@ export const legend = (id: string, isLonger: boolean): Plugin => { } // Reuse the built-in legendItems generator - const items = chart?.options?.plugins?.legend?.labels?.generateLabels(chart); + const items = get(chart, [ + 'options', + 'plugins', + 'legend', + 'labels', + 'generateLabels', + ]) + ? get(chart, ['options', 'plugins', 'legend', 'labels', 'generateLabels'])( + chart, + ) + : null; - items?.forEach((item, index) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + items?.forEach((item: Record, index: number) => { const li = document.createElement('li'); li.style.alignItems = 'center'; li.style.cursor = 'pointer'; @@ -66,8 +78,8 @@ export const legend = (id: string, isLonger: boolean): Plugin => { // Color box const boxSpan = document.createElement('span'); - boxSpan.style.background = item.strokeStyle || colors[0]; - boxSpan.style.borderColor = item?.strokeStyle; + boxSpan.style.background = `${item.strokeStyle}` || `${colors[0]}`; + boxSpan.style.borderColor = `${item?.strokeStyle}`; boxSpan.style.borderWidth = `${item.lineWidth}px`; boxSpan.style.display = 'inline-block'; boxSpan.style.minHeight = '20px'; diff --git a/frontend/src/components/Styled/index.ts b/frontend/src/components/Styled/index.ts index 317a0f660e..ffa3fbccc0 100644 --- a/frontend/src/components/Styled/index.ts +++ b/frontend/src/components/Styled/index.ts @@ -6,8 +6,8 @@ import styled, { FlattenSimpleInterpolation } from 'styled-components'; import { IStyledClass } from './types'; -const styledClass = (props: IStyledClass): FlattenSimpleInterpolation => - props.styledclass; +const styledClass = (props: IStyledClass): FlattenSimpleInterpolation | null => + props.styledclass || null; type TStyledCol = AntD.ColProps & IStyledClass; const StyledCol = styled(AntD.Col)` diff --git a/frontend/src/components/Styled/styles.ts b/frontend/src/components/Styled/styles.ts index 8425beae07..9ff0b54146 100644 --- a/frontend/src/components/Styled/styles.ts +++ b/frontend/src/components/Styled/styles.ts @@ -1,6 +1,7 @@ import { css, FlattenSimpleInterpolation } from 'styled-components'; -const cssProprty = (key: string, value): FlattenSimpleInterpolation => +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const cssProperty = (key: any, value: any): FlattenSimpleInterpolation => key && value && css` @@ -15,8 +16,8 @@ export const Flex = ({ flexDirection, flex, }: IFlexProps): FlattenSimpleInterpolation => css` - ${cssProprty('flex-direction', flexDirection)} - ${cssProprty('flex', flex)} + ${cssProperty('flex-direction', flexDirection)} + ${cssProperty('flex', flex)} `; interface IDisplayProps { @@ -25,7 +26,7 @@ interface IDisplayProps { export const Display = ({ display, }: IDisplayProps): FlattenSimpleInterpolation => css` - ${cssProprty('display', display)} + ${cssProperty('display', display)} `; interface ISpacingProps { @@ -36,6 +37,6 @@ export const Spacing = ({ margin, padding, }: ISpacingProps): FlattenSimpleInterpolation => css` - ${cssProprty('margin', margin)} - ${cssProprty('padding', padding)} + ${cssProperty('margin', margin)} + ${cssProperty('padding', padding)} `; diff --git a/frontend/src/components/Styled/types.ts b/frontend/src/components/Styled/types.ts index 4a02884334..fb829fb394 100644 --- a/frontend/src/components/Styled/types.ts +++ b/frontend/src/components/Styled/types.ts @@ -1,5 +1,5 @@ import { FlattenSimpleInterpolation } from 'styled-components'; export interface IStyledClass { - styledclass: FlattenSimpleInterpolation[]; + styledclass?: FlattenSimpleInterpolation[]; } diff --git a/frontend/src/container/AllAlertChannels/Delete.tsx b/frontend/src/container/AllAlertChannels/Delete.tsx index 6f767d8bd1..4501c916c8 100644 --- a/frontend/src/container/AllAlertChannels/Delete.tsx +++ b/frontend/src/container/AllAlertChannels/Delete.tsx @@ -30,7 +30,7 @@ function Delete({ notifications, setChannels, id }: DeleteProps): JSX.Element { } catch (error) { notifications.error({ message: 'Error', - description: error.toString() || 'Something went wrong', + description: error instanceof Error ? error.toString() : 'Something went wrong', }); setLoading(false); } diff --git a/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx b/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx index de4d563acb..c284d83b7c 100644 --- a/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx +++ b/frontend/src/container/GridGraphLayout/Graph/FullView/EmptyGraph.tsx @@ -60,6 +60,7 @@ function EmptyGraph({ return ( void; + onSelect: React.Dispatch>; fieldLabel: string; }): JSX.Element { const onSelectHandler = (selectedValue: string): void => { - onSelect(findCategoryByName(selectedValue)?.id); + onSelect(findCategoryByName(selectedValue)?.id || ''); }; const options = flattenedCategories.map((options) => ({ value: options.name, diff --git a/frontend/src/container/Timeline/index.tsx b/frontend/src/container/Timeline/index.tsx index a8a12927bb..1ecea1f59f 100644 --- a/frontend/src/container/Timeline/index.tsx +++ b/frontend/src/container/Timeline/index.tsx @@ -1,4 +1,5 @@ import { StyledDiv } from 'components/Styled'; +import { ITraceMetaData } from 'container/GantChart'; import { IIntervalUnit, INTERVAL_UNITS } from 'container/TraceDetail/utils'; import useThemeMode from 'hooks/useThemeMode'; import React, { useEffect, useRef, useState } from 'react'; @@ -74,10 +75,9 @@ function Timeline({ {intervals && intervals.map((interval, index) => ( @@ -104,7 +104,7 @@ interface TimelineProps { totalSpans: number; levels: number; }; - globalTraceMetadata: Record; + globalTraceMetadata: ITraceMetaData; setIntervalUnit: React.Dispatch>; } diff --git a/frontend/src/container/Timeline/utils.ts b/frontend/src/container/Timeline/utils.ts index 60bec06331..1f4367c88e 100644 --- a/frontend/src/container/Timeline/utils.ts +++ b/frontend/src/container/Timeline/utils.ts @@ -1,3 +1,4 @@ +import { ITraceMetaData } from 'container/GantChart'; import { IIntervalUnit, resolveTimeFromInterval, @@ -7,14 +8,12 @@ import { toFixed } from 'utils/toFixed'; import { Interval } from './types'; -type TMetaDataType = Record; - export const getIntervalSpread = ({ localTraceMetaData, globalTraceMetadata, }: { - localTraceMetaData: TMetaDataType; - globalTraceMetadata: TMetaDataType; + localTraceMetaData: ITraceMetaData; + globalTraceMetadata: ITraceMetaData; }): { baseInterval: number; baseSpread: number; diff --git a/frontend/src/container/TraceDetail/index.tsx b/frontend/src/container/TraceDetail/index.tsx index 3207feee73..489eaa4f26 100644 --- a/frontend/src/container/TraceDetail/index.tsx +++ b/frontend/src/container/TraceDetail/index.tsx @@ -9,7 +9,7 @@ import { StyledTypography, } from 'components/Styled'; import * as StyledStyles from 'components/Styled/styles'; -import GanttChart from 'container/GantChart'; +import GanttChart, { ITraceMetaData } from 'container/GantChart'; import { getNodeById } from 'container/GantChart/utils'; import Timeline from 'container/Timeline'; import TraceFlameGraph from 'container/TraceFlameGraph'; @@ -55,7 +55,7 @@ function TraceDetail({ response }: TraceDetailProps): JSX.Element { /* eslint-enable */ }, [treeData, spanServiceColors]); - const [globalTraceMetadata] = useState>({ + const [globalTraceMetadata] = useState({ ...traceMetaData, }); @@ -129,7 +129,6 @@ function TraceDetail({ response }: TraceDetailProps): JSX.Element { diff --git a/frontend/src/container/TraceFlameGraph/index.tsx b/frontend/src/container/TraceFlameGraph/index.tsx index 6490a4c435..08a998fe77 100644 --- a/frontend/src/container/TraceFlameGraph/index.tsx +++ b/frontend/src/container/TraceFlameGraph/index.tsx @@ -173,6 +173,8 @@ function TraceFlameGraph(props: { onSpanSelect={onSpanSelect} hoveredSpanId={hoveredSpanId} selectedSpanId={selectedSpanId} + level={0} + parentLeftOffset={0} /> ); diff --git a/frontend/src/store/actions/dashboard/deleteDashboard.ts b/frontend/src/store/actions/dashboard/deleteDashboard.ts index 100970eeec..29115f395b 100644 --- a/frontend/src/store/actions/dashboard/deleteDashboard.ts +++ b/frontend/src/store/actions/dashboard/deleteDashboard.ts @@ -31,7 +31,8 @@ export const DeleteDashboard = ({ dispatch({ type: 'DELETE_DASHBOARD_ERROR', payload: { - errorMessage: error.toString() || 'Something went wrong', + errorMessage: + error instanceof Error ? error.toString() : 'Something went wrong', }, }); } diff --git a/frontend/src/store/actions/dashboard/getDashboard.ts b/frontend/src/store/actions/dashboard/getDashboard.ts index b219e3978d..917365049e 100644 --- a/frontend/src/store/actions/dashboard/getDashboard.ts +++ b/frontend/src/store/actions/dashboard/getDashboard.ts @@ -64,7 +64,8 @@ export const GetDashboard = ({ dispatch({ type: 'GET_DASHBOARD_ERROR', payload: { - errorMessage: error.toString() || 'Something went wrong', + errorMessage: + error instanceof Error ? error.toString() : 'Something went wrong', }, }); } diff --git a/frontend/src/store/actions/dashboard/updateDashboardTitle.ts b/frontend/src/store/actions/dashboard/updateDashboardTitle.ts index e60e01d345..dc1b24fb96 100644 --- a/frontend/src/store/actions/dashboard/updateDashboardTitle.ts +++ b/frontend/src/store/actions/dashboard/updateDashboardTitle.ts @@ -42,7 +42,8 @@ export const UpdateDashboardTitleDescriptionTags = ({ dispatch({ type: 'UPDATE_TITLE_DESCRIPTION_TAGS_ERROR', payload: { - errorMessage: error.toString() || 'Something went wrong', + errorMessage: + error instanceof Error ? error.toString() : 'Something went wrong', }, }); } diff --git a/frontend/src/typings/chartjs-adapter-date-fns.ts b/frontend/src/typings/chartjs-adapter-date-fns.d.ts similarity index 100% rename from frontend/src/typings/chartjs-adapter-date-fns.ts rename to frontend/src/typings/chartjs-adapter-date-fns.d.ts diff --git a/frontend/src/typings/d3-tip.ts b/frontend/src/typings/d3-tip.d.ts similarity index 100% rename from frontend/src/typings/d3-tip.ts rename to frontend/src/typings/d3-tip.d.ts diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 3ff85194f8..3c56b8f9d8 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -19,7 +19,8 @@ "noEmit": true, "baseUrl": "./src", "downlevelIteration": true, - "plugins": [{ "name": "typescript-plugin-css-modules" }] + "plugins": [{ "name": "typescript-plugin-css-modules" }], + "suppressImplicitAnyIndexErrors": true }, "exclude": ["node_modules"], "include": ["./src"] From ca78947a559e247f7e3f6999b93ad725869b2fc3 Mon Sep 17 00:00:00 2001 From: Pranshu Chittora Date: Fri, 25 Mar 2022 12:29:40 +0530 Subject: [PATCH 06/15] fix: save unit on dashboard without hitting apply (#912) --- frontend/src/store/actions/dashboard/saveDashboard.ts | 3 +++ frontend/src/store/reducers/dashboard.ts | 1 + 2 files changed, 4 insertions(+) diff --git a/frontend/src/store/actions/dashboard/saveDashboard.ts b/frontend/src/store/actions/dashboard/saveDashboard.ts index 9bbba4c1de..e14e40b737 100644 --- a/frontend/src/store/actions/dashboard/saveDashboard.ts +++ b/frontend/src/store/actions/dashboard/saveDashboard.ts @@ -18,6 +18,7 @@ export const SaveDashboard = ({ title, widgetId, dashboardId, + yAxisUnit, }: SaveDashboardProps): ((dispatch: Dispatch) => void) => { return async (dispatch: Dispatch): Promise => { try { @@ -39,6 +40,7 @@ export const SaveDashboard = ({ const updatednullZeroValues = nullZeroValues; const updatedopacity = opacity; const updatedtimePreferance = timePreferance; + const updatedYAxisUnit = yAxisUnit; const selectedWidgetIndex = data.widgets?.findIndex( (e) => e.id === widgetId, @@ -74,6 +76,7 @@ export const SaveDashboard = ({ opacity: updatedopacity, title: updatedTitle, timePreferance: updatedtimePreferance, + yAxisUnit: updatedYAxisUnit, queryData: { ...selectedWidget.queryData, data: [ diff --git a/frontend/src/store/reducers/dashboard.ts b/frontend/src/store/reducers/dashboard.ts index ef15a2b55c..7e46a21d3c 100644 --- a/frontend/src/store/reducers/dashboard.ts +++ b/frontend/src/store/reducers/dashboard.ts @@ -357,6 +357,7 @@ const dashboard = ( case SAVE_SETTING_TO_PANEL_SUCCESS: { const selectedDashboard = action.payload; + return { ...state, dashboards: [ From 84bfe112857b5602166fef3404a2ec30ff034b0d Mon Sep 17 00:00:00 2001 From: Palash gupta Date: Fri, 25 Mar 2022 12:33:52 +0530 Subject: [PATCH 07/15] chore: tsc error are fixed --- .../__tests__/TraceFlameGraph.test.tsx | 39 +++++++++++++++++-- frontend/src/modules/Usage/UsageExplorer.tsx | 11 ++++-- .../store/actions/trace/selectTraceFilter.ts | 1 + 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/frontend/src/container/TraceFlameGraph/__tests__/TraceFlameGraph.test.tsx b/frontend/src/container/TraceFlameGraph/__tests__/TraceFlameGraph.test.tsx index 7a8e1381d0..f97e41764c 100644 --- a/frontend/src/container/TraceFlameGraph/__tests__/TraceFlameGraph.test.tsx +++ b/frontend/src/container/TraceFlameGraph/__tests__/TraceFlameGraph.test.tsx @@ -1,9 +1,42 @@ import { expect } from '@jest/globals'; import { render } from '@testing-library/react'; import TraceFlameGraph from 'container/TraceFlameGraph'; -import React from 'react'; +import React, { useState } from 'react'; -test('loads and displays greeting', async () => { - const { asFragment } = render(); +test('loads and displays greeting', () => { + const onSpanHover = useState(''); + + const { asFragment } = render( + {}, + selectedSpanId: '', + traceMetaData: { + globalEnd: 0, + globalStart: 0, + levels: 0, + spread: 0, + totalSpans: 0, + }, + treeData: { + children: [], + id: '', + name: '', + serviceColour: '', + serviceName: '', + startTime: 0, + tags: [], + time: 0, + value: 0, + event: [], + hasError: false, + parent: undefined, + }, + }} + />, + ); expect(asFragment()).toMatchSnapshot(); }); diff --git a/frontend/src/modules/Usage/UsageExplorer.tsx b/frontend/src/modules/Usage/UsageExplorer.tsx index 1790343210..502ae0294b 100644 --- a/frontend/src/modules/Usage/UsageExplorer.tsx +++ b/frontend/src/modules/Usage/UsageExplorer.tsx @@ -5,6 +5,7 @@ import { Select, Space } from 'antd'; import Graph from 'components/Graph'; import React, { useEffect, useState } from 'react'; import { connect, useSelector } from 'react-redux'; +import { withRouter } from 'react-router-dom'; import { GetService, getUsageData, UsageDataItem } from 'store/actions'; import { AppState } from 'store/reducers'; import { GlobalTime } from 'types/actions/globalTime'; @@ -213,7 +214,9 @@ const mapStateToProps = ( }; }; -export const UsageExplorer = connect(mapStateToProps, { - getUsageData, - getServicesList: GetService, -})(_UsageExplorer); +export const UsageExplorer = withRouter( + connect(mapStateToProps, { + getUsageData, + getServicesList: GetService, + })(_UsageExplorer), +); diff --git a/frontend/src/store/actions/trace/selectTraceFilter.ts b/frontend/src/store/actions/trace/selectTraceFilter.ts index 7b1cd16729..f23a361f0a 100644 --- a/frontend/src/store/actions/trace/selectTraceFilter.ts +++ b/frontend/src/store/actions/trace/selectTraceFilter.ts @@ -46,6 +46,7 @@ export const SelectedTraceFilter = (props: { traces.selectedTags, traces.filter, traces.isFilterExclude, + traces.userSelectedFilter, ); }; }; From b1de6c1d7d16dd94e8e77768a09c0ebb01caf10a Mon Sep 17 00:00:00 2001 From: Palash gupta Date: Fri, 25 Mar 2022 12:35:38 +0530 Subject: [PATCH 08/15] chore: link is reverted --- frontend/src/container/ListOfDashboard/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/container/ListOfDashboard/index.tsx b/frontend/src/container/ListOfDashboard/index.tsx index 492da5c846..8828d748f2 100644 --- a/frontend/src/container/ListOfDashboard/index.tsx +++ b/frontend/src/container/ListOfDashboard/index.tsx @@ -157,7 +157,7 @@ function ListOfAllDashboard(): JSX.Element { From cc5d47e3eea58992e0ba290e9277829354f6b16a Mon Sep 17 00:00:00 2001 From: Palash gupta Date: Fri, 25 Mar 2022 12:39:26 +0530 Subject: [PATCH 09/15] chore: updated the type any --- frontend/src/container/Trace/Graph/config.ts | 2 ++ frontend/tsconfig.json | 3 +-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/container/Trace/Graph/config.ts b/frontend/src/container/Trace/Graph/config.ts index de6408354c..ed0f383d9c 100644 --- a/frontend/src/container/Trace/Graph/config.ts +++ b/frontend/src/container/Trace/Graph/config.ts @@ -69,6 +69,8 @@ export const getChartDataforGroupBy = ( const allGroupBy = Object.keys(items).map((e) => items[e].groupBy); keys(allGroupBy).forEach((e: string): void => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore const { length } = keys(allGroupBy[e]); if (length >= max) { diff --git a/frontend/tsconfig.json b/frontend/tsconfig.json index 3c56b8f9d8..3ff85194f8 100644 --- a/frontend/tsconfig.json +++ b/frontend/tsconfig.json @@ -19,8 +19,7 @@ "noEmit": true, "baseUrl": "./src", "downlevelIteration": true, - "plugins": [{ "name": "typescript-plugin-css-modules" }], - "suppressImplicitAnyIndexErrors": true + "plugins": [{ "name": "typescript-plugin-css-modules" }] }, "exclude": ["node_modules"], "include": ["./src"] From e7ba5f9f3397dd1b6c7fa0bb28641a4e5ebc2959 Mon Sep 17 00:00:00 2001 From: palash-signoz Date: Fri, 25 Mar 2022 19:16:07 +0530 Subject: [PATCH 10/15] =?UTF-8?q?bug=20=F0=9F=90=9B=20:=20on=20click=20tag?= =?UTF-8?q?=20filter=20is=20now=20fixed=20(#916)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/container/Trace/Search/AllTags/index.tsx | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/frontend/src/container/Trace/Search/AllTags/index.tsx b/frontend/src/container/Trace/Search/AllTags/index.tsx index a5c93f2c81..91e2d08cb0 100644 --- a/frontend/src/container/Trace/Search/AllTags/index.tsx +++ b/frontend/src/container/Trace/Search/AllTags/index.tsx @@ -1,7 +1,6 @@ import { CaretRightFilled, PlusOutlined } from '@ant-design/icons'; import { Button, Space, Typography } from 'antd'; -import { isEqual } from 'lodash-es'; -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import { connect, useSelector } from 'react-redux'; import { bindActionCreators } from 'redux'; import { ThunkDispatch } from 'redux-thunk'; @@ -48,12 +47,6 @@ function AllTags({ ]); }; - useEffect(() => { - if (!isEqual(traces.selectedTags, localSelectedTags)) { - setLocalSelectedTags(traces.selectedTags); - } - }, [traces.selectedTags, localSelectedTags]); - const onCloseHandler = (index: number): void => { setLocalSelectedTags([ ...localSelectedTags.slice(0, index), From 0efb901863304970b8fc5b9518cb10d439e73b65 Mon Sep 17 00:00:00 2001 From: Amol Umbark Date: Mon, 28 Mar 2022 21:01:57 +0530 Subject: [PATCH 11/15] feat: Amol/webhook (#868) webhook receiver enabled for alerts Co-authored-by: Palash gupta --- .../clickhouse-setup/docker-compose.yaml | 11 +- frontend/src/api/channels/createWebhook.ts | 51 +++++++ frontend/src/api/channels/editWebhook.ts | 50 +++++++ frontend/src/components/Graph/index.tsx | 1 + .../src/container/AllAlertChannels/Delete.tsx | 3 +- .../container/CreateAlertChannels/config.ts | 26 +++- .../container/CreateAlertChannels/index.tsx | 101 ++++++++++++-- .../src/container/EditAlertChannels/index.tsx | 65 ++++++++- .../FormAlertChannels/Settings/Webhook.tsx | 59 ++++++++ .../src/container/FormAlertChannels/index.tsx | 22 ++- frontend/src/container/Timeline/index.tsx | 5 +- .../src/pages/AlertChannelCreate/index.tsx | 2 +- frontend/src/pages/ChannelsEdit/index.tsx | 32 ++++- .../src/types/api/channels/createWebhook.ts | 8 ++ .../src/types/api/channels/editWebhook.ts | 10 ++ .../app/clickhouseReader/reader.go | 86 +++--------- pkg/query-service/app/druidReader/reader.go | 5 +- pkg/query-service/app/http_handler.go | 5 +- pkg/query-service/app/interface.go | 5 +- pkg/query-service/constants/constants.go | 14 +- .../integrations/alertManager/manager.go | 129 ++++++++++++++++++ .../integrations/alertManager/model.go | 22 +++ pkg/query-service/model/response.go | 21 --- 23 files changed, 604 insertions(+), 129 deletions(-) create mode 100644 frontend/src/api/channels/createWebhook.ts create mode 100644 frontend/src/api/channels/editWebhook.ts create mode 100644 frontend/src/container/FormAlertChannels/Settings/Webhook.tsx create mode 100644 frontend/src/types/api/channels/createWebhook.ts create mode 100644 frontend/src/types/api/channels/editWebhook.ts create mode 100644 pkg/query-service/integrations/alertManager/manager.go create mode 100644 pkg/query-service/integrations/alertManager/model.go diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index ac69884ff6..c161d1c4d4 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -15,17 +15,20 @@ services: retries: 3 alertmanager: - image: signoz/alertmanager:0.5.0 + image: signoz/alertmanager:0.6.0 volumes: - - ./alertmanager.yml:/prometheus/alertmanager.yml + # we no longer need the config file as query services delivers + # the required config now + # - ./alertmanager.yml:/prometheus/alertmanager.yml - ./data/alertmanager:/data + depends_on: + - query-service command: - - '--config.file=/prometheus/alertmanager.yml' + - '--queryService.url=http://query-service:8080' - '--storage.path=/data' # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` - query-service: image: signoz/query-service:0.7.3 container_name: query-service diff --git a/frontend/src/api/channels/createWebhook.ts b/frontend/src/api/channels/createWebhook.ts new file mode 100644 index 0000000000..9c3c52c943 --- /dev/null +++ b/frontend/src/api/channels/createWebhook.ts @@ -0,0 +1,51 @@ +import axios from 'api'; +import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; +import { AxiosError } from 'axios'; +import { ErrorResponse, SuccessResponse } from 'types/api'; +import { PayloadProps, Props } from 'types/api/channels/createWebhook'; + +const create = async ( + props: Props, +): Promise | ErrorResponse> => { + try { + let httpConfig = {}; + + if (props.username !== '' && props.password !== '') { + httpConfig = { + basic_auth: { + username: props.username, + password: props.password, + }, + }; + } else if (props.username === '' && props.password !== '') { + httpConfig = { + authorization: { + type: 'bearer', + credentials: props.password, + }, + }; + } + + const response = await axios.post('/channels', { + name: props.name, + webhook_configs: [ + { + send_resolved: true, + url: props.api_url, + http_config: httpConfig, + }, + ], + }); + + return { + statusCode: 200, + error: null, + message: 'Success', + payload: response.data.data, + }; + } catch (error) { + return ErrorResponseHandler(error as AxiosError); + } +}; + +export default create; diff --git a/frontend/src/api/channels/editWebhook.ts b/frontend/src/api/channels/editWebhook.ts new file mode 100644 index 0000000000..a574633e4e --- /dev/null +++ b/frontend/src/api/channels/editWebhook.ts @@ -0,0 +1,50 @@ +import axios from 'api'; +import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; +import { AxiosError } from 'axios'; +import { ErrorResponse, SuccessResponse } from 'types/api'; +import { PayloadProps, Props } from 'types/api/channels/editWebhook'; + +const editWebhook = async ( + props: Props, +): Promise | ErrorResponse> => { + try { + let httpConfig = {}; + if (props.username !== '' && props.password !== '') { + httpConfig = { + basic_auth: { + username: props.username, + password: props.password, + }, + }; + } else if (props.username === '' && props.password !== '') { + httpConfig = { + authorization: { + type: 'bearer', + credentials: props.password, + }, + }; + } + + const response = await axios.put(`/channels/${props.id}`, { + name: props.name, + webhook_configs: [ + { + send_resolved: true, + url: props.api_url, + http_config: httpConfig, + }, + ], + }); + + return { + statusCode: 200, + error: null, + message: 'Success', + payload: response.data.data, + }; + } catch (error) { + return ErrorResponseHandler(error as AxiosError); + } +}; + +export default editWebhook; diff --git a/frontend/src/components/Graph/index.tsx b/frontend/src/components/Graph/index.tsx index bdf23e6468..a8f668235d 100644 --- a/frontend/src/components/Graph/index.tsx +++ b/frontend/src/components/Graph/index.tsx @@ -79,6 +79,7 @@ function Graph({ return 'rgba(231,233,237,0.8)'; }, [currentTheme]); + // eslint-disable-next-line sonarjs/cognitive-complexity const buildChart = useCallback(() => { if (lineChartRef.current !== undefined) { lineChartRef.current.destroy(); diff --git a/frontend/src/container/AllAlertChannels/Delete.tsx b/frontend/src/container/AllAlertChannels/Delete.tsx index 4501c916c8..85116fd922 100644 --- a/frontend/src/container/AllAlertChannels/Delete.tsx +++ b/frontend/src/container/AllAlertChannels/Delete.tsx @@ -30,7 +30,8 @@ function Delete({ notifications, setChannels, id }: DeleteProps): JSX.Element { } catch (error) { notifications.error({ message: 'Error', - description: error instanceof Error ? error.toString() : 'Something went wrong', + description: + error instanceof Error ? error.toString() : 'Something went wrong', }); setLoading(false); } diff --git a/frontend/src/container/CreateAlertChannels/config.ts b/frontend/src/container/CreateAlertChannels/config.ts index 364d367806..f104a84076 100644 --- a/frontend/src/container/CreateAlertChannels/config.ts +++ b/frontend/src/container/CreateAlertChannels/config.ts @@ -1,10 +1,22 @@ -export interface SlackChannel { - send_resolved: boolean; - api_url: string; - channel: string; - title: string; - text: string; +export interface Channel { + send_resolved?: boolean; name: string; } -export type ChannelType = 'slack' | 'email'; +export interface SlackChannel extends Channel { + api_url?: string; + channel?: string; + title?: string; + text?: string; +} + +export interface WebhookChannel extends Channel { + api_url?: string; + // basic auth + username?: string; + password?: string; +} + +export type ChannelType = 'slack' | 'email' | 'webhook'; +export const SlackType: ChannelType = 'slack'; +export const WebhookType: ChannelType = 'webhook'; diff --git a/frontend/src/container/CreateAlertChannels/index.tsx b/frontend/src/container/CreateAlertChannels/index.tsx index 8a3b3fe606..f999627154 100644 --- a/frontend/src/container/CreateAlertChannels/index.tsx +++ b/frontend/src/container/CreateAlertChannels/index.tsx @@ -1,17 +1,26 @@ import { Form, notification } from 'antd'; import createSlackApi from 'api/channels/createSlack'; +import createWebhookApi from 'api/channels/createWebhook'; import ROUTES from 'constants/routes'; import FormAlertChannels from 'container/FormAlertChannels'; import history from 'lib/history'; import React, { useCallback, useState } from 'react'; -import { ChannelType, SlackChannel } from './config'; +import { + ChannelType, + SlackChannel, + SlackType, + WebhookChannel, + WebhookType, +} from './config'; function CreateAlertChannels({ preType = 'slack', }: CreateAlertChannelsProps): JSX.Element { const [formInstance] = Form.useForm(); - const [selectedConfig, setSelectedConfig] = useState>({ + const [selectedConfig, setSelectedConfig] = useState< + Partial + >({ text: ` {{ range .Alerts -}} *Alert:* {{ .Annotations.title }}{{ if .Labels.severity }} - {{ .Labels.severity }}{{ end }} @@ -73,17 +82,93 @@ function CreateAlertChannels({ } setSavingState(false); } catch (error) { + notifications.error({ + message: 'Error', + description: + 'An unexpected error occurred while creating this channel, please try again', + }); setSavingState(false); } }, [notifications, selectedConfig]); + const onWebhookHandler = useCallback(async () => { + // initial api request without auth params + let request: WebhookChannel = { + api_url: selectedConfig?.api_url || '', + name: selectedConfig?.name || '', + send_resolved: true, + }; + + setSavingState(true); + + try { + if (selectedConfig?.username !== '' || selectedConfig?.password !== '') { + if (selectedConfig?.username !== '') { + // if username is not null then password must be passed + if (selectedConfig?.password !== '') { + request = { + ...request, + username: selectedConfig.username, + password: selectedConfig.password, + }; + } else { + notifications.error({ + message: 'Error', + description: 'A Password must be provided with user name', + }); + } + } else if (selectedConfig?.password !== '') { + // only password entered, set bearer token + request = { + ...request, + username: '', + password: selectedConfig.password, + }; + } + } + + const response = await createWebhookApi(request); + if (response.statusCode === 200) { + notifications.success({ + message: 'Success', + description: 'Successfully created the channel', + }); + setTimeout(() => { + history.replace(ROUTES.SETTINGS); + }, 2000); + } else { + notifications.error({ + message: 'Error', + description: response.error || 'Error while creating the channel', + }); + } + } catch (error) { + notifications.error({ + message: 'Error', + description: + 'An unexpected error occurred while creating this channel, please try again', + }); + } + setSavingState(false); + }, [notifications, selectedConfig]); + const onSaveHandler = useCallback( async (value: ChannelType) => { - if (value === 'slack') { - onSlackHandler(); + switch (value) { + case SlackType: + onSlackHandler(); + break; + case WebhookType: + onWebhookHandler(); + break; + default: + notifications.error({ + message: 'Error', + description: 'channel type selected is invalid', + }); } }, - [onSlackHandler], + [onSlackHandler, onWebhookHandler, notifications], ); return ( @@ -108,11 +193,7 @@ function CreateAlertChannels({ } interface CreateAlertChannelsProps { - preType?: ChannelType; + preType: ChannelType; } -CreateAlertChannels.defaultProps = { - preType: undefined, -}; - export default CreateAlertChannels; diff --git a/frontend/src/container/EditAlertChannels/index.tsx b/frontend/src/container/EditAlertChannels/index.tsx index 2d8ac3576d..e4aab19d31 100644 --- a/frontend/src/container/EditAlertChannels/index.tsx +++ b/frontend/src/container/EditAlertChannels/index.tsx @@ -1,9 +1,13 @@ import { Form, notification } from 'antd'; import editSlackApi from 'api/channels/editSlack'; +import editWebhookApi from 'api/channels/editWebhook'; import ROUTES from 'constants/routes'; import { ChannelType, SlackChannel, + SlackType, + WebhookChannel, + WebhookType, } from 'container/CreateAlertChannels/config'; import FormAlertChannels from 'container/FormAlertChannels'; import history from 'lib/history'; @@ -14,14 +18,18 @@ function EditAlertChannels({ initialValue, }: EditAlertChannelsProps): JSX.Element { const [formInstance] = Form.useForm(); - const [selectedConfig, setSelectedConfig] = useState>({ + const [selectedConfig, setSelectedConfig] = useState< + Partial + >({ ...initialValue, }); const [savingState, setSavingState] = useState(false); const [notifications, NotificationElement] = notification.useNotification(); const { id } = useParams<{ id: string }>(); - const [type, setType] = useState('slack'); + const [type, setType] = useState( + initialValue?.type ? (initialValue.type as ChannelType) : SlackType, + ); const onTypeChangeHandler = useCallback((value: string) => { setType(value as ChannelType); @@ -57,13 +65,62 @@ function EditAlertChannels({ setSavingState(false); }, [selectedConfig, notifications, id]); + const onWebhookEditHandler = useCallback(async () => { + setSavingState(true); + const { name, username, password } = selectedConfig; + + const showError = (msg: string): void => { + notifications.error({ + message: 'Error', + description: msg, + }); + }; + + if (selectedConfig?.api_url === '') { + showError('Webhook URL is mandatory'); + setSavingState(false); + return; + } + + if (username && (!password || password === '')) { + showError('Please enter a password'); + setSavingState(false); + return; + } + + const response = await editWebhookApi({ + api_url: selectedConfig?.api_url || '', + name: name || '', + send_resolved: true, + username, + password, + id, + }); + + if (response.statusCode === 200) { + notifications.success({ + message: 'Success', + description: 'Channels Edited Successfully', + }); + + setTimeout(() => { + history.replace(ROUTES.SETTINGS); + }, 2000); + } else { + showError(response.error || 'error while updating the Channels'); + } + setSavingState(false); + }, [selectedConfig, notifications, id]); + const onSaveHandler = useCallback( (value: ChannelType) => { - if (value === 'slack') { + if (value === SlackType) { onSlackEditHandler(); + } else if (value === WebhookType) { + onWebhookEditHandler(); } }, - [onSlackEditHandler], + [onSlackEditHandler, onWebhookEditHandler], ); const onTestHandler = useCallback(() => { diff --git a/frontend/src/container/FormAlertChannels/Settings/Webhook.tsx b/frontend/src/container/FormAlertChannels/Settings/Webhook.tsx new file mode 100644 index 0000000000..1c7748f795 --- /dev/null +++ b/frontend/src/container/FormAlertChannels/Settings/Webhook.tsx @@ -0,0 +1,59 @@ +import { Input } from 'antd'; +import FormItem from 'antd/lib/form/FormItem'; +import React from 'react'; + +import { WebhookChannel } from '../../CreateAlertChannels/config'; + +function WebhookSettings({ setSelectedConfig }: WebhookProps): JSX.Element { + return ( + <> + + { + setSelectedConfig((value) => ({ + ...value, + api_url: event.target.value, + })); + }} + /> + + + { + setSelectedConfig((value) => ({ + ...value, + username: event.target.value, + })); + }} + /> + + + { + setSelectedConfig((value) => ({ + ...value, + password: event.target.value, + })); + }} + /> + + + ); +} + +interface WebhookProps { + setSelectedConfig: React.Dispatch< + React.SetStateAction> + >; +} + +export default WebhookSettings; diff --git a/frontend/src/container/FormAlertChannels/index.tsx b/frontend/src/container/FormAlertChannels/index.tsx index 573be68d00..55aa6e238f 100644 --- a/frontend/src/container/FormAlertChannels/index.tsx +++ b/frontend/src/container/FormAlertChannels/index.tsx @@ -5,11 +5,14 @@ import ROUTES from 'constants/routes'; import { ChannelType, SlackChannel, + SlackType, + WebhookType, } from 'container/CreateAlertChannels/config'; import history from 'lib/history'; import React from 'react'; import SlackSettings from './Settings/Slack'; +import WebhookSettings from './Settings/Webhook'; import { Button } from './styles'; const { Option } = Select; @@ -28,6 +31,16 @@ function FormAlertChannels({ initialValue, nameDisable = false, }: FormAlertChannelsProps): JSX.Element { + const renderSettings = (): React.ReactElement | null => { + switch (type) { + case SlackType: + return ; + case WebhookType: + return ; + default: + return null; + } + }; return ( <> {NotificationElement} @@ -52,14 +65,13 @@ function FormAlertChannels({ + - - {type === 'slack' && ( - - )} - + {renderSettings()} - ); + return Delete; } interface DispatchProps { diff --git a/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx b/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx index fa2ff98991..e54431063f 100644 --- a/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx +++ b/frontend/src/container/ListOfDashboard/TableComponents/Name.tsx @@ -1,10 +1,10 @@ -import { Button } from 'antd'; import ROUTES from 'constants/routes'; import history from 'lib/history'; import React from 'react'; import { generatePath } from 'react-router-dom'; import { Data } from '..'; +import { TableLinkText } from './styles'; function Name(name: Data['name'], data: Data): JSX.Element { const onClickHandler = (): void => { @@ -17,11 +17,7 @@ function Name(name: Data['name'], data: Data): JSX.Element { ); }; - return ( - - ); + return {name}; } export default Name; diff --git a/frontend/src/container/ListOfDashboard/TableComponents/styles.ts b/frontend/src/container/ListOfDashboard/TableComponents/styles.ts new file mode 100644 index 0000000000..78c382700b --- /dev/null +++ b/frontend/src/container/ListOfDashboard/TableComponents/styles.ts @@ -0,0 +1,8 @@ +import { blue } from '@ant-design/colors'; +import { Typography } from 'antd'; +import styled from 'styled-components'; + +export const TableLinkText = styled(Typography.Text)` + color: ${blue.primary} !important; + cursor: pointer; +`; From 3dc94c8da76ff03d1e07646cb91710b47cab4159 Mon Sep 17 00:00:00 2001 From: Amol Umbark Date: Tue, 29 Mar 2022 19:59:40 +0530 Subject: [PATCH 14/15] (fix): Duplicate alerts in triggered alerts (#932) * (fix): Duplicate alerts in triggered alerts fixed by changing source api from /alert/groups to /alerts * (fix): added comments for removed lines of group api call * (fix): restored all getGroup --- frontend/src/api/alerts/getTriggered.ts | 29 +++++++++++++++++++ .../TriggeredAlerts/TriggeredAlert.tsx | 16 +++++----- .../src/container/TriggeredAlerts/index.tsx | 19 +++++++----- frontend/src/types/api/alerts/getTriggered.ts | 10 +++++++ 4 files changed, 59 insertions(+), 15 deletions(-) create mode 100644 frontend/src/api/alerts/getTriggered.ts create mode 100644 frontend/src/types/api/alerts/getTriggered.ts diff --git a/frontend/src/api/alerts/getTriggered.ts b/frontend/src/api/alerts/getTriggered.ts new file mode 100644 index 0000000000..160b9a3b93 --- /dev/null +++ b/frontend/src/api/alerts/getTriggered.ts @@ -0,0 +1,29 @@ +import { AxiosAlertManagerInstance } from 'api'; +import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; +import { AxiosError } from 'axios'; +import convertObjectIntoParams from 'lib/query/convertObjectIntoParams'; +import { ErrorResponse, SuccessResponse } from 'types/api'; +import { PayloadProps, Props } from 'types/api/alerts/getTriggered'; + +const getTriggered = async ( + props: Props, +): Promise | ErrorResponse> => { + try { + const queryParams = convertObjectIntoParams(props); + + const response = await AxiosAlertManagerInstance.get( + `/alerts?${queryParams}`, + ); + + return { + statusCode: 200, + error: null, + message: response.data.status, + payload: response.data, + }; + } catch (error) { + return ErrorResponseHandler(error as AxiosError); + } +}; + +export default getTriggered; diff --git a/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx b/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx index df3b6ff012..425334e7ba 100644 --- a/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx +++ b/frontend/src/container/TriggeredAlerts/TriggeredAlert.tsx @@ -1,4 +1,4 @@ -import getGroupApi from 'api/alerts/getGroup'; +import getTriggeredApi from 'api/alerts/getTriggered'; import useInterval from 'hooks/useInterval'; import React, { useState } from 'react'; import { Alerts } from 'types/api/alerts/getAll'; @@ -13,20 +13,22 @@ function TriggeredAlerts({ allAlerts }: TriggeredAlertsProps): JSX.Element { useInterval(() => { (async (): Promise => { - const response = await getGroupApi({ + const response = await getTriggeredApi({ active: true, inhibited: true, silenced: false, }); if (response.statusCode === 200 && response.payload !== null) { - const initialAlerts: Alerts[] = []; + // commented reduce() call as we no longer use /alerts/groups + // from alertmanager which needed re-grouping on client side + // const initialAlerts: Alerts[] = []; - const allAlerts: Alerts[] = response.payload.reduce((acc, cur) => { - return [...acc, ...cur.alerts]; - }, initialAlerts); + // const allAlerts: Alerts[] = response.payload.reduce((acc, cur) => { + // return [...acc, ...cur.alerts]; + // }, initialAlerts); - setInitialAlerts(allAlerts); + setInitialAlerts(response.payload); } })(); }, 30000); diff --git a/frontend/src/container/TriggeredAlerts/index.tsx b/frontend/src/container/TriggeredAlerts/index.tsx index a665adf6dd..88ebb2e138 100644 --- a/frontend/src/container/TriggeredAlerts/index.tsx +++ b/frontend/src/container/TriggeredAlerts/index.tsx @@ -1,9 +1,9 @@ -import getGroupApi from 'api/alerts/getGroup'; +import getTriggeredApi from 'api/alerts/getTriggered'; import Spinner from 'components/Spinner'; import { State } from 'hooks/useFetch'; import React, { useCallback, useEffect, useState } from 'react'; import { Alerts } from 'types/api/alerts/getAll'; -import { PayloadProps } from 'types/api/alerts/getGroups'; +import { PayloadProps } from 'types/api/alerts/getTriggered'; import TriggerComponent from './TriggeredAlert'; @@ -23,7 +23,7 @@ function TriggeredAlerts(): JSX.Element { loading: true, })); - const response = await getGroupApi({ + const response = await getTriggeredApi({ active: true, inhibited: true, silenced: false, @@ -65,13 +65,16 @@ function TriggeredAlerts(): JSX.Element { return ; } - const initialAlerts: Alerts[] = []; + // commented the reduce() call as we no longer use /alerts/groups + // API from alert manager, which returns a group for each receiver - const allAlerts: Alerts[] = groupState.payload.reduce((acc, curr) => { - return [...acc, ...curr.alerts]; - }, initialAlerts); + // const initialAlerts: Alerts[] = []; - return ; + // const allAlerts: Alerts[] = groupState.payload.reduce((acc, curr) => { + // return [...acc, ...curr.alerts]; + // }, initialAlerts); + + return ; } export default TriggeredAlerts; diff --git a/frontend/src/types/api/alerts/getTriggered.ts b/frontend/src/types/api/alerts/getTriggered.ts new file mode 100644 index 0000000000..8b0e50a279 --- /dev/null +++ b/frontend/src/types/api/alerts/getTriggered.ts @@ -0,0 +1,10 @@ +import { Alerts } from './getAll'; + +export interface Props { + silenced: boolean; + inhibited: boolean; + active: boolean; + [key: string]: string | boolean; +} + +export type PayloadProps = Alerts[] | []; From 1002ab553eed39b580d22f88d1c06b76757ea987 Mon Sep 17 00:00:00 2001 From: Prashant Shahi Date: Tue, 29 Mar 2022 22:59:32 +0530 Subject: [PATCH 15/15] =?UTF-8?q?chore(release):=20=F0=9F=93=8C=20pin=200.?= =?UTF-8?q?7.4=20SigNoz=20version=20and=20deployment=20changes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Prashant Shahi --- .../clickhouse-setup/docker-compose.yaml | 15 +++++++------ .../clickhouse-setup/docker-compose.arm.yaml | 17 +++++++------- .../clickhouse-setup/docker-compose.yaml | 14 +++++------- .../tests/test-deploy/docker-compose.arm.yaml | 20 ++++++++--------- .../tests/test-deploy/docker-compose.yaml | 22 ++++++++----------- 5 files changed, 40 insertions(+), 48 deletions(-) diff --git a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml index 425dbde5a3..c5d8e6b630 100644 --- a/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker-swarm/clickhouse-setup/docker-compose.yaml @@ -17,19 +17,20 @@ services: retries: 3 alertmanager: - image: signoz/alertmanager:0.5.0 + image: signoz/alertmanager:0.6.0 volumes: - - ./alertmanager.yml:/prometheus/alertmanager.yml - ./data/alertmanager:/data command: - - '--config.file=/prometheus/alertmanager.yml' - - '--storage.path=/data' + - --queryService.url=http://query-service:8080 + - --storage.path=/data + depends_on: + - query-service deploy: restart_policy: condition: on-failure query-service: - image: signoz/query-service:0.7.3 + image: signoz/query-service:0.7.4 command: ["-config=/root/config/prometheus.yml"] ports: - "8080:8080" @@ -48,10 +49,10 @@ services: restart_policy: condition: on-failure depends_on: - - clickhouse + - clickhouse frontend: - image: signoz/frontend:0.7.3 + image: signoz/frontend:0.7.4 depends_on: - query-service ports: diff --git a/deploy/docker/clickhouse-setup/docker-compose.arm.yaml b/deploy/docker/clickhouse-setup/docker-compose.arm.yaml index 2d5a638fd9..0540fa2868 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.arm.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.arm.yaml @@ -15,16 +15,17 @@ services: retries: 3 alertmanager: - image: signoz/alertmanager:0.5.0 + image: signoz/alertmanager:0.6.0 volumes: - - ./alertmanager.yml:/prometheus/alertmanager.yml - ./data/alertmanager:/data + depends_on: + - query-service command: - - '--config.file=/prometheus/alertmanager.yml' - - '--storage.path=/data' + - --queryService.url=http://query-service:8080 + - --storage.path=/data query-service: - image: signoz/query-service:0.7.3 + image: signoz/query-service:0.7.4 container_name: query-service command: ["-config=/root/config/prometheus.yml"] volumes: @@ -44,7 +45,7 @@ services: condition: service_healthy frontend: - image: signoz/frontend:0.7.3 + image: signoz/frontend:0.7.4 container_name: frontend depends_on: - query-service @@ -66,7 +67,7 @@ services: # - "14268:14268" # Jaeger receiver # - "55678:55678" # OpenCensus receiver # - "55679:55679" # zpages extension - # - "55680:55680" # OTLP gRPC legacy port + # - "55680:55680" # OTLP gRPC legacy receiver # - "55681:55681" # OTLP HTTP legacy receiver mem_limit: 2000m restart: on-failure @@ -93,7 +94,7 @@ services: max-file: "3" command: ["all"] environment: - - JAEGER_ENDPOINT=http://otel-collector:14268/api/traces + - JAEGER_ENDPOINT=http://otel-collector:14268/api/traces load-hotrod: image: "grubykarol/locust:1.2.3-python3.9-alpine3.12" diff --git a/deploy/docker/clickhouse-setup/docker-compose.yaml b/deploy/docker/clickhouse-setup/docker-compose.yaml index c161d1c4d4..b9c96c7bdb 100644 --- a/deploy/docker/clickhouse-setup/docker-compose.yaml +++ b/deploy/docker/clickhouse-setup/docker-compose.yaml @@ -17,20 +17,17 @@ services: alertmanager: image: signoz/alertmanager:0.6.0 volumes: - # we no longer need the config file as query services delivers - # the required config now - # - ./alertmanager.yml:/prometheus/alertmanager.yml - ./data/alertmanager:/data depends_on: - query-service command: - - '--queryService.url=http://query-service:8080' - - '--storage.path=/data' + - --queryService.url=http://query-service:8080 + - --storage.path=/data # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` query-service: - image: signoz/query-service:0.7.3 + image: signoz/query-service:0.7.4 container_name: query-service command: ["-config=/root/config/prometheus.yml"] volumes: @@ -43,14 +40,13 @@ services: - GODEBUG=netdns=go - TELEMETRY_ENABLED=true - DEPLOYMENT_TYPE=docker-standalone-amd - restart: on-failure depends_on: clickhouse: condition: service_healthy frontend: - image: signoz/frontend:0.7.3 + image: signoz/frontend:0.7.4 container_name: frontend depends_on: - query-service @@ -72,7 +68,7 @@ services: # - "14268:14268" # Jaeger receiver # - "55678:55678" # OpenCensus receiver # - "55679:55679" # zpages extension - # - "55680:55680" # OTLP gRPC legacy port + # - "55680:55680" # OTLP gRPC legacy receiver # - "55681:55681" # OTLP HTTP legacy receiver mem_limit: 2000m restart: on-failure diff --git a/pkg/query-service/tests/test-deploy/docker-compose.arm.yaml b/pkg/query-service/tests/test-deploy/docker-compose.arm.yaml index d231ab656b..0447c26a35 100644 --- a/pkg/query-service/tests/test-deploy/docker-compose.arm.yaml +++ b/pkg/query-service/tests/test-deploy/docker-compose.arm.yaml @@ -5,7 +5,6 @@ services: image: altinity/clickhouse-server:21.12.3.32.altinitydev.arm volumes: - ./clickhouse-config.xml:/etc/clickhouse-server/config.xml - - ./data/clickhouse/:/var/lib/clickhouse/ healthcheck: # "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'" test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"] @@ -14,13 +13,12 @@ services: retries: 3 alertmanager: - image: signoz/alertmanager:0.5.0 - volumes: - - ./alertmanager.yml:/prometheus/alertmanager.yml - - ./data/alertmanager:/data + image: signoz/alertmanager:0.6.0 + depends_on: + - query-service command: - - '--config.file=/prometheus/alertmanager.yml' - - '--storage.path=/data' + - --queryService.url=http://query-service:8080 + - --storage.path=/data query-service: image: signoz/query-service:latest @@ -29,9 +27,9 @@ services: volumes: - ./prometheus.yml:/root/config/prometheus.yml - ../dashboards:/root/config/dashboards - - ./data/signoz/:/var/lib/signoz/ + - ./data:/var/lib/signoz ports: - - "8180:8080" + - "8180:8080" environment: - ClickHouseUrl=tcp://clickhouse:9000 - STORAGE=clickhouse @@ -72,7 +70,7 @@ services: max-file: "3" command: ["all"] environment: - - JAEGER_ENDPOINT=http://otel-collector:14268/api/traces + - JAEGER_ENDPOINT=http://otel-collector:14268/api/traces load-hotrod: image: "grubykarol/locust:1.2.3-python3.9-alpine3.12" @@ -87,4 +85,4 @@ services: QUIET_MODE: "${QUIET_MODE:-false}" LOCUST_OPTS: "--headless -u 10 -r 1" volumes: - - ../common/locust-scripts:/locust + - ../../../../deploy/docker/common/locust-scripts:/locust diff --git a/pkg/query-service/tests/test-deploy/docker-compose.yaml b/pkg/query-service/tests/test-deploy/docker-compose.yaml index 2dbafff539..6edd31b63a 100644 --- a/pkg/query-service/tests/test-deploy/docker-compose.yaml +++ b/pkg/query-service/tests/test-deploy/docker-compose.yaml @@ -13,22 +13,25 @@ services: retries: 3 alertmanager: - image: signoz/alertmanager:0.5.0 - volumes: - - ./alertmanager.yml:/prometheus/alertmanager.yml + image: signoz/alertmanager:0.6.0 + depends_on: + - query-service command: - - '--config.file=/prometheus/alertmanager.yml' - - '--storage.path=/data' + - --queryService.url=http://query-service:8080 + - --storage.path=/data # Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md` - query-service: image: signoz/query-service:latest + container_name: query-service command: ["-config=/root/config/prometheus.yml"] volumes: - ./prometheus.yml:/root/config/prometheus.yml - ../dashboards:/root/config/dashboards + - ./data:/var/lib/signoz + ports: + - "8180:8080" environment: - ClickHouseUrl=tcp://clickhouse:9000 - STORAGE=clickhouse @@ -37,13 +40,6 @@ services: depends_on: clickhouse: condition: service_healthy - ports: - - "8180:8080" - volumes: - - type: bind - source: ./data - target: /var/lib/signoz - read_only: false otel-collector: image: signoz/otelcontribcol:0.43.0