mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-15 11:45:53 +08:00
fix: merge conflict removed
This commit is contained in:
commit
f084637f84
@ -106,28 +106,39 @@ Need to update [https://github.com/SigNoz/charts](https://github.com/SigNoz/char
|
|||||||
- [k3d](https://k3d.io/#installation)
|
- [k3d](https://k3d.io/#installation)
|
||||||
- [minikube](https://minikube.sigs.k8s.io/docs/start/)
|
- [minikube](https://minikube.sigs.k8s.io/docs/start/)
|
||||||
- create a k8s cluster and make sure `kubectl` points to the locally created k8s cluster
|
- create a k8s cluster and make sure `kubectl` points to the locally created k8s cluster
|
||||||
- run `helm install -n platform --create-namespace my-release charts/signoz` to install SigNoz chart
|
- run `make dev-install` to install SigNoz chart with `my-release` release name in `platform` namespace.
|
||||||
- run `kubectl -n platform port-forward svc/my-release-frontend 3301:3301` to make SigNoz UI available at [localhost:3301](http://localhost:3301)
|
- run `kubectl -n platform port-forward svc/my-release-signoz-frontend 3301:3301` to make SigNoz UI available at [localhost:3301](http://localhost:3301)
|
||||||
|
|
||||||
|
**To install HotROD sample app:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sL https://github.com/SigNoz/signoz/raw/main/sample-apps/hotrod/hotrod-install.sh \
|
||||||
|
| HELM_RELEASE=my-release SIGNOZ_NAMESPACE=platform bash
|
||||||
|
```
|
||||||
|
|
||||||
**To load data with HotROD sample app:**
|
**To load data with HotROD sample app:**
|
||||||
|
|
||||||
```sh
|
```bash
|
||||||
kubectl create ns sample-application
|
|
||||||
|
|
||||||
kubectl -n sample-application apply -f https://raw.githubusercontent.com/SigNoz/signoz/main/sample-apps/hotrod/hotrod.yaml
|
|
||||||
|
|
||||||
kubectl -n sample-application run strzal --image=djbingham/curl \
|
kubectl -n sample-application run strzal --image=djbingham/curl \
|
||||||
--restart='OnFailure' -i --tty --rm --command -- curl -X POST -F \
|
--restart='OnFailure' -i --tty --rm --command -- curl -X POST -F \
|
||||||
'locust_count=6' -F 'hatch_rate=2' http://locust-master:8089/swarm
|
'locust_count=6' -F 'hatch_rate=2' http://locust-master:8089/swarm
|
||||||
```
|
```
|
||||||
|
|
||||||
**To stop the load generation:**
|
**To stop the load generation:**
|
||||||
|
|
||||||
```sh
|
```bash
|
||||||
kubectl -n sample-application run strzal --image=djbingham/curl \
|
kubectl -n sample-application run strzal --image=djbingham/curl \
|
||||||
--restart='OnFailure' -i --tty --rm --command -- curl \
|
--restart='OnFailure' -i --tty --rm --command -- curl \
|
||||||
http://locust-master:8089/stop
|
http://locust-master:8089/stop
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**To delete HotROD sample app:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sL https://github.com/SigNoz/signoz/raw/main/sample-apps/hotrod/hotrod-delete.sh \
|
||||||
|
| HOTROD_NAMESPACE=sample-application bash
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## General Instructions
|
## General Instructions
|
||||||
|
@ -39,8 +39,9 @@ services:
|
|||||||
query-service:
|
query-service:
|
||||||
image: signoz/query-service:0.8.0
|
image: signoz/query-service:0.8.0
|
||||||
command: ["-config=/root/config/prometheus.yml"]
|
command: ["-config=/root/config/prometheus.yml"]
|
||||||
ports:
|
# ports:
|
||||||
- "8080:8080"
|
# - "6060:6060" # pprof port
|
||||||
|
# - "8080:8080" # query-service port
|
||||||
volumes:
|
volumes:
|
||||||
- ./prometheus.yml:/root/config/prometheus.yml
|
- ./prometheus.yml:/root/config/prometheus.yml
|
||||||
- ../dashboards:/root/config/dashboards
|
- ../dashboards:/root/config/dashboards
|
||||||
@ -85,7 +86,7 @@ services:
|
|||||||
- "4317:4317" # OTLP gRPC receiver
|
- "4317:4317" # OTLP gRPC receiver
|
||||||
- "4318:4318" # OTLP HTTP receiver
|
- "4318:4318" # OTLP HTTP receiver
|
||||||
# - "8889:8889" # Prometheus metrics exposed by the agent
|
# - "8889:8889" # Prometheus metrics exposed by the agent
|
||||||
# - "13133" # health_check
|
# - "13133:13133" # health_check
|
||||||
# - "14268:14268" # Jaeger receiver
|
# - "14268:14268" # Jaeger receiver
|
||||||
# - "55678:55678" # OpenCensus receiver
|
# - "55678:55678" # OpenCensus receiver
|
||||||
# - "55679:55679" # zpages extension
|
# - "55679:55679" # zpages extension
|
||||||
|
@ -12,13 +12,18 @@ server {
|
|||||||
gzip_http_version 1.1;
|
gzip_http_version 1.1;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0";
|
if ( $uri = '/index.html' ) {
|
||||||
add_header Last-Modified $date_gmt;
|
add_header Cache-Control no-store always;
|
||||||
|
}
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /api/alertmanager {
|
||||||
|
proxy_pass http://alertmanager:9093/api/v2;
|
||||||
|
}
|
||||||
|
|
||||||
location /api {
|
location /api {
|
||||||
proxy_pass http://query-service:8080/api;
|
proxy_pass http://query-service:8080/api;
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,9 @@ services:
|
|||||||
image: signoz/query-service:0.8.0
|
image: signoz/query-service:0.8.0
|
||||||
container_name: query-service
|
container_name: query-service
|
||||||
command: ["-config=/root/config/prometheus.yml"]
|
command: ["-config=/root/config/prometheus.yml"]
|
||||||
|
# ports:
|
||||||
|
# - "6060:6060" # pprof port
|
||||||
|
# - "8080:8080" # query-service port
|
||||||
volumes:
|
volumes:
|
||||||
- ./prometheus.yml:/root/config/prometheus.yml
|
- ./prometheus.yml:/root/config/prometheus.yml
|
||||||
- ../dashboards:/root/config/dashboards
|
- ../dashboards:/root/config/dashboards
|
||||||
@ -82,7 +85,7 @@ services:
|
|||||||
- "4317:4317" # OTLP gRPC receiver
|
- "4317:4317" # OTLP gRPC receiver
|
||||||
- "4318:4318" # OTLP HTTP receiver
|
- "4318:4318" # OTLP HTTP receiver
|
||||||
# - "8889:8889" # Prometheus metrics exposed by the agent
|
# - "8889:8889" # Prometheus metrics exposed by the agent
|
||||||
# - "13133" # health_check
|
# - "13133:13133" # health_check
|
||||||
# - "14268:14268" # Jaeger receiver
|
# - "14268:14268" # Jaeger receiver
|
||||||
# - "55678:55678" # OpenCensus receiver
|
# - "55678:55678" # OpenCensus receiver
|
||||||
# - "55679:55679" # zpages extension
|
# - "55679:55679" # zpages extension
|
||||||
|
@ -39,6 +39,9 @@ services:
|
|||||||
image: signoz/query-service:0.8.0
|
image: signoz/query-service:0.8.0
|
||||||
container_name: query-service
|
container_name: query-service
|
||||||
command: ["-config=/root/config/prometheus.yml"]
|
command: ["-config=/root/config/prometheus.yml"]
|
||||||
|
# ports:
|
||||||
|
# - "6060:6060" # pprof port
|
||||||
|
# - "8080:8080" # query-service port
|
||||||
volumes:
|
volumes:
|
||||||
- ./prometheus.yml:/root/config/prometheus.yml
|
- ./prometheus.yml:/root/config/prometheus.yml
|
||||||
- ../dashboards:/root/config/dashboards
|
- ../dashboards:/root/config/dashboards
|
||||||
@ -80,7 +83,7 @@ services:
|
|||||||
- "4317:4317" # OTLP gRPC receiver
|
- "4317:4317" # OTLP gRPC receiver
|
||||||
- "4318:4318" # OTLP HTTP receiver
|
- "4318:4318" # OTLP HTTP receiver
|
||||||
# - "8889:8889" # Prometheus metrics exposed by the agent
|
# - "8889:8889" # Prometheus metrics exposed by the agent
|
||||||
# - "13133" # health_check
|
# - "13133:13133" # health_check
|
||||||
# - "14268:14268" # Jaeger receiver
|
# - "14268:14268" # Jaeger receiver
|
||||||
# - "55678:55678" # OpenCensus receiver
|
# - "55678:55678" # OpenCensus receiver
|
||||||
# - "55679:55679" # zpages extension
|
# - "55679:55679" # zpages extension
|
||||||
|
@ -12,14 +12,15 @@ server {
|
|||||||
gzip_http_version 1.1;
|
gzip_http_version 1.1;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
add_header Cache-Control "no-store, no-cache, must-revalidate, max-age=0";
|
if ( $uri = '/index.html' ) {
|
||||||
add_header Last-Modified $date_gmt;
|
add_header Cache-Control no-store always;
|
||||||
|
}
|
||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html index.htm;
|
index index.html index.htm;
|
||||||
try_files $uri $uri/ /index.html;
|
try_files $uri $uri/ /index.html;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /api/alertmanager{
|
location /api/alertmanager {
|
||||||
proxy_pass http://alertmanager:9093/api/v2;
|
proxy_pass http://alertmanager:9093/api/v2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
frontend/.husky/commit-msg
Executable file
4
frontend/.husky/commit-msg
Executable file
@ -0,0 +1,4 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
. "$(dirname "$0")/_/husky.sh"
|
||||||
|
|
||||||
|
cd frontend && npm run commitlint
|
@ -12,6 +12,9 @@ WORKDIR /frontend
|
|||||||
# copy the package.json to install dependencies
|
# copy the package.json to install dependencies
|
||||||
COPY package.json ./
|
COPY package.json ./
|
||||||
|
|
||||||
|
# configure node_env as production
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
# Install the dependencies and make the folder
|
# Install the dependencies and make the folder
|
||||||
RUN yarn install
|
RUN yarn install
|
||||||
|
|
||||||
|
1
frontend/commitlint.config.js
Normal file
1
frontend/commitlint.config.js
Normal file
@ -0,0 +1 @@
|
|||||||
|
module.exports = { extends: ['@commitlint/config-conventional'] };
|
@ -1,8 +1,8 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
||||||
import {
|
import {
|
||||||
getDefaultOption,
|
getDefaultOption,
|
||||||
getOptions,
|
getOptions,
|
||||||
} from 'container/Header/DateTimeSelection/config';
|
} from 'container/TopNav/DateTimeSelection/config';
|
||||||
// import { AppState } from 'store/reducers';
|
|
||||||
|
|
||||||
const CheckRouteDefaultGlobalTimeOptions = ({
|
const CheckRouteDefaultGlobalTimeOptions = ({
|
||||||
route,
|
route,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
|
@ -26,7 +26,7 @@ describe('Global Time Metrics Application', () => {
|
|||||||
|
|
||||||
cy.wait('@defaultApps');
|
cy.wait('@defaultApps');
|
||||||
|
|
||||||
//clicking on frontend
|
// clicking on frontend
|
||||||
cy.get('tr:nth-child(1) > td:first-child').click();
|
cy.get('tr:nth-child(1) > td:first-child').click();
|
||||||
|
|
||||||
cy
|
cy
|
||||||
@ -64,7 +64,7 @@ describe('Global Time Metrics Application', () => {
|
|||||||
|
|
||||||
cy.wait('@topEndPoints');
|
cy.wait('@topEndPoints');
|
||||||
cy.wait('@serviceOverview');
|
cy.wait('@serviceOverview');
|
||||||
//TODO add errorPercentage also
|
// TODO add errorPercentage also
|
||||||
// cy.wait('@errorPercentage');
|
// cy.wait('@errorPercentage');
|
||||||
cy.wait('@requestPerSecond');
|
cy.wait('@requestPerSecond');
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ describe('Metrics', () => {
|
|||||||
parseFloat(errorRate.toString()).toFixed(2),
|
parseFloat(errorRate.toString()).toFixed(2),
|
||||||
);
|
);
|
||||||
expect(rpsName).to.be.equals(callRate.toString());
|
expect(rpsName).to.be.equals(callRate.toString());
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -16,7 +16,7 @@ describe('Alerts', () => {
|
|||||||
})
|
})
|
||||||
.as('defaultRules');
|
.as('defaultRules');
|
||||||
|
|
||||||
cy.visit(Cypress.env('baseUrl') + `${ROUTES.LIST_ALL_ALERT}`);
|
cy.visit(`${Cypress.env('baseUrl')}${ROUTES.LIST_ALL_ALERT}`);
|
||||||
|
|
||||||
cy.wait('@defaultRules');
|
cy.wait('@defaultRules');
|
||||||
});
|
});
|
||||||
@ -97,7 +97,7 @@ describe('Alerts', () => {
|
|||||||
|
|
||||||
const defaultLabels = defaultRules.data.rules[index].labels;
|
const defaultLabels = defaultRules.data.rules[index].labels;
|
||||||
|
|
||||||
expect(label).to.be.equals(defaultLabels['severity']);
|
expect(label).to.be.equals(defaultLabels.severity);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-unused-expressions */
|
||||||
/* eslint-disable sonarjs/no-duplicate-string */
|
/* eslint-disable sonarjs/no-duplicate-string */
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
@ -33,7 +34,7 @@ describe('Trace', () => {
|
|||||||
})
|
})
|
||||||
.as('Filters');
|
.as('Filters');
|
||||||
|
|
||||||
cy.visit(Cypress.env('baseUrl') + `${ROUTES.TRACE}`);
|
cy.visit(`${Cypress.env('baseUrl')}${ROUTES.TRACE}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('First Initial Load should go with 3 AJAX request', () => {
|
it('First Initial Load should go with 3 AJAX request', () => {
|
||||||
|
@ -4,9 +4,6 @@
|
|||||||
"lib": ["es5", "dom"],
|
"lib": ["es5", "dom"],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
// be explicit about types included
|
|
||||||
// to avoid clashing with Jest types
|
|
||||||
"types": ["cypress", "@testing-library/cypress", "node"],
|
|
||||||
"isolatedModules": false
|
"isolatedModules": false
|
||||||
},
|
},
|
||||||
"include": ["../node_modules/cypress", "./**/*.ts"]
|
"include": ["../node_modules/cypress", "./**/*.ts"]
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
"jest:coverage": "jest --coverage",
|
"jest:coverage": "jest --coverage",
|
||||||
"jest:watch": "jest --watch",
|
"jest:watch": "jest --watch",
|
||||||
"postinstall": "yarn husky:configure",
|
"postinstall": "yarn husky:configure",
|
||||||
"husky:configure": "cd .. && husky install frontend/.husky"
|
"husky:configure": "cd .. && husky install frontend/.husky && cd frontend && chmod ug+x .husky/*",
|
||||||
|
"commitlint": "commitlint --edit $1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=12.13.0"
|
"node": ">=12.13.0"
|
||||||
@ -109,6 +110,8 @@
|
|||||||
"@babel/preset-env": "^7.12.17",
|
"@babel/preset-env": "^7.12.17",
|
||||||
"@babel/preset-react": "^7.12.13",
|
"@babel/preset-react": "^7.12.13",
|
||||||
"@babel/preset-typescript": "^7.12.17",
|
"@babel/preset-typescript": "^7.12.17",
|
||||||
|
"@commitlint/cli": "^16.2.4",
|
||||||
|
"@commitlint/config-conventional": "^16.2.4",
|
||||||
"@jest/globals": "^27.5.1",
|
"@jest/globals": "^27.5.1",
|
||||||
"@testing-library/cypress": "^8.0.0",
|
"@testing-library/cypress": "^8.0.0",
|
||||||
"@testing-library/react-hooks": "^7.0.2",
|
"@testing-library/react-hooks": "^7.0.2",
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import { notification } from 'antd';
|
import { notification } from 'antd';
|
||||||
import getLocalStorageApi from 'api/browser/localstorage/get';
|
import getLocalStorageApi from 'api/browser/localstorage/get';
|
||||||
import loginApi from 'api/user/login';
|
import loginApi from 'api/user/login';
|
||||||
|
import { Logout } from 'api/utils';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import { LOCALSTORAGE } from 'constants/localStorage';
|
import { LOCALSTORAGE } from 'constants/localStorage';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
@ -103,7 +104,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
|
|||||||
history.push(ROUTES.UN_AUTHORIZED);
|
history.push(ROUTES.UN_AUTHORIZED);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
history.push(ROUTES.SOMETHING_WENT_WRONG);
|
Logout();
|
||||||
|
|
||||||
notification.error({
|
notification.error({
|
||||||
message: response.error || t('something_went_wrong'),
|
message: response.error || t('something_went_wrong'),
|
||||||
|
@ -5,6 +5,7 @@ import history from 'lib/history';
|
|||||||
import store from 'store';
|
import store from 'store';
|
||||||
import {
|
import {
|
||||||
LOGGED_IN,
|
LOGGED_IN,
|
||||||
|
UPDATE_ORG,
|
||||||
UPDATE_USER,
|
UPDATE_USER,
|
||||||
UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
|
UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
|
||||||
UPDATE_USER_ORG_ROLE,
|
UPDATE_USER_ORG_ROLE,
|
||||||
@ -51,5 +52,12 @@ export const Logout = (): void => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
store.dispatch({
|
||||||
|
type: UPDATE_ORG,
|
||||||
|
payload: {
|
||||||
|
org: [],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
history.push(ROUTES.LOGIN);
|
history.push(ROUTES.LOGIN);
|
||||||
};
|
};
|
||||||
|
@ -3,4 +3,5 @@ export const ENVIRONMENT = {
|
|||||||
process?.env?.FRONTEND_API_ENDPOINT ||
|
process?.env?.FRONTEND_API_ENDPOINT ||
|
||||||
process?.env?.GITPOD_WORKSPACE_URL?.replace('://', '://8080-') ||
|
process?.env?.GITPOD_WORKSPACE_URL?.replace('://', '://8080-') ||
|
||||||
'',
|
'',
|
||||||
|
NODE_ENV: process?.env?.NODE_ENV,
|
||||||
};
|
};
|
||||||
|
@ -18,7 +18,7 @@ const ROUTES = {
|
|||||||
ALL_CHANNELS: '/settings/channels',
|
ALL_CHANNELS: '/settings/channels',
|
||||||
CHANNELS_NEW: '/setting/channels/new',
|
CHANNELS_NEW: '/setting/channels/new',
|
||||||
CHANNELS_EDIT: '/setting/channels/edit/:id',
|
CHANNELS_EDIT: '/setting/channels/edit/:id',
|
||||||
ALL_ERROR: '/errors',
|
ALL_ERROR: '/exceptions',
|
||||||
ERROR_DETAIL: '/error-detail',
|
ERROR_DETAIL: '/error-detail',
|
||||||
VERSION: '/status',
|
VERSION: '/status',
|
||||||
MY_SETTINGS: '/my-settings',
|
MY_SETTINGS: '/my-settings',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { notification, Table, Typography } from 'antd';
|
import { notification, Table, Tooltip, Typography } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
import getAll from 'api/errors/getAll';
|
import getAll from 'api/errors/getAll';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
@ -47,11 +47,13 @@ function AllErrors(): JSX.Element {
|
|||||||
dataIndex: 'exceptionType',
|
dataIndex: 'exceptionType',
|
||||||
key: 'exceptionType',
|
key: 'exceptionType',
|
||||||
render: (value, record): JSX.Element => (
|
render: (value, record): JSX.Element => (
|
||||||
|
<Tooltip overlay={(): JSX.Element => value}>
|
||||||
<Link
|
<Link
|
||||||
to={`${ROUTES.ERROR_DETAIL}?serviceName=${record.serviceName}&errorType=${record.exceptionType}`}
|
to={`${ROUTES.ERROR_DETAIL}?serviceName=${record.serviceName}&errorType=${record.exceptionType}`}
|
||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</Link>
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
),
|
),
|
||||||
sorter: (a, b): number =>
|
sorter: (a, b): number =>
|
||||||
a.exceptionType.charCodeAt(0) - b.exceptionType.charCodeAt(0),
|
a.exceptionType.charCodeAt(0) - b.exceptionType.charCodeAt(0),
|
||||||
@ -61,6 +63,7 @@ function AllErrors(): JSX.Element {
|
|||||||
dataIndex: 'exceptionMessage',
|
dataIndex: 'exceptionMessage',
|
||||||
key: 'exceptionMessage',
|
key: 'exceptionMessage',
|
||||||
render: (value): JSX.Element => (
|
render: (value): JSX.Element => (
|
||||||
|
<Tooltip overlay={(): JSX.Element => value}>
|
||||||
<Typography.Paragraph
|
<Typography.Paragraph
|
||||||
ellipsis={{
|
ellipsis={{
|
||||||
rows: 2,
|
rows: 2,
|
||||||
@ -68,6 +71,7 @@ function AllErrors(): JSX.Element {
|
|||||||
>
|
>
|
||||||
{value}
|
{value}
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
|
</Tooltip>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@ function GridCardGraph({
|
|||||||
.map(async (query) => {
|
.map(async (query) => {
|
||||||
const result = await getQueryResult({
|
const result = await getQueryResult({
|
||||||
end,
|
end,
|
||||||
query: query.query,
|
query: encodeURIComponent(query.query),
|
||||||
start,
|
start,
|
||||||
step: '60',
|
step: '60',
|
||||||
});
|
});
|
||||||
|
@ -28,6 +28,7 @@ function GridGraph(): JSX.Element {
|
|||||||
const { dashboards, loading } = useSelector<AppState, DashboardReducer>(
|
const { dashboards, loading } = useSelector<AppState, DashboardReducer>(
|
||||||
(state) => state.dashboards,
|
(state) => state.dashboards,
|
||||||
);
|
);
|
||||||
|
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
const [saveLayoutState, setSaveLayoutState] = useState<State>({
|
const [saveLayoutState, setSaveLayoutState] = useState<State>({
|
||||||
loading: false,
|
loading: false,
|
||||||
error: false,
|
error: false,
|
||||||
@ -251,8 +252,13 @@ function GridGraph(): JSX.Element {
|
|||||||
const isQueryType = type === 'VALUE';
|
const isQueryType = type === 'VALUE';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CardContainer key={rest.i} data-grid={rest}>
|
<CardContainer
|
||||||
<Card isQueryType={isQueryType}>
|
isQueryType={isQueryType}
|
||||||
|
isDarkMode={isDarkMode}
|
||||||
|
key={rest.i}
|
||||||
|
data-grid={rest}
|
||||||
|
>
|
||||||
|
<Card isDarkMode={isDarkMode} isQueryType={isQueryType}>
|
||||||
<Component />
|
<Component />
|
||||||
</Card>
|
</Card>
|
||||||
</CardContainer>
|
</CardContainer>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Button as ButtonComponent, Card as CardComponent } from 'antd';
|
import { Button as ButtonComponent, Card as CardComponent } from 'antd';
|
||||||
|
import { StyledCSS } from 'container/GantChart/Trace/styles';
|
||||||
import RGL, { WidthProvider } from 'react-grid-layout';
|
import RGL, { WidthProvider } from 'react-grid-layout';
|
||||||
import styled from 'styled-components';
|
import styled, { css } from 'styled-components';
|
||||||
|
|
||||||
const ReactGridLayoutComponent = WidthProvider(RGL);
|
const ReactGridLayoutComponent = WidthProvider(RGL);
|
||||||
|
|
||||||
@ -18,20 +19,34 @@ export const Card = styled(CardComponent)<Props>`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const CardContainer = styled.div`
|
interface Props {
|
||||||
|
isDarkMode: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CardContainer = styled.div<Props>`
|
||||||
|
:hover {
|
||||||
.react-resizable-handle {
|
.react-resizable-handle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/Pg08IS0tIEdlbmVyYXRvcjogQWRvYmUgRmlyZXdvcmtzIENTNiwgRXhwb3J0IFNWRyBFeHRlbnNpb24gYnkgQWFyb24gQmVhbGwgKGh0dHA6Ly9maXJld29ya3MuYWJlYWxsLmNvbSkgLiBWZXJzaW9uOiAwLjYuMSAgLS0+DTwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+DTxzdmcgaWQ9IlVudGl0bGVkLVBhZ2UlMjAxIiB2aWV3Qm94PSIwIDAgNiA2IiBzdHlsZT0iYmFja2dyb3VuZC1jb2xvcjojZmZmZmZmMDAiIHZlcnNpb249IjEuMSINCXhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHhtbDpzcGFjZT0icHJlc2VydmUiDQl4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjZweCIgaGVpZ2h0PSI2cHgiDT4NCTxnIG9wYWNpdHk9IjAuMzAyIj4NCQk8cGF0aCBkPSJNIDYgNiBMIDAgNiBMIDAgNC4yIEwgNCA0LjIgTCA0LjIgNC4yIEwgNC4yIDAgTCA2IDAgTCA2IDYgTCA2IDYgWiIgZmlsbD0iIzAwMDAwMCIvPg0JPC9nPg08L3N2Zz4=');
|
|
||||||
background-position: bottom right;
|
background-position: bottom right;
|
||||||
padding: 0 3px 3px 0;
|
padding: 0 3px 3px 0;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-origin: content-box;
|
background-origin: content-box;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
cursor: se-resize;
|
cursor: se-resize;
|
||||||
|
|
||||||
|
${({ isDarkMode }): StyledCSS => {
|
||||||
|
const uri = `data:image/svg+xml,%3Csvg viewBox='0 0 6 6' style='background-color:%23ffffff00' version='1.1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xml:space='preserve' x='0px' y='0px' width='6px' height='6px'%0A%3E%3Cg opacity='0.302'%3E%3Cpath d='M 6 6 L 0 6 L 0 4.2 L 4 4.2 L 4.2 4.2 L 4.2 0 L 6 0 L 6 6 L 6 6 Z' fill='${
|
||||||
|
isDarkMode ? 'white' : 'grey'
|
||||||
|
}'/%3E%3C/g%3E%3C/svg%3E`;
|
||||||
|
|
||||||
|
return css`
|
||||||
|
background-image: ${(): string => `url("${uri}")`};
|
||||||
|
`;
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
function IsRouteAccessible(): JSX.Element {
|
|
||||||
return <div>asd</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default IsRouteAccessible;
|
|
@ -1,6 +1,7 @@
|
|||||||
|
import { notification } from 'antd';
|
||||||
import getAll from 'api/alerts/getAll';
|
import getAll from 'api/alerts/getAll';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import React from 'react';
|
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';
|
||||||
|
|
||||||
@ -8,15 +9,37 @@ import ListAlert from './ListAlert';
|
|||||||
|
|
||||||
function ListAlertRules(): JSX.Element {
|
function ListAlertRules(): JSX.Element {
|
||||||
const { t } = useTranslation('common');
|
const { t } = useTranslation('common');
|
||||||
const { data, isError, isLoading, refetch } = useQuery('allAlerts', {
|
const { data, isError, isLoading, refetch, status } = useQuery('allAlerts', {
|
||||||
queryFn: getAll,
|
queryFn: getAll,
|
||||||
cacheTime: 0,
|
cacheTime: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (status === 'error' || (status === 'success' && data.statusCode >= 400)) {
|
||||||
|
notification.error({
|
||||||
|
message: data?.error || t('something_went_wrong'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [data?.error, data?.statusCode, status, t]);
|
||||||
|
|
||||||
|
// api failed to load the data
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return <div>{data?.error || t('something_went_wrong')}</div>;
|
return <div>{data?.error || t('something_went_wrong')}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// api is successful but error is present
|
||||||
|
if (status === 'success' && data.statusCode >= 400) {
|
||||||
|
return (
|
||||||
|
<ListAlert
|
||||||
|
{...{
|
||||||
|
allAlertRules: [],
|
||||||
|
refetch,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// in case of loading
|
||||||
if (isLoading || !data?.payload) {
|
if (isLoading || !data?.payload) {
|
||||||
return <Spinner height="75vh" tip="Loading Rules..." />;
|
return <Spinner height="75vh" tip="Loading Rules..." />;
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,9 @@ function ImportJSON({
|
|||||||
...queryData,
|
...queryData,
|
||||||
queryData: [],
|
queryData: [],
|
||||||
})),
|
})),
|
||||||
|
error: false,
|
||||||
|
errorMessage: '',
|
||||||
|
loading: false,
|
||||||
},
|
},
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,7 @@ import MetricReducer from 'types/reducer/metrics';
|
|||||||
|
|
||||||
import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles';
|
import { Card, Col, GraphContainer, GraphTitle, Row } from '../styles';
|
||||||
import TopEndpointsTable from '../TopEndpointsTable';
|
import TopEndpointsTable from '../TopEndpointsTable';
|
||||||
import { Button, TableContainerCard } from './styles';
|
import { Button } from './styles';
|
||||||
|
|
||||||
function Application({ getWidget }: DashboardProps): JSX.Element {
|
function Application({ getWidget }: DashboardProps): JSX.Element {
|
||||||
const { servicename } = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
@ -48,7 +48,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onClickhandler = async (
|
const onClickHandler = async (
|
||||||
event: ChartEvent,
|
event: ChartEvent,
|
||||||
elements: ActiveElement[],
|
elements: ActiveElement[],
|
||||||
chart: Chart,
|
chart: Chart,
|
||||||
@ -119,7 +119,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
<GraphContainer>
|
<GraphContainer>
|
||||||
<Graph
|
<Graph
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
onClickhandler(ChartEvent, activeElements, chart, data, 'Application');
|
onClickHandler(ChartEvent, activeElements, chart, data, 'Application');
|
||||||
}}
|
}}
|
||||||
name="application_latency"
|
name="application_latency"
|
||||||
type="line"
|
type="line"
|
||||||
@ -189,7 +189,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
name="request_per_sec"
|
name="request_per_sec"
|
||||||
fullViewOptions={false}
|
fullViewOptions={false}
|
||||||
onClickHandler={(event, element, chart, data): void => {
|
onClickHandler={(event, element, chart, data): void => {
|
||||||
onClickhandler(event, element, chart, data, 'Request');
|
onClickHandler(event, element, chart, data, 'Request');
|
||||||
}}
|
}}
|
||||||
widget={getWidget([
|
widget={getWidget([
|
||||||
{
|
{
|
||||||
@ -223,7 +223,7 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
name="error_percentage_%"
|
name="error_percentage_%"
|
||||||
fullViewOptions={false}
|
fullViewOptions={false}
|
||||||
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
onClickHandler={(ChartEvent, activeElements, chart, data): void => {
|
||||||
onClickhandler(ChartEvent, activeElements, chart, data, 'Error');
|
onClickHandler(ChartEvent, activeElements, chart, data, 'Error');
|
||||||
}}
|
}}
|
||||||
widget={getWidget([
|
widget={getWidget([
|
||||||
{
|
{
|
||||||
@ -238,9 +238,9 @@ function Application({ getWidget }: DashboardProps): JSX.Element {
|
|||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<TableContainerCard>
|
<Card>
|
||||||
<TopEndpointsTable data={topEndPoints} />
|
<TopEndpointsTable data={topEndPoints} />
|
||||||
</TableContainerCard>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</>
|
</>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
import { Button as ButtonComponent } from 'antd';
|
import { Button as ButtonComponent } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { Card } from '../styles';
|
|
||||||
|
|
||||||
export const Button = styled(ButtonComponent)`
|
export const Button = styled(ButtonComponent)`
|
||||||
&&& {
|
&&& {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@ -10,6 +8,3 @@ export const Button = styled(ButtonComponent)`
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
export const TableContainerCard = styled(Card)`
|
|
||||||
overflow-x: auto;
|
|
||||||
`;
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Button, Table, Tooltip } from 'antd';
|
import { Table, Tooltip, Typography } from 'antd';
|
||||||
import { ColumnsType } from 'antd/lib/table';
|
import { ColumnsType } from 'antd/lib/table';
|
||||||
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
import { METRICS_PAGE_QUERY_PARAM } from 'constants/query';
|
||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
@ -51,17 +51,12 @@ function TopEndpointsTable(props: TopEndpointsTableProps): JSX.Element {
|
|||||||
title: 'Name',
|
title: 'Name',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
|
ellipsis: true,
|
||||||
// eslint-disable-next-line react/display-name
|
|
||||||
render: (text: string): JSX.Element => (
|
render: (text: string): JSX.Element => (
|
||||||
<Tooltip placement="topLeft" title={text}>
|
<Tooltip placement="topLeft" title={text}>
|
||||||
<Button
|
<Typography.Link onClick={(): void => handleOnClick(text)}>
|
||||||
className="topEndpointsButton"
|
|
||||||
type="link"
|
|
||||||
onClick={(): void => handleOnClick(text)}
|
|
||||||
>
|
|
||||||
{text}
|
{text}
|
||||||
</Button>
|
</Typography.Link>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
@ -101,9 +96,9 @@ function TopEndpointsTable(props: TopEndpointsTableProps): JSX.Element {
|
|||||||
title={(): string => {
|
title={(): string => {
|
||||||
return 'Top Endpoints';
|
return 'Top Endpoints';
|
||||||
}}
|
}}
|
||||||
|
tableLayout="fixed"
|
||||||
dataSource={data}
|
dataSource={data}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={false}
|
|
||||||
rowKey="name"
|
rowKey="name"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -77,7 +77,6 @@ function Metrics(): JSX.Element {
|
|||||||
loading={loading}
|
loading={loading}
|
||||||
dataSource={services}
|
dataSource={services}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={false}
|
|
||||||
rowKey="serviceName"
|
rowKey="serviceName"
|
||||||
/>
|
/>
|
||||||
</Container>
|
</Container>
|
||||||
|
@ -12,9 +12,23 @@ function ShareModal({
|
|||||||
onToggleHandler,
|
onToggleHandler,
|
||||||
selectedData,
|
selectedData,
|
||||||
}: ShareModalProps): JSX.Element {
|
}: ShareModalProps): JSX.Element {
|
||||||
const [jsonValue, setJSONValue] = useState<string>(
|
const getParsedValue = (): string => {
|
||||||
JSON.stringify(selectedData, null, 2),
|
const updatedData: DashboardData = {
|
||||||
);
|
...selectedData,
|
||||||
|
widgets: selectedData.widgets?.map((widget) => ({
|
||||||
|
...widget,
|
||||||
|
queryData: {
|
||||||
|
...widget.queryData,
|
||||||
|
loading: false,
|
||||||
|
error: false,
|
||||||
|
errorMessage: '',
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
return JSON.stringify(updatedData, null, 2);
|
||||||
|
};
|
||||||
|
|
||||||
|
const [jsonValue, setJSONValue] = useState<string>(getParsedValue());
|
||||||
const [isViewJSON, setIsViewJSON] = useState<boolean>(false);
|
const [isViewJSON, setIsViewJSON] = useState<boolean>(false);
|
||||||
const { t } = useTranslation(['dashboard', 'common']);
|
const { t } = useTranslation(['dashboard', 'common']);
|
||||||
const [state, setCopy] = useCopyToClipboard();
|
const [state, setCopy] = useCopyToClipboard();
|
||||||
|
@ -38,7 +38,7 @@ function DisplayName({
|
|||||||
dispatch({
|
dispatch({
|
||||||
type: UPDATE_ORG_NAME,
|
type: UPDATE_ORG_NAME,
|
||||||
payload: {
|
payload: {
|
||||||
index,
|
orgId,
|
||||||
name: orgName,
|
name: orgName,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Checkbox, notification, Typography } from 'antd';
|
import { Checkbox, notification, Tooltip, Typography } from 'antd';
|
||||||
import getFilters from 'api/trace/getFilters';
|
import getFilters from 'api/trace/getFilters';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
import React, { useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
import { useDispatch, useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
import { Dispatch } from 'redux';
|
import { Dispatch } from 'redux';
|
||||||
import { getFilter, updateURL } from 'store/actions/trace/util';
|
import { getFilter, updateURL } from 'store/actions/trace/util';
|
||||||
@ -11,7 +11,7 @@ import { UPDATE_ALL_FILTERS } from 'types/actions/trace';
|
|||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||||
|
|
||||||
import { CheckBoxContainer } from './styles';
|
import { CheckBoxContainer, ParaGraph } from './styles';
|
||||||
|
|
||||||
function CheckBoxComponent(props: CheckBoxProps): JSX.Element {
|
function CheckBoxComponent(props: CheckBoxProps): JSX.Element {
|
||||||
const {
|
const {
|
||||||
@ -155,6 +155,11 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element {
|
|||||||
|
|
||||||
const isCheckBoxSelected = isUserSelected;
|
const isCheckBoxSelected = isUserSelected;
|
||||||
|
|
||||||
|
const TooTipOverLay = useMemo(
|
||||||
|
(): JSX.Element => <Typography>{keyValue}</Typography>,
|
||||||
|
[keyValue],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CheckBoxContainer>
|
<CheckBoxContainer>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
@ -164,7 +169,9 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element {
|
|||||||
defaultChecked
|
defaultChecked
|
||||||
key={keyValue}
|
key={keyValue}
|
||||||
>
|
>
|
||||||
{keyValue}
|
<Tooltip overlay={TooTipOverLay}>
|
||||||
|
<ParaGraph ellipsis>{keyValue}</ParaGraph>
|
||||||
|
</Tooltip>
|
||||||
</Checkbox>
|
</Checkbox>
|
||||||
{isCheckBoxSelected ? (
|
{isCheckBoxSelected ? (
|
||||||
<Typography>{value}</Typography>
|
<Typography>{value}</Typography>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { Typography } from 'antd';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
export const CheckBoxContainer = styled.div`
|
export const CheckBoxContainer = styled.div`
|
||||||
@ -9,3 +10,10 @@ export const CheckBoxContainer = styled.div`
|
|||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const ParaGraph = styled(Typography.Paragraph)`
|
||||||
|
&&& {
|
||||||
|
margin: 0;
|
||||||
|
max-width: 8rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
@ -34,7 +34,7 @@ function TraceGraph(): JSX.Element {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loading || payload === undefined) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Container>
|
<Container>
|
||||||
<Spinner height="20vh" size="small" tip="Loading..." />
|
<Spinner height="20vh" size="small" tip="Loading..." />
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
import { notification } from 'antd';
|
||||||
import getTriggeredApi from 'api/alerts/getTriggered';
|
import getTriggeredApi from 'api/alerts/getTriggered';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import { State } from 'hooks/useFetch';
|
import { State } from 'hooks/useFetch';
|
||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { PayloadProps } from 'types/api/alerts/getTriggered';
|
import { PayloadProps } from 'types/api/alerts/getTriggered';
|
||||||
|
|
||||||
import TriggerComponent from './TriggeredAlert';
|
import TriggerComponent from './TriggeredAlert';
|
||||||
@ -14,6 +16,7 @@ function TriggeredAlerts(): JSX.Element {
|
|||||||
success: false,
|
success: false,
|
||||||
payload: [],
|
payload: [],
|
||||||
});
|
});
|
||||||
|
const { t } = useTranslation(['common']);
|
||||||
|
|
||||||
const fetchData = useCallback(async () => {
|
const fetchData = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
@ -56,8 +59,16 @@ function TriggeredAlerts(): JSX.Element {
|
|||||||
fetchData();
|
fetchData();
|
||||||
}, [fetchData]);
|
}, [fetchData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
if (groupState.error) {
|
if (groupState.error) {
|
||||||
return <div>{groupState.errorMessage}</div>;
|
notification.error({
|
||||||
|
message: groupState.errorMessage || t('something_went_wrong'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [groupState.error, groupState.errorMessage, t]);
|
||||||
|
|
||||||
|
if (groupState.error) {
|
||||||
|
return <TriggerComponent allAlerts={[]} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groupState.loading || groupState.payload === undefined) {
|
if (groupState.loading || groupState.payload === undefined) {
|
||||||
|
@ -5,12 +5,13 @@ import { Card } from 'antd';
|
|||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useEffect, useRef } from 'react';
|
||||||
import { ForceGraph2D } from 'react-force-graph';
|
import { ForceGraph2D } from 'react-force-graph';
|
||||||
import { connect } from 'react-redux';
|
import { connect, useSelector } from 'react-redux';
|
||||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||||
import { getDetailedServiceMapItems, ServiceMapStore } from 'store/actions';
|
import { getDetailedServiceMapItems, ServiceMapStore } from 'store/actions';
|
||||||
import { AppState } from 'store/reducers';
|
import { AppState } from 'store/reducers';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import { GlobalTime } from 'types/actions/globalTime';
|
import { GlobalTime } from 'types/actions/globalTime';
|
||||||
|
import AppReducer from 'types/reducer/app';
|
||||||
|
|
||||||
import SelectService from './SelectService';
|
import SelectService from './SelectService';
|
||||||
import { getGraphData, getTooltip, getZoomPx, transformLabel } from './utils';
|
import { getGraphData, getTooltip, getZoomPx, transformLabel } from './utils';
|
||||||
@ -53,6 +54,8 @@ export interface graphDataType {
|
|||||||
function ServiceMap(props: ServiceMapProps): JSX.Element {
|
function ServiceMap(props: ServiceMapProps): JSX.Element {
|
||||||
const fgRef = useRef();
|
const fgRef = useRef();
|
||||||
|
|
||||||
|
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||||
|
|
||||||
const { getDetailedServiceMapItems, globalTime, serviceMap } = props;
|
const { getDetailedServiceMapItems, globalTime, serviceMap } = props;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -115,10 +118,11 @@ function ServiceMap(props: ServiceMapProps): JSX.Element {
|
|||||||
ctx.fillStyle = node.color;
|
ctx.fillStyle = node.color;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false);
|
ctx.arc(node.x, node.y, width, 0, 2 * Math.PI, false);
|
||||||
|
ctx.fillStyle = isDarkMode ? '#3d0b00' : '#ffbcad';
|
||||||
ctx.fill();
|
ctx.fill();
|
||||||
ctx.textAlign = 'center';
|
ctx.textAlign = 'center';
|
||||||
ctx.textBaseline = 'middle';
|
ctx.textBaseline = 'middle';
|
||||||
ctx.fillStyle = '#646464';
|
ctx.fillStyle = isDarkMode ? '#ffffff' : '#000000';
|
||||||
ctx.fillText(label, node.x, node.y);
|
ctx.fillText(label, node.x, node.y);
|
||||||
}}
|
}}
|
||||||
onNodeClick={(node) => {
|
onNodeClick={(node) => {
|
||||||
|
@ -5,6 +5,7 @@ import Spinner from 'components/Spinner';
|
|||||||
import ROUTES from 'constants/routes';
|
import ROUTES from 'constants/routes';
|
||||||
import ErrorDetailsContainer from 'container/ErrorDetails';
|
import ErrorDetailsContainer from 'container/ErrorDetails';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useQuery } from 'react-query';
|
import { useQuery } from 'react-query';
|
||||||
import { useSelector } from 'react-redux';
|
import { useSelector } from 'react-redux';
|
||||||
import { Redirect, useLocation } from 'react-router-dom';
|
import { Redirect, useLocation } from 'react-router-dom';
|
||||||
@ -13,6 +14,7 @@ import { PayloadProps } from 'types/api/errors/getById';
|
|||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
|
|
||||||
function ErrorDetails(): JSX.Element {
|
function ErrorDetails(): JSX.Element {
|
||||||
|
const { t } = useTranslation(['common']);
|
||||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||||
(state) => state.globalTime,
|
(state) => state.globalTime,
|
||||||
);
|
);
|
||||||
@ -22,6 +24,7 @@ function ErrorDetails(): JSX.Element {
|
|||||||
const errorId = params.get('errorId');
|
const errorId = params.get('errorId');
|
||||||
const errorType = params.get('errorType');
|
const errorType = params.get('errorType');
|
||||||
const serviceName = params.get('serviceName');
|
const serviceName = params.get('serviceName');
|
||||||
|
const defaultError = t('something_went_wrong');
|
||||||
|
|
||||||
const { data, status } = useQuery(
|
const { data, status } = useQuery(
|
||||||
[
|
[
|
||||||
@ -72,16 +75,31 @@ function ErrorDetails(): JSX.Element {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// if errorType and serviceName is null redirecting to the ALL_ERROR page not now
|
||||||
if (errorType === null || serviceName === null) {
|
if (errorType === null || serviceName === null) {
|
||||||
return <Redirect to={ROUTES.ALL_ERROR} />;
|
return <Redirect to={ROUTES.ALL_ERROR} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// when the api is in loading state
|
||||||
if (status === 'loading' || ErrorIdStatus === 'loading') {
|
if (status === 'loading' || ErrorIdStatus === 'loading') {
|
||||||
return <Spinner tip="Loading.." />;
|
return <Spinner tip="Loading.." />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if any error occurred while loading
|
||||||
if (status === 'error' || ErrorIdStatus === 'error') {
|
if (status === 'error' || ErrorIdStatus === 'error') {
|
||||||
return <Typography>{data?.error || errorIdPayload?.error}</Typography>;
|
return (
|
||||||
|
<Typography>
|
||||||
|
{data?.error || errorIdPayload?.error || defaultError}
|
||||||
|
</Typography>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if API is successfully but there is an error
|
||||||
|
if (
|
||||||
|
(status === 'success' && data?.statusCode >= 400) ||
|
||||||
|
(ErrorIdStatus === 'success' && errorIdPayload.statusCode >= 400)
|
||||||
|
) {
|
||||||
|
return <Typography>{data?.error || defaultError}</Typography>;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -20,7 +20,10 @@ function Login(): JSX.Element {
|
|||||||
enabled: !isLoggedIn,
|
enabled: !isLoggedIn,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (versionResult.status === 'error') {
|
if (
|
||||||
|
versionResult.status === 'error' ||
|
||||||
|
(versionResult.status === 'success' && versionResult?.data.statusCode !== 200)
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<Typography>
|
<Typography>
|
||||||
{versionResult.data?.error || t('something_went_wrong')}
|
{versionResult.data?.error || t('something_went_wrong')}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { notification } from 'antd';
|
||||||
import getLocalStorageKey from 'api/browser/localstorage/get';
|
import getLocalStorageKey from 'api/browser/localstorage/get';
|
||||||
import Spinner from 'components/Spinner';
|
import Spinner from 'components/Spinner';
|
||||||
import { SKIP_ONBOARDING } from 'constants/onboarding';
|
import { SKIP_ONBOARDING } from 'constants/onboarding';
|
||||||
@ -20,10 +21,20 @@ function Metrics({ getService }: MetricsProps): JSX.Element {
|
|||||||
AppState,
|
AppState,
|
||||||
GlobalReducer
|
GlobalReducer
|
||||||
>((state) => state.globalTime);
|
>((state) => state.globalTime);
|
||||||
const { services, resourceAttributeQueries } = useSelector<
|
const {
|
||||||
AppState,
|
services,
|
||||||
MetricReducer
|
resourceAttributeQueries,
|
||||||
>((state) => state.metrics);
|
error,
|
||||||
|
errorMessage,
|
||||||
|
} = useSelector<AppState, MetricReducer>((state) => state.metrics);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (error) {
|
||||||
|
notification.error({
|
||||||
|
message: errorMessage,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [error, errorMessage]);
|
||||||
|
|
||||||
const selectedTags = useMemo(
|
const selectedTags = useMemo(
|
||||||
() =>
|
() =>
|
||||||
|
@ -10,8 +10,8 @@ export const Container = styled.div`
|
|||||||
|
|
||||||
export const LeftContainer = styled(Card)`
|
export const LeftContainer = styled(Card)`
|
||||||
flex: 0.5;
|
flex: 0.5;
|
||||||
width: 95%;
|
margin-right: 0.5rem;
|
||||||
padding-right: 0.5rem;
|
width: 15rem;
|
||||||
|
|
||||||
.ant-card-body {
|
.ant-card-body {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
@ -7,6 +7,7 @@ import AppActions from 'types/actions';
|
|||||||
import {
|
import {
|
||||||
UPDATE_ALL_FILTERS,
|
UPDATE_ALL_FILTERS,
|
||||||
UPDATE_TRACE_FILTER_LOADING,
|
UPDATE_TRACE_FILTER_LOADING,
|
||||||
|
UPDATE_TRACE_GRAPH_LOADING,
|
||||||
} from 'types/actions/trace';
|
} from 'types/actions/trace';
|
||||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||||
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
import { TraceFilterEnum, TraceReducer } from 'types/reducer/trace';
|
||||||
@ -183,6 +184,12 @@ export const GetInitialTraceFilter = (
|
|||||||
filterLoading: false,
|
filterLoading: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
dispatch({
|
||||||
|
type: UPDATE_TRACE_GRAPH_LOADING,
|
||||||
|
payload: {
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
dispatch({
|
dispatch({
|
||||||
@ -191,6 +198,12 @@ export const GetInitialTraceFilter = (
|
|||||||
filterLoading: false,
|
filterLoading: false,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
dispatch({
|
||||||
|
type: UPDATE_TRACE_GRAPH_LOADING,
|
||||||
|
payload: {
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { applyMiddleware, compose, createStore } from 'redux';
|
import { applyMiddleware, compose, createStore } from 'redux';
|
||||||
import thunk, { ThunkMiddleware } from 'redux-thunk';
|
import thunk, { ThunkMiddleware } from 'redux-thunk';
|
||||||
|
import AppActions from 'types/actions';
|
||||||
|
|
||||||
import reducers, { AppState } from './reducers';
|
import reducers, { AppState } from './reducers';
|
||||||
|
|
||||||
@ -8,8 +9,9 @@ const composeEnhancers =
|
|||||||
|
|
||||||
const store = createStore(
|
const store = createStore(
|
||||||
reducers,
|
reducers,
|
||||||
// @TODO Add Type for AppActions also
|
composeEnhancers(
|
||||||
composeEnhancers(applyMiddleware(thunk as ThunkMiddleware<AppState>)),
|
applyMiddleware(thunk as ThunkMiddleware<AppState, AppActions>),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
export default store;
|
export default store;
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
UPDATE_CURRENT_VERSION,
|
UPDATE_CURRENT_VERSION,
|
||||||
UPDATE_LATEST_VERSION,
|
UPDATE_LATEST_VERSION,
|
||||||
UPDATE_LATEST_VERSION_ERROR,
|
UPDATE_LATEST_VERSION_ERROR,
|
||||||
|
UPDATE_ORG,
|
||||||
UPDATE_ORG_NAME,
|
UPDATE_ORG_NAME,
|
||||||
UPDATE_USER,
|
UPDATE_USER,
|
||||||
UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
|
UPDATE_USER_ACCESS_REFRESH_ACCESS_TOKEN,
|
||||||
@ -172,16 +173,19 @@ const appReducer = (
|
|||||||
|
|
||||||
case UPDATE_ORG_NAME: {
|
case UPDATE_ORG_NAME: {
|
||||||
const stateOrg = state.org || ({} as OrgPayload);
|
const stateOrg = state.org || ({} as OrgPayload);
|
||||||
const { index, name: updatedName } = action.payload;
|
const { orgId, name: updatedName } = action.payload;
|
||||||
const current = stateOrg[index];
|
|
||||||
|
const orgIndex = stateOrg.findIndex((e) => e.id === orgId);
|
||||||
|
|
||||||
|
const current = stateOrg[orgIndex];
|
||||||
|
|
||||||
const updatedOrg: OrgPayload = [
|
const updatedOrg: OrgPayload = [
|
||||||
...stateOrg.slice(0, index),
|
...stateOrg.slice(0, orgIndex),
|
||||||
{
|
{
|
||||||
...current,
|
...current,
|
||||||
name: updatedName,
|
name: updatedName,
|
||||||
},
|
},
|
||||||
...stateOrg.slice(index + 1, stateOrg.length),
|
...stateOrg.slice(orgIndex + 1, stateOrg.length),
|
||||||
];
|
];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -190,6 +194,13 @@ const appReducer = (
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case UPDATE_ORG: {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
org: action.payload.org,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,7 @@ export const UPDATE_USER_IS_FETCH = 'UPDATE_USER_IS_FETCH';
|
|||||||
export const UPDATE_USER_ORG_ROLE = 'UPDATE_USER_ORG_ROLE';
|
export const UPDATE_USER_ORG_ROLE = 'UPDATE_USER_ORG_ROLE';
|
||||||
export const UPDATE_USER = 'UPDATE_USER';
|
export const UPDATE_USER = 'UPDATE_USER';
|
||||||
export const UPDATE_ORG_NAME = 'UPDATE_ORG_NAME';
|
export const UPDATE_ORG_NAME = 'UPDATE_ORG_NAME';
|
||||||
|
export const UPDATE_ORG = 'UPDATE_ORG';
|
||||||
|
|
||||||
export interface SwitchDarkMode {
|
export interface SwitchDarkMode {
|
||||||
type: typeof SWITCH_DARK_MODE;
|
type: typeof SWITCH_DARK_MODE;
|
||||||
@ -98,7 +99,14 @@ export interface UpdateOrgName {
|
|||||||
type: typeof UPDATE_ORG_NAME;
|
type: typeof UPDATE_ORG_NAME;
|
||||||
payload: {
|
payload: {
|
||||||
name: string;
|
name: string;
|
||||||
index: number;
|
orgId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateOrg {
|
||||||
|
type: typeof UPDATE_ORG;
|
||||||
|
payload: {
|
||||||
|
org: AppReducer['org'];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,4 +121,5 @@ export type AppAction =
|
|||||||
| UpdateUserIsFetched
|
| UpdateUserIsFetched
|
||||||
| UpdateUserOrgRole
|
| UpdateUserOrgRole
|
||||||
| UpdateUser
|
| UpdateUser
|
||||||
| UpdateOrgName;
|
| UpdateOrgName
|
||||||
|
| UpdateOrg;
|
||||||
|
@ -3,6 +3,7 @@ declare global {
|
|||||||
namespace NodeJS {
|
namespace NodeJS {
|
||||||
interface ProcessEnv {
|
interface ProcessEnv {
|
||||||
FRONTEND_API_ENDPOINT: string | undefined;
|
FRONTEND_API_ENDPOINT: string | undefined;
|
||||||
|
NODE_ENV: 'development' | 'production' | 'test';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,8 @@
|
|||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"baseUrl": "./src",
|
"baseUrl": "./src",
|
||||||
"downlevelIteration": true,
|
"downlevelIteration": true,
|
||||||
"plugins": [{ "name": "typescript-plugin-css-modules" }]
|
"plugins": [{ "name": "typescript-plugin-css-modules" }],
|
||||||
|
"types": ["cypress", "@testing-library/cypress", "node"]
|
||||||
},
|
},
|
||||||
"exclude": ["node_modules"],
|
"exclude": ["node_modules"],
|
||||||
"include": [
|
"include": [
|
||||||
@ -30,6 +31,9 @@
|
|||||||
"./__mocks__",
|
"./__mocks__",
|
||||||
"./conf/default.conf",
|
"./conf/default.conf",
|
||||||
"./public",
|
"./public",
|
||||||
"./cypress"
|
"./cypress",
|
||||||
|
"./commitlint.config.js",
|
||||||
|
"./webpack.config.js",
|
||||||
|
"./webpack.config.prod.js"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
// shared config (dev and prod)
|
// shared config (dev and prod)
|
||||||
const { resolve } = require('path');
|
const { resolve } = require('path');
|
||||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
@ -5,8 +6,7 @@ const portFinderSync = require('portfinder-sync');
|
|||||||
const dotenv = require('dotenv');
|
const dotenv = require('dotenv');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
.BundleAnalyzerPlugin;
|
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
@ -106,7 +106,7 @@ const config = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: plugins,
|
plugins,
|
||||||
performance: {
|
performance: {
|
||||||
hints: false,
|
hints: false,
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||||
// shared config (dev and prod)
|
// shared config (dev and prod)
|
||||||
const { resolve } = require('path');
|
const { resolve } = require('path');
|
||||||
@ -9,8 +10,7 @@ const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
|||||||
const TerserPlugin = require('terser-webpack-plugin');
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
|
||||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
|
||||||
.BundleAnalyzerPlugin;
|
|
||||||
const Critters = require('critters-webpack-plugin');
|
const Critters = require('critters-webpack-plugin');
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
@ -119,13 +119,13 @@ const config = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: plugins,
|
plugins,
|
||||||
optimization: {
|
optimization: {
|
||||||
chunkIds: 'named',
|
chunkIds: 'named',
|
||||||
concatenateModules: false,
|
concatenateModules: false,
|
||||||
emitOnErrors: true,
|
emitOnErrors: true,
|
||||||
flagIncludedChunks: true,
|
flagIncludedChunks: true,
|
||||||
innerGraph: true, //tells webpack whether to conduct inner graph analysis for unused exports.
|
innerGraph: true, // tells webpack whether to conduct inner graph analysis for unused exports.
|
||||||
mangleWasmImports: true,
|
mangleWasmImports: true,
|
||||||
mergeDuplicateChunks: true,
|
mergeDuplicateChunks: true,
|
||||||
minimize: true,
|
minimize: true,
|
||||||
|
4050
frontend/yarn.lock
4050
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
@ -2333,6 +2333,40 @@ func (r *ClickHouseReader) setColdStorage(ctx context.Context, tableName string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *ClickHouseReader) RemoveTTL(ctx context.Context,
|
||||||
|
params *model.RemoveTTLParams) (*model.RemoveTTLResponseItem, *model.ApiError) {
|
||||||
|
|
||||||
|
var reqs []string
|
||||||
|
templateQuery := `ALTER TABLE %v REMOVE TTL`
|
||||||
|
tracesTables := []string{signozTraceDBName + "." + signozTraceTableName, signozTraceDBName + "." + signozDurationMVTable, signozTraceDBName + "." + signozSpansTable, signozTraceDBName + "." + signozErrorIndexTable}
|
||||||
|
metricsTables := []string{signozMetricDBName + "." + signozSampleName}
|
||||||
|
|
||||||
|
switch params.Type {
|
||||||
|
case constants.TraceTTL:
|
||||||
|
for _, tableName := range tracesTables {
|
||||||
|
reqs = append(reqs, fmt.Sprintf(templateQuery, tableName))
|
||||||
|
}
|
||||||
|
case constants.MetricsTTL:
|
||||||
|
for _, tableName := range metricsTables {
|
||||||
|
reqs = append(reqs, fmt.Sprintf(templateQuery, tableName))
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
for _, tableName := range append(append([]string{}, tracesTables...), metricsTables...) {
|
||||||
|
reqs = append(reqs, fmt.Sprintf(templateQuery, tableName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zap.S().Debugf("Executing remove TTL requests: %s\n", reqs)
|
||||||
|
for _, req := range reqs {
|
||||||
|
if err := r.db.Exec(ctx, req); err != nil {
|
||||||
|
zap.S().Error(fmt.Errorf("error while removing ttl. Err=%v", err))
|
||||||
|
return nil, &model.ApiError{Typ: model.ErrorExec,
|
||||||
|
Err: fmt.Errorf("error while removing ttl. Err=%v", err)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &model.RemoveTTLResponseItem{Message: "ttl has been successfully removed"}, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetDisks returns a list of disks {name, type} configured in clickhouse DB.
|
// GetDisks returns a list of disks {name, type} configured in clickhouse DB.
|
||||||
func (r *ClickHouseReader) GetDisks(ctx context.Context) (*[]model.DiskItem, *model.ApiError) {
|
func (r *ClickHouseReader) GetDisks(ctx context.Context) (*[]model.DiskItem, *model.ApiError) {
|
||||||
diskItems := []model.DiskItem{}
|
diskItems := []model.DiskItem{}
|
||||||
|
@ -310,6 +310,7 @@ func (aH *APIHandler) RegisterRoutes(router *mux.Router) {
|
|||||||
router.HandleFunc("/api/v1/serviceMapDependencies", ViewAccess(aH.serviceMapDependencies)).Methods(http.MethodPost)
|
router.HandleFunc("/api/v1/serviceMapDependencies", ViewAccess(aH.serviceMapDependencies)).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/api/v1/settings/ttl", AdminAccess(aH.setTTL)).Methods(http.MethodPost)
|
router.HandleFunc("/api/v1/settings/ttl", AdminAccess(aH.setTTL)).Methods(http.MethodPost)
|
||||||
router.HandleFunc("/api/v1/settings/ttl", ViewAccess(aH.getTTL)).Methods(http.MethodGet)
|
router.HandleFunc("/api/v1/settings/ttl", ViewAccess(aH.getTTL)).Methods(http.MethodGet)
|
||||||
|
router.HandleFunc("/api/v1/settings/ttl", AdminAccess(aH.removeTTL)).Methods(http.MethodDelete)
|
||||||
|
|
||||||
router.HandleFunc("/api/v1/version", OpenAccess(aH.getVersion)).Methods(http.MethodGet)
|
router.HandleFunc("/api/v1/version", OpenAccess(aH.getVersion)).Methods(http.MethodGet)
|
||||||
|
|
||||||
@ -1162,6 +1163,47 @@ func (aH *APIHandler) getTTL(w http.ResponseWriter, r *http.Request) {
|
|||||||
aH.writeJSON(w, r, result)
|
aH.writeJSON(w, r, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (aH *APIHandler) removeTTL(w http.ResponseWriter, r *http.Request) {
|
||||||
|
ttlParams, err := parseRemoveTTL(r)
|
||||||
|
if aH.handleError(w, err, http.StatusBadRequest) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
existingTTL, apiErr := (*aH.reader).GetTTL(context.Background(), &model.GetTTLParams{GetAllTTL: true})
|
||||||
|
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttlParams.Type == constants.TraceTTL && existingTTL.TracesTime == -1 &&
|
||||||
|
aH.handleError(w, fmt.Errorf("traces doesn't have any TTL set, cannot remove"), http.StatusBadRequest) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttlParams.Type == constants.MetricsTTL && existingTTL.MetricsTime == -1 &&
|
||||||
|
aH.handleError(w, fmt.Errorf("metrics doesn't have any TTL set, cannot remove"), http.StatusBadRequest) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttlParams.RemoveAllTTL {
|
||||||
|
if existingTTL.TracesTime == -1 && existingTTL.MetricsTime != -1 {
|
||||||
|
ttlParams.Type = constants.MetricsTTL
|
||||||
|
ttlParams.RemoveAllTTL = false
|
||||||
|
} else if existingTTL.TracesTime != -1 && existingTTL.MetricsTime == -1 {
|
||||||
|
ttlParams.Type = constants.TraceTTL
|
||||||
|
ttlParams.RemoveAllTTL = false
|
||||||
|
} else if aH.handleError(w, fmt.Errorf("no TTL set, cannot remove"), http.StatusBadRequest) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result, apiErr := (*aH.reader).RemoveTTL(context.Background(), ttlParams)
|
||||||
|
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
aH.writeJSON(w, r, result)
|
||||||
|
}
|
||||||
|
|
||||||
func (aH *APIHandler) getDisks(w http.ResponseWriter, r *http.Request) {
|
func (aH *APIHandler) getDisks(w http.ResponseWriter, r *http.Request) {
|
||||||
result, apiErr := (*aH.reader).GetDisks(context.Background())
|
result, apiErr := (*aH.reader).GetDisks(context.Background())
|
||||||
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
|
if apiErr != nil && aH.handleError(w, apiErr.Err, http.StatusInternalServerError) {
|
||||||
|
@ -50,6 +50,7 @@ type Reader interface {
|
|||||||
|
|
||||||
// Setter Interfaces
|
// Setter Interfaces
|
||||||
SetTTL(ctx context.Context, ttlParams *model.TTLParams) (*model.SetTTLResponseItem, *model.ApiError)
|
SetTTL(ctx context.Context, ttlParams *model.TTLParams) (*model.SetTTLResponseItem, *model.ApiError)
|
||||||
|
RemoveTTL(ctx context.Context, ttlParams *model.RemoveTTLParams) (*model.RemoveTTLResponseItem, *model.ApiError)
|
||||||
|
|
||||||
GetMetricAutocompleteMetricNames(ctx context.Context, matchText string) (*[]string, *model.ApiError)
|
GetMetricAutocompleteMetricNames(ctx context.Context, matchText string) (*[]string, *model.ApiError)
|
||||||
GetMetricAutocompleteTagKey(ctx context.Context, params *model.MetricAutocompleteTagParams) (*[]string, *model.ApiError)
|
GetMetricAutocompleteTagKey(ctx context.Context, params *model.MetricAutocompleteTagParams) (*[]string, *model.ApiError)
|
||||||
|
@ -545,7 +545,7 @@ func parseTTLParams(r *http.Request) (*model.TTLParams, error) {
|
|||||||
|
|
||||||
// Validate the TTL duration.
|
// Validate the TTL duration.
|
||||||
durationParsed, err := time.ParseDuration(delDuration)
|
durationParsed, err := time.ParseDuration(delDuration)
|
||||||
if err != nil {
|
if err != nil || durationParsed.Seconds() <= 0 {
|
||||||
return nil, fmt.Errorf("Not a valid TTL duration %v", delDuration)
|
return nil, fmt.Errorf("Not a valid TTL duration %v", delDuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -554,7 +554,7 @@ func parseTTLParams(r *http.Request) (*model.TTLParams, error) {
|
|||||||
// If some cold storage is provided, validate the cold storage move TTL.
|
// If some cold storage is provided, validate the cold storage move TTL.
|
||||||
if len(coldStorage) > 0 {
|
if len(coldStorage) > 0 {
|
||||||
toColdParsed, err = time.ParseDuration(toColdDuration)
|
toColdParsed, err = time.ParseDuration(toColdDuration)
|
||||||
if err != nil {
|
if err != nil || toColdParsed.Seconds() <= 0 {
|
||||||
return nil, fmt.Errorf("Not a valid toCold TTL duration %v", toColdDuration)
|
return nil, fmt.Errorf("Not a valid toCold TTL duration %v", toColdDuration)
|
||||||
}
|
}
|
||||||
if toColdParsed.Seconds() != 0 && toColdParsed.Seconds() >= durationParsed.Seconds() {
|
if toColdParsed.Seconds() != 0 && toColdParsed.Seconds() >= durationParsed.Seconds() {
|
||||||
@ -587,6 +587,23 @@ func parseGetTTL(r *http.Request) (*model.GetTTLParams, error) {
|
|||||||
return &model.GetTTLParams{Type: typeTTL, GetAllTTL: getAllTTL}, nil
|
return &model.GetTTLParams{Type: typeTTL, GetAllTTL: getAllTTL}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseRemoveTTL(r *http.Request) (*model.RemoveTTLParams, error) {
|
||||||
|
|
||||||
|
typeTTL := r.URL.Query().Get("type")
|
||||||
|
removeAllTTL := false
|
||||||
|
|
||||||
|
if len(typeTTL) == 0 {
|
||||||
|
removeAllTTL = true
|
||||||
|
} else {
|
||||||
|
// Validate the type parameter
|
||||||
|
if typeTTL != constants.TraceTTL && typeTTL != constants.MetricsTTL {
|
||||||
|
return nil, fmt.Errorf("type param should be <metrics|traces>, got %v", typeTTL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &model.RemoveTTLParams{Type: typeTTL, RemoveAllTTL: removeAllTTL}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseUserRequest(r *http.Request) (*model.User, error) {
|
func parseUserRequest(r *http.Request) (*model.User, error) {
|
||||||
var req model.User
|
var req model.User
|
||||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
_ "net/http/pprof" // http profiler
|
||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -257,7 +258,15 @@ func (s *Server) Start() error {
|
|||||||
zap.S().Error("Could not start HTTP server", zap.Error(err))
|
zap.S().Error("Could not start HTTP server", zap.Error(err))
|
||||||
}
|
}
|
||||||
s.unavailableChannel <- healthcheck.Unavailable
|
s.unavailableChannel <- healthcheck.Unavailable
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
zap.S().Info("Starting pprof server", zap.String("addr", constants.DebugHttpPort))
|
||||||
|
|
||||||
|
err = http.ListenAndServe(constants.DebugHttpPort, nil)
|
||||||
|
if err != nil {
|
||||||
|
zap.S().Error("Could not start pprof server", zap.Error(err))
|
||||||
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -6,7 +6,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
HTTPHostPort = "0.0.0.0:8080"
|
HTTPHostPort = "0.0.0.0:8080" // Address to serve http (query service)
|
||||||
|
DebugHttpPort = "0.0.0.0:6060" // Address to serve http (pprof)
|
||||||
)
|
)
|
||||||
|
|
||||||
var DEFAULT_TELEMETRY_ANONYMOUS = false
|
var DEFAULT_TELEMETRY_ANONYMOUS = false
|
||||||
|
@ -206,3 +206,8 @@ type GetErrorParams struct {
|
|||||||
ErrorID string
|
ErrorID string
|
||||||
ServiceName string
|
ServiceName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RemoveTTLParams struct {
|
||||||
|
Type string
|
||||||
|
RemoveAllTTL bool
|
||||||
|
}
|
||||||
|
@ -246,6 +246,10 @@ type SetTTLResponseItem struct {
|
|||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RemoveTTLResponseItem struct {
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
type DiskItem struct {
|
type DiskItem struct {
|
||||||
Name string `json:"name,omitempty" ch:"name"`
|
Name string `json:"name,omitempty" ch:"name"`
|
||||||
Type string `json:"type,omitempty" ch:"type"`
|
Type string `json:"type,omitempty" ch:"type"`
|
||||||
|
Loading…
x
Reference in New Issue
Block a user