mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-14 01:36:08 +08:00
Merge branch 'develop' into 417-search-filter
This commit is contained in:
commit
f57808bdb4
1
.github/CODEOWNERS
vendored
1
.github/CODEOWNERS
vendored
@ -4,3 +4,4 @@
|
|||||||
* @ankitnayan
|
* @ankitnayan
|
||||||
/frontend/ @palashgdev @pranshuchittora
|
/frontend/ @palashgdev @pranshuchittora
|
||||||
/deploy/ @prashant-shahi
|
/deploy/ @prashant-shahi
|
||||||
|
/pkg/query-service/ @srikanthccv @makeavish @nityanandagohain
|
||||||
|
2
.github/workflows/build.yaml
vendored
2
.github/workflows/build.yaml
vendored
@ -17,6 +17,8 @@ jobs:
|
|||||||
run: cd frontend && yarn install
|
run: cd frontend && yarn install
|
||||||
- name: Run ESLint
|
- name: Run ESLint
|
||||||
run: cd frontend && npm run lint
|
run: cd frontend && npm run lint
|
||||||
|
- name: Run Jest
|
||||||
|
run: cd frontend && npm run jest
|
||||||
- name: TSC
|
- name: TSC
|
||||||
run: yarn tsc
|
run: yarn tsc
|
||||||
working-directory: ./frontend
|
working-directory: ./frontend
|
||||||
|
@ -2,3 +2,4 @@
|
|||||||
* Adds custom matchers from the react testing library to all tests
|
* Adds custom matchers from the react testing library to all tests
|
||||||
*/
|
*/
|
||||||
import '@testing-library/jest-dom';
|
import '@testing-library/jest-dom';
|
||||||
|
import 'jest-styled-components';
|
||||||
|
@ -159,6 +159,7 @@
|
|||||||
"husky": "^7.0.4",
|
"husky": "^7.0.4",
|
||||||
"is-ci": "^3.0.1",
|
"is-ci": "^3.0.1",
|
||||||
"jest-playwright-preset": "^1.7.0",
|
"jest-playwright-preset": "^1.7.0",
|
||||||
|
"jest-styled-components": "^7.0.8",
|
||||||
"less-plugin-npm-import": "^2.1.0",
|
"less-plugin-npm-import": "^2.1.0",
|
||||||
"lint-staged": "^12.3.7",
|
"lint-staged": "^12.3.7",
|
||||||
"portfinder-sync": "^0.0.2",
|
"portfinder-sync": "^0.0.2",
|
||||||
|
@ -2,8 +2,102 @@
|
|||||||
|
|
||||||
exports[`Not Found page test should render Not Found page without errors 1`] = `
|
exports[`Not Found page test should render Not Found page without errors 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<div
|
.c3 {
|
||||||
class="sc-gsDKAQ cLXpIa"
|
border: 2px solid #2f80ed;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 10px;
|
||||||
|
width: 400px;
|
||||||
|
background: inherit;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 24px;
|
||||||
|
line-height: 20px;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding-top: 14px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
color: #2f80ed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c0 {
|
||||||
|
min-height: 80vh;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c2 {
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 300;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 20px;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
color: #828282;
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: center;
|
||||||
|
-webkit-justify-content: center;
|
||||||
|
-ms-flex-pack: center;
|
||||||
|
justify-content: center;
|
||||||
|
-webkit-align-items: center;
|
||||||
|
-webkit-box-align: center;
|
||||||
|
-ms-flex-align: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c1 {
|
||||||
|
min-height: 50px;
|
||||||
|
display: -webkit-box;
|
||||||
|
display: -webkit-flex;
|
||||||
|
display: -ms-flexbox;
|
||||||
|
display: flex;
|
||||||
|
-webkit-box-pack: justify;
|
||||||
|
-webkit-justify-content: space-between;
|
||||||
|
-ms-flex-pack: justify;
|
||||||
|
justify-content: space-between;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="c0"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
fill="none"
|
fill="none"
|
||||||
@ -272,21 +366,21 @@ exports[`Not Found page test should render Not Found page without errors 1`] = `
|
|||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
<div
|
<div
|
||||||
class="sc-hKwDye foaleg"
|
class="c1"
|
||||||
>
|
>
|
||||||
<p
|
<p
|
||||||
class="sc-dkPtRN fcyVIq"
|
class="c2"
|
||||||
>
|
>
|
||||||
Ah, seems like we reached a dead end!
|
Ah, seems like we reached a dead end!
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p
|
||||||
class="sc-dkPtRN fcyVIq"
|
class="c2"
|
||||||
>
|
>
|
||||||
Page Not Found
|
Page Not Found
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
class="sc-bdvvtL dbTZkj"
|
class="c3"
|
||||||
href="/application"
|
href="/application"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
>
|
>
|
||||||
|
@ -12,7 +12,7 @@ const ROUTES = {
|
|||||||
ALL_DASHBOARD: '/dashboard',
|
ALL_DASHBOARD: '/dashboard',
|
||||||
DASHBOARD: '/dashboard/:dashboardId',
|
DASHBOARD: '/dashboard/:dashboardId',
|
||||||
DASHBOARD_WIDGET: '/dashboard/:dashboardId/:widgetId',
|
DASHBOARD_WIDGET: '/dashboard/:dashboardId/:widgetId',
|
||||||
EDIT_ALERTS: '/alerts/edit/:ruleId',
|
EDIT_ALERTS: '/alerts/edit',
|
||||||
LIST_ALL_ALERT: '/alerts',
|
LIST_ALL_ALERT: '/alerts',
|
||||||
ALERTS_NEW: '/alerts/new',
|
ALERTS_NEW: '/alerts/new',
|
||||||
ALL_CHANNELS: '/settings/channels',
|
ALL_CHANNELS: '/settings/channels',
|
||||||
|
@ -57,7 +57,10 @@ function FullView({
|
|||||||
time: timePreferenceType,
|
time: timePreferenceType,
|
||||||
): { min: string | number; max: string | number } => {
|
): { min: string | number; max: string | number } => {
|
||||||
if (time === 'GLOBAL_TIME') {
|
if (time === 'GLOBAL_TIME') {
|
||||||
const minMax = GetMinMax(globalSelectedTime);
|
const minMax = GetMinMax(globalSelectedTime, [
|
||||||
|
minTime / 1000000,
|
||||||
|
maxTime / 1000000,
|
||||||
|
]);
|
||||||
return {
|
return {
|
||||||
min: convertToNanoSecondsToSecond(minMax.minTime / 1000),
|
min: convertToNanoSecondsToSecond(minMax.minTime / 1000),
|
||||||
max: convertToNanoSecondsToSecond(minMax.maxTime / 1000),
|
max: convertToNanoSecondsToSecond(minMax.maxTime / 1000),
|
||||||
|
@ -11,7 +11,6 @@ import React, { useCallback, useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { UseQueryResult } from 'react-query';
|
import { UseQueryResult } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { generatePath } from 'react-router-dom';
|
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import { ErrorResponse, SuccessResponse } from 'types/api';
|
import { ErrorResponse, SuccessResponse } from 'types/api';
|
||||||
import { Alerts } from 'types/api/alerts/getAll';
|
import { Alerts } from 'types/api/alerts/getAll';
|
||||||
@ -51,11 +50,7 @@ function ListAlert({ allAlertRules, refetch }: ListAlertProps): JSX.Element {
|
|||||||
const [notifications, Element] = notification.useNotification();
|
const [notifications, Element] = notification.useNotification();
|
||||||
|
|
||||||
const onEditHandler = (id: string): void => {
|
const onEditHandler = (id: string): void => {
|
||||||
history.push(
|
history.push(`${ROUTES.EDIT_ALERTS}?ruleId=${id}`);
|
||||||
generatePath(ROUTES.EDIT_ALERTS, {
|
|
||||||
ruleId: id,
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const columns: ColumnsType<Alerts> = [
|
const columns: ColumnsType<Alerts> = [
|
||||||
|
@ -15,7 +15,7 @@ const menus: SidebarMenu[] = [
|
|||||||
{
|
{
|
||||||
Icon: BarChartOutlined,
|
Icon: BarChartOutlined,
|
||||||
to: ROUTES.APPLICATION,
|
to: ROUTES.APPLICATION,
|
||||||
name: 'Metrics',
|
name: 'Services',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Icon: AlignLeftOutlined,
|
Icon: AlignLeftOutlined,
|
||||||
|
@ -16,6 +16,7 @@ const breadcrumbNameMap = {
|
|||||||
[ROUTES.ORG_SETTINGS]: 'Organization Settings',
|
[ROUTES.ORG_SETTINGS]: 'Organization Settings',
|
||||||
[ROUTES.MY_SETTINGS]: 'My Settings',
|
[ROUTES.MY_SETTINGS]: 'My Settings',
|
||||||
[ROUTES.ERROR_DETAIL]: 'Errors',
|
[ROUTES.ERROR_DETAIL]: 'Errors',
|
||||||
|
[ROUTES.LIST_ALL_ALERT]: 'Alerts',
|
||||||
};
|
};
|
||||||
|
|
||||||
function ShowBreadcrumbs(props: RouteComponentProps): JSX.Element {
|
function ShowBreadcrumbs(props: RouteComponentProps): JSX.Element {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Space, Tabs, Typography } from 'antd';
|
import { Tabs, Tooltip, Typography } from 'antd';
|
||||||
import { StyledSpace } from 'components/Styled';
|
import { StyledSpace } from 'components/Styled';
|
||||||
import useThemeMode from 'hooks/useThemeMode';
|
import useThemeMode from 'hooks/useThemeMode';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
import { ITraceTree } from 'types/api/trace/getTraceItem';
|
||||||
|
|
||||||
import ErrorTag from './ErrorTag';
|
import ErrorTag from './ErrorTag';
|
||||||
@ -19,29 +19,38 @@ const { TabPane } = Tabs;
|
|||||||
function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
function SelectedSpanDetails(props: SelectedSpanDetailsProps): JSX.Element {
|
||||||
const { tree } = props;
|
const { tree } = props;
|
||||||
const { isDarkMode } = useThemeMode();
|
const { isDarkMode } = useThemeMode();
|
||||||
|
|
||||||
|
const OverLayComponentName = useMemo(() => tree?.name, [tree?.name]);
|
||||||
|
const OverLayComponentServiceName = useMemo(() => tree?.serviceName, [
|
||||||
|
tree?.serviceName,
|
||||||
|
]);
|
||||||
|
|
||||||
if (!tree) {
|
if (!tree) {
|
||||||
return <div />;
|
return <div />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { name, tags, serviceName } = tree;
|
const { tags } = tree;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardContainer>
|
<CardContainer>
|
||||||
<StyledSpace
|
<StyledSpace
|
||||||
styledclass={[styles.selectedSpanDetailsContainer]}
|
styledclass={[styles.selectedSpanDetailsContainer, styles.overflow]}
|
||||||
direction="vertical"
|
direction="vertical"
|
||||||
style={{ marginLeft: '0.5rem' }}
|
style={{ marginLeft: '0.5rem' }}
|
||||||
>
|
>
|
||||||
<strong> Details for selected Span </strong>
|
<strong> Details for selected Span </strong>
|
||||||
<Space direction="vertical" size={2}>
|
|
||||||
<CustomTitle>Service</CustomTitle>
|
<CustomTitle>Service</CustomTitle>
|
||||||
<CustomText>{serviceName}</CustomText>
|
<Tooltip overlay={OverLayComponentServiceName}>
|
||||||
</Space>
|
<CustomText ellipsis>{tree.serviceName}</CustomText>
|
||||||
<Space direction="vertical" size={2}>
|
</Tooltip>
|
||||||
<CustomTitle>Operation</CustomTitle>
|
|
||||||
<CustomText>{name}</CustomText>
|
<CustomTitle>Operation</CustomTitle>
|
||||||
</Space>
|
<Tooltip overlay={OverLayComponentName}>
|
||||||
|
<CustomText ellipsis>{tree.name}</CustomText>
|
||||||
|
</Tooltip>
|
||||||
</StyledSpace>
|
</StyledSpace>
|
||||||
|
|
||||||
<Tabs defaultActiveKey="1">
|
<Tabs defaultActiveKey="1">
|
||||||
<TabPane tab="Tags" key="1">
|
<TabPane tab="Tags" key="1">
|
||||||
{tags.length !== 0 ? (
|
{tags.length !== 0 ? (
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Typography } from 'antd';
|
import { Space, Typography } from 'antd';
|
||||||
import styled, { css } from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
|
|
||||||
const { Text, Title, Paragraph } = Typography;
|
const { Title, Paragraph } = Typography;
|
||||||
|
|
||||||
export const CustomTitle = styled(Title)`
|
export const CustomTitle = styled(Title)`
|
||||||
&&& {
|
&&& {
|
||||||
@ -9,7 +9,7 @@ export const CustomTitle = styled(Title)`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CustomText = styled(Text)`
|
export const CustomText = styled(Paragraph)`
|
||||||
&&& {
|
&&& {
|
||||||
color: #2d9cdb;
|
color: #2d9cdb;
|
||||||
}
|
}
|
||||||
@ -17,7 +17,6 @@ export const CustomText = styled(Text)`
|
|||||||
|
|
||||||
export const CustomSubTitle = styled(Title)`
|
export const CustomSubTitle = styled(Title)`
|
||||||
&&& {
|
&&& {
|
||||||
/* color: #bdbdbd; */
|
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
@ -44,6 +43,17 @@ export const CardContainer = styled.div`
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const CustomSpace = styled(Space)`
|
||||||
|
&&& {
|
||||||
|
.ant-space-item {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const removeMargin = css`
|
const removeMargin = css`
|
||||||
@ -60,9 +70,21 @@ const selectedSpanDetailsContainer = css`
|
|||||||
const spanEventsTabsContainer = css`
|
const spanEventsTabsContainer = css`
|
||||||
margin-top: 1rem;
|
margin-top: 1rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
const overflow = css`
|
||||||
|
width: 95%;
|
||||||
|
|
||||||
|
> div.ant-space-item:nth-child(4) {
|
||||||
|
overflow-x: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const styles = {
|
export const styles = {
|
||||||
removeMargin,
|
removeMargin,
|
||||||
removePadding,
|
removePadding,
|
||||||
selectedSpanDetailsContainer,
|
selectedSpanDetailsContainer,
|
||||||
spanEventsTabsContainer,
|
spanEventsTabsContainer,
|
||||||
|
overflow,
|
||||||
};
|
};
|
||||||
|
@ -2,12 +2,30 @@
|
|||||||
|
|
||||||
exports[`loads and displays greeting 1`] = `
|
exports[`loads and displays greeting 1`] = `
|
||||||
<DocumentFragment>
|
<DocumentFragment>
|
||||||
<div
|
.c1 {
|
||||||
class="sc-gsDKAQ jFDWPs"
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: NaN%;
|
||||||
|
width: Infinity%;
|
||||||
|
height: 10px;
|
||||||
|
margin: 1px 0;
|
||||||
|
background-color: hsl(282.9,100%,60.7%);
|
||||||
|
border-radius: 5px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c0 {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="c0"
|
||||||
height="0"
|
height="0"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="sc-bdvvtL fyFVjh"
|
class="c1"
|
||||||
title=""
|
title=""
|
||||||
width="Infinity"
|
width="Infinity"
|
||||||
/>
|
/>
|
||||||
|
@ -1,23 +1,45 @@
|
|||||||
|
import { notification } from 'antd';
|
||||||
import get from 'api/alerts/get';
|
import get from 'api/alerts/get';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
|
import ROUTES from 'constants/routes';
|
||||||
import EditRulesContainer from 'container/EditRules';
|
import EditRulesContainer from 'container/EditRules';
|
||||||
import React from 'react';
|
import history from 'lib/history';
|
||||||
|
import React, { useEffect } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { useParams } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
function EditRules(): JSX.Element {
|
function EditRules(): JSX.Element {
|
||||||
const { ruleId } = useParams<EditRulesParam>();
|
const { search } = useLocation();
|
||||||
|
const params = new URLSearchParams(search);
|
||||||
|
const ruleId = params.get('ruleId');
|
||||||
|
|
||||||
const { t } = useTranslation('common');
|
const { t } = useTranslation('common');
|
||||||
|
|
||||||
|
const isValidRuleId = ruleId !== null && String(ruleId).length !== 0;
|
||||||
|
|
||||||
const { isLoading, data, isError } = useQuery(['ruleId', ruleId], {
|
const { isLoading, data, isError } = useQuery(['ruleId', ruleId], {
|
||||||
queryFn: () =>
|
queryFn: () =>
|
||||||
get({
|
get({
|
||||||
id: parseInt(ruleId, 10),
|
id: parseInt(ruleId || '', 10),
|
||||||
}),
|
}),
|
||||||
|
enabled: isValidRuleId,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isError) {
|
useEffect(() => {
|
||||||
|
if (!isValidRuleId) {
|
||||||
|
notification.error({
|
||||||
|
message: 'Rule Id is required',
|
||||||
|
});
|
||||||
|
history.replace(ROUTES.LIST_ALL_ALERT);
|
||||||
|
}
|
||||||
|
}, [isValidRuleId, ruleId]);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(isError && !isValidRuleId) ||
|
||||||
|
ruleId == null ||
|
||||||
|
(data?.payload?.data === undefined && !isLoading)
|
||||||
|
) {
|
||||||
return <div>{data?.error || t('something_went_wrong')}</div>;
|
return <div>{data?.error || t('something_went_wrong')}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,8 +50,4 @@ function EditRules(): JSX.Element {
|
|||||||
return <EditRulesContainer ruleId={ruleId} initialData={data.payload.data} />;
|
return <EditRulesContainer ruleId={ruleId} initialData={data.payload.data} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface EditRulesParam {
|
|
||||||
ruleId: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default EditRules;
|
export default EditRules;
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
"playwright.config.ts",
|
"playwright.config.ts",
|
||||||
"./commitlint.config.js",
|
"./commitlint.config.js",
|
||||||
"./webpack.config.js",
|
"./webpack.config.js",
|
||||||
"./webpack.config.prod.js"
|
"./webpack.config.prod.js",
|
||||||
|
"./jest.setup.ts"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -8128,6 +8128,13 @@ jest-snapshot@^27.5.1:
|
|||||||
pretty-format "^27.5.1"
|
pretty-format "^27.5.1"
|
||||||
semver "^7.3.2"
|
semver "^7.3.2"
|
||||||
|
|
||||||
|
jest-styled-components@^7.0.8:
|
||||||
|
version "7.0.8"
|
||||||
|
resolved "https://registry.yarnpkg.com/jest-styled-components/-/jest-styled-components-7.0.8.tgz#9ea3b43f002de060b4638fde3b422d14b3e3ec9f"
|
||||||
|
integrity sha512-0KE54d0yIzKcvtOv8eikyjG3rFRtKYUyQovaoha3nondtZzXYGB3bhsvYgEegU08Iry0ndWx2+g9f5ZzD4I+0Q==
|
||||||
|
dependencies:
|
||||||
|
css "^3.0.0"
|
||||||
|
|
||||||
jest-util@^26.6.2:
|
jest-util@^26.6.2:
|
||||||
version "26.6.2"
|
version "26.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1"
|
resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1"
|
||||||
|
@ -592,21 +592,45 @@ func (r *ClickHouseReader) GetRulesFromDB() (*[]model.RuleResponseItem, *model.A
|
|||||||
|
|
||||||
func (r *ClickHouseReader) GetRule(id string) (*model.RuleResponseItem, *model.ApiError) {
|
func (r *ClickHouseReader) GetRule(id string) (*model.RuleResponseItem, *model.ApiError) {
|
||||||
|
|
||||||
idInt, _ := strconv.Atoi(id)
|
idInt, err := strconv.Atoi(id)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Debug("Error in parsing param: ", err)
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorBadData, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
rule := &model.RuleResponseItem{}
|
rule := &model.RuleResponseItem{}
|
||||||
|
|
||||||
query := fmt.Sprintf("SELECT id, updated_at, data FROM rules WHERE id=%d", idInt)
|
query := "SELECT id, updated_at, data FROM rules WHERE id=?"
|
||||||
|
rows, err := r.localDB.Query(query, idInt)
|
||||||
err := r.localDB.Get(rule, query)
|
|
||||||
|
|
||||||
zap.S().Info(query)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
zap.S().Debug("Error in processing sql query: ", err)
|
zap.S().Debug("Error in processing sql query: ", err)
|
||||||
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
count := 0
|
||||||
|
// iterate over each row
|
||||||
|
for rows.Next() {
|
||||||
|
err = rows.Scan(&rule.Id, &rule.UpdatedAt, &rule.Data)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Debug(err)
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorInternal, Err: err}
|
||||||
|
}
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if count == 0 {
|
||||||
|
err = fmt.Errorf("no rule with id %d found", idInt)
|
||||||
|
zap.S().Debug(err)
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorNotFound, Err: err}
|
||||||
|
}
|
||||||
|
if count > 1 {
|
||||||
|
err = fmt.Errorf("multiple rules with id %d found", idInt)
|
||||||
|
zap.S().Debug(err)
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorConflict, Err: err}
|
||||||
|
}
|
||||||
|
|
||||||
return rule, nil
|
return rule, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user