mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-08 10:59:04 +08:00
Merge pull request #25 from himanshu-source21/ft-saas-opensource-parity-1
Ft saas opensource parity 1
This commit is contained in:
commit
ae2dfe59d9
16
frontend/.babelrc
Normal file
16
frontend/.babelrc
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"presets": [
|
||||||
|
"@babel/preset-env",
|
||||||
|
"@babel/preset-react",
|
||||||
|
"@babel/preset-typescript"
|
||||||
|
],
|
||||||
|
"plugins": [
|
||||||
|
"react-hot-loader/babel",
|
||||||
|
"@babel/plugin-proposal-class-properties"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"production": {
|
||||||
|
"presets": ["minify"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,12 @@
|
|||||||
|
# Docker
|
||||||
|
|
||||||
# Docker
|
**Building image**
|
||||||
**Building image**
|
|
||||||
|
|
||||||
```docker-compose up``
|
``docker-compose up`
|
||||||
/ This will also run
|
/ This will also run
|
||||||
|
|
||||||
or
|
or
|
||||||
```docker build . -t tagname```
|
`docker build . -t tagname`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**Tag to remote url- Introduce versinoing later on**
|
**Tag to remote url- Introduce versinoing later on**
|
||||||
|
|
||||||
@ -16,7 +14,7 @@ or
|
|||||||
docker tag signoz/frontend:latest 7296823551/signoz:latest
|
docker tag signoz/frontend:latest 7296823551/signoz:latest
|
||||||
```
|
```
|
||||||
|
|
||||||
**Running locally**
|
**Running locally**
|
||||||
|
|
||||||
```
|
```
|
||||||
docker-compose up
|
docker-compose up
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
version: "3.9"
|
version: "3.9"
|
||||||
services:
|
services:
|
||||||
web:
|
web:
|
||||||
build: .
|
build: .
|
||||||
image: signoz/frontend:latest
|
image: signoz/frontend:latest
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
|
@ -3,7 +3,7 @@ const gulpless = require("gulp-less");
|
|||||||
const postcss = require("gulp-postcss");
|
const postcss = require("gulp-postcss");
|
||||||
const debug = require("gulp-debug");
|
const debug = require("gulp-debug");
|
||||||
var csso = require("gulp-csso");
|
var csso = require("gulp-csso");
|
||||||
const autoprefixer = require("autoprefixer");
|
const autteoprefixer = require("autoprefixer");
|
||||||
const NpmImportPlugin = require("less-plugin-npm-import");
|
const NpmImportPlugin = require("less-plugin-npm-import");
|
||||||
|
|
||||||
gulp.task("less", function () {
|
gulp.task("less", function () {
|
||||||
|
@ -1,9 +1,22 @@
|
|||||||
{
|
{
|
||||||
"name": "client",
|
"name": "frontend",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"private": true,
|
"description": "",
|
||||||
|
"main": "webpack.config.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "NODE_ENV=development webpack serve",
|
||||||
|
"start": "node scripts/start.js",
|
||||||
|
"build": "webpack --config=webpack.config.prod.js",
|
||||||
|
"prettify": "prettier --write ."
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@auth0/auth0-react": "^1.2.0",
|
||||||
|
"@babel/core": "7.12.3",
|
||||||
"@material-ui/core": "^4.0.0",
|
"@material-ui/core": "^4.0.0",
|
||||||
|
"@pmmmwh/react-refresh-webpack-plugin": "0.4.2",
|
||||||
|
"@svgr/webpack": "5.4.0",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
@ -18,41 +31,87 @@
|
|||||||
"@types/redux": "^3.6.0",
|
"@types/redux": "^3.6.0",
|
||||||
"@types/styled-components": "^5.1.4",
|
"@types/styled-components": "^5.1.4",
|
||||||
"@types/vis": "^4.21.21",
|
"@types/vis": "^4.21.21",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.5.0",
|
||||||
|
"@typescript-eslint/parser": "^4.5.0",
|
||||||
"antd": "^4.8.0",
|
"antd": "^4.8.0",
|
||||||
"axios": "^0.21.0",
|
"axios": "^0.21.0",
|
||||||
|
"babel-eslint": "^10.1.0",
|
||||||
|
"babel-jest": "^26.6.0",
|
||||||
|
"babel-loader": "8.1.0",
|
||||||
|
"babel-plugin-named-asset-import": "^0.3.7",
|
||||||
|
"babel-preset-minify": "^0.5.1",
|
||||||
|
"babel-preset-react-app": "^10.0.0",
|
||||||
|
"bfj": "^7.0.2",
|
||||||
|
"camelcase": "^6.1.0",
|
||||||
|
"case-sensitive-paths-webpack-plugin": "2.3.0",
|
||||||
"chart.js": "^2.9.4",
|
"chart.js": "^2.9.4",
|
||||||
|
"css-loader": "4.3.0",
|
||||||
"d3": "^6.2.0",
|
"d3": "^6.2.0",
|
||||||
"d3-array": "^2.8.0",
|
"d3-array": "^2.8.0",
|
||||||
"d3-ease": "^2.0.0",
|
"d3-ease": "^2.0.0",
|
||||||
"d3-flame-graph": "^3.1.1",
|
"d3-flame-graph": "^3.1.1",
|
||||||
"d3-tip": "^0.9.1",
|
"d3-tip": "^0.9.1",
|
||||||
|
"dotenv": "8.2.0",
|
||||||
|
"dotenv-expand": "5.1.0",
|
||||||
|
"eslint": "^7.11.0",
|
||||||
|
"eslint-config-react-app": "^6.0.0",
|
||||||
|
"eslint-plugin-flowtype": "^5.2.0",
|
||||||
|
"eslint-plugin-import": "^2.22.1",
|
||||||
|
"eslint-plugin-jest": "^24.1.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.3.1",
|
||||||
|
"eslint-plugin-react": "^7.21.5",
|
||||||
|
"eslint-plugin-react-hooks": "^4.2.0",
|
||||||
|
"eslint-plugin-testing-library": "^3.9.2",
|
||||||
|
"eslint-webpack-plugin": "^2.1.0",
|
||||||
|
"file-loader": "6.1.1",
|
||||||
|
"fs-extra": "^9.0.1",
|
||||||
|
"html-webpack-plugin": "5.1.0",
|
||||||
|
"identity-obj-proxy": "3.0.0",
|
||||||
|
"jest": "26.6.0",
|
||||||
|
"jest-circus": "26.6.0",
|
||||||
|
"jest-resolve": "26.6.0",
|
||||||
|
"jest-watch-typeahead": "0.6.1",
|
||||||
"material-ui-chip-input": "^2.0.0-beta.2",
|
"material-ui-chip-input": "^2.0.0-beta.2",
|
||||||
|
"mini-css-extract-plugin": "0.11.3",
|
||||||
|
"optimize-css-assets-webpack-plugin": "5.0.4",
|
||||||
|
"pnp-webpack-plugin": "1.6.4",
|
||||||
|
"postcss-flexbugs-fixes": "4.2.1",
|
||||||
|
"postcss-loader": "3.0.0",
|
||||||
|
"postcss-normalize": "8.0.1",
|
||||||
|
"postcss-preset-env": "6.7.0",
|
||||||
|
"postcss-safe-parser": "5.0.2",
|
||||||
"prop-types": "^15.6.2",
|
"prop-types": "^15.6.2",
|
||||||
"react": "17.0.0",
|
"react": "17.0.0",
|
||||||
|
"react-app-polyfill": "^2.0.0",
|
||||||
"react-chartjs-2": "^2.11.1",
|
"react-chartjs-2": "^2.11.1",
|
||||||
"react-chips": "^0.8.0",
|
"react-chips": "^0.8.0",
|
||||||
"react-css-theme-switcher": "^0.1.6",
|
"react-css-theme-switcher": "^0.1.6",
|
||||||
|
"react-dev-utils": "^11.0.0",
|
||||||
"react-dom": "17.0.0",
|
"react-dom": "17.0.0",
|
||||||
"react-graph-vis": "^1.0.5",
|
"react-graph-vis": "^1.0.5",
|
||||||
|
"react-modal": "^3.12.1",
|
||||||
"react-redux": "^7.2.2",
|
"react-redux": "^7.2.2",
|
||||||
|
"react-refresh": "^0.8.3",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.0",
|
|
||||||
"react-vis": "^1.11.7",
|
"react-vis": "^1.11.7",
|
||||||
"recharts": "^1.8.5",
|
"recharts": "^1.8.5",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
|
"resolve": "1.18.1",
|
||||||
|
"resolve-url-loader": "^3.1.2",
|
||||||
|
"sass-loader": "8.0.2",
|
||||||
|
"semver": "7.3.2",
|
||||||
|
"style-loader": "1.3.0",
|
||||||
"styled-components": "^5.2.1",
|
"styled-components": "^5.2.1",
|
||||||
|
"terser-webpack-plugin": "4.2.3",
|
||||||
|
"ts-pnp": "1.2.0",
|
||||||
"typescript": "^4.0.5",
|
"typescript": "^4.0.5",
|
||||||
"web-vitals": "^0.2.4"
|
"url-loader": "4.1.1",
|
||||||
},
|
"web-vitals": "^0.2.4",
|
||||||
"scripts": {
|
"webpack": "^5.23.0",
|
||||||
"start": "react-scripts start",
|
"webpack-dev-server": "^3.11.2",
|
||||||
"build": "react-scripts build",
|
"webpack-manifest-plugin": "2.2.0",
|
||||||
"test": "react-scripts test",
|
"workbox-webpack-plugin": "5.1.4"
|
||||||
"eject": "react-scripts eject",
|
|
||||||
"storybook": "start-storybook -p 6006 -s public --no-dll",
|
|
||||||
"build-storybook": "build-storybook -s public --no-dll",
|
|
||||||
"prettify": "prettier --write ."
|
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
@ -74,9 +133,14 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.12.3",
|
"@babel/core": "^7.12.3",
|
||||||
"@babel/preset-typescript": "^7.12.7",
|
"@babel/plugin-proposal-class-properties": "^7.12.13",
|
||||||
|
"@babel/plugin-syntax-jsx": "^7.12.13",
|
||||||
|
"@babel/preset-env": "^7.12.17",
|
||||||
|
"@babel/preset-react": "^7.12.13",
|
||||||
|
"@babel/preset-typescript": "^7.12.17",
|
||||||
"autoprefixer": "^9.0.0",
|
"autoprefixer": "^9.0.0",
|
||||||
"babel-plugin-styled-components": "^1.12.0",
|
"babel-plugin-styled-components": "^1.12.0",
|
||||||
|
"copy-webpack-plugin": "^7.0.0",
|
||||||
"gulp": "^4.0.2",
|
"gulp": "^4.0.2",
|
||||||
"gulp-csso": "^4.0.1",
|
"gulp-csso": "^4.0.1",
|
||||||
"gulp-debug": "^4.0.0",
|
"gulp-debug": "^4.0.0",
|
||||||
@ -86,6 +150,8 @@
|
|||||||
"less-plugin-npm-import": "^2.1.0",
|
"less-plugin-npm-import": "^2.1.0",
|
||||||
"lint-staged": "10.5.3",
|
"lint-staged": "10.5.3",
|
||||||
"prettier": "2.2.1",
|
"prettier": "2.2.1",
|
||||||
"react-is": "^17.0.1"
|
"react-hot-loader": "^4.13.0",
|
||||||
|
"react-is": "^17.0.1",
|
||||||
|
"webpack-cli": "^4.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 2.2 KiB |
@ -1,46 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
<meta name="theme-color" content="#000000" />
|
|
||||||
<meta name="description" content="Web site created using create-react-app" />
|
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
|
||||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
|
|
||||||
crossorigin="anonymous"
|
|
||||||
/>
|
|
||||||
<!--
|
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
|
||||||
-->
|
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
|
||||||
<!--
|
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
|
||||||
-->
|
|
||||||
<title>React App</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
||||||
<div id="root"></div>
|
|
||||||
<!--
|
|
||||||
This HTML file is a template.
|
|
||||||
If you open it directly in the browser, you will see an empty page.
|
|
||||||
|
|
||||||
You can add webfonts, meta tags, or analytics to this file.
|
|
||||||
The build step will place the bundled scripts into the <body> tag.
|
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
|
||||||
-->
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -2,6 +2,8 @@ import { Dispatch } from "redux";
|
|||||||
import metricsAPI from "../api/metricsAPI";
|
import metricsAPI from "../api/metricsAPI";
|
||||||
import { GlobalTime } from "./global";
|
import { GlobalTime } from "./global";
|
||||||
import { ActionTypes } from "./types";
|
import { ActionTypes } from "./types";
|
||||||
|
import { Token } from "../utils/token";
|
||||||
|
import { toUTCEpoch } from "../utils/timeUtils";
|
||||||
|
|
||||||
export interface servicesListItem {
|
export interface servicesListItem {
|
||||||
serviceName: string;
|
serviceName: string;
|
||||||
@ -61,6 +63,7 @@ export const getServicesList = (globalTime: GlobalTime) => {
|
|||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch) => {
|
||||||
let request_string =
|
let request_string =
|
||||||
"services?start=" + globalTime.minTime + "&end=" + globalTime.maxTime;
|
"services?start=" + globalTime.minTime + "&end=" + globalTime.maxTime;
|
||||||
|
|
||||||
const response = await metricsAPI.get<servicesListItem[]>(request_string);
|
const response = await metricsAPI.get<servicesListItem[]>(request_string);
|
||||||
|
|
||||||
dispatch<getServicesListAction>({
|
dispatch<getServicesListAction>({
|
||||||
@ -123,9 +126,9 @@ export const getFilteredTraceMetrics = (
|
|||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch) => {
|
||||||
let request_string =
|
let request_string =
|
||||||
"spans/aggregates?start=" +
|
"spans/aggregates?start=" +
|
||||||
globalTime.minTime +
|
toUTCEpoch(globalTime.minTime) +
|
||||||
"&end=" +
|
"&end=" +
|
||||||
globalTime.maxTime +
|
toUTCEpoch(globalTime.maxTime) +
|
||||||
"&" +
|
"&" +
|
||||||
filter_params;
|
filter_params;
|
||||||
const response = await metricsAPI.get<customMetricsItem[]>(request_string);
|
const response = await metricsAPI.get<customMetricsItem[]>(request_string);
|
||||||
|
@ -2,6 +2,7 @@ import { ActionTypes } from "./types";
|
|||||||
import tracesAPI from "../api/tracesAPI";
|
import tracesAPI from "../api/tracesAPI";
|
||||||
import { Dispatch } from "redux";
|
import { Dispatch } from "redux";
|
||||||
import { GlobalTime } from "./global";
|
import { GlobalTime } from "./global";
|
||||||
|
import { toUTCEpoch } from "../utils/timeUtils";
|
||||||
|
|
||||||
// PNOTE
|
// PNOTE
|
||||||
// define trace interface - what it should return
|
// define trace interface - what it should return
|
||||||
@ -121,9 +122,9 @@ export const fetchTraces = (globalTime: GlobalTime, filter_params: string) => {
|
|||||||
if (globalTime) {
|
if (globalTime) {
|
||||||
let request_string =
|
let request_string =
|
||||||
"spans?limit=100&lookback=2d&start=" +
|
"spans?limit=100&lookback=2d&start=" +
|
||||||
globalTime.minTime +
|
toUTCEpoch(globalTime.minTime) +
|
||||||
"&end=" +
|
"&end=" +
|
||||||
globalTime.maxTime +
|
toUTCEpoch(globalTime.maxTime) +
|
||||||
"&" +
|
"&" +
|
||||||
filter_params;
|
filter_params;
|
||||||
const response = await tracesAPI.get<traceResponseNew>(request_string);
|
const response = await tracesAPI.get<traceResponseNew>(request_string);
|
||||||
|
@ -10,7 +10,7 @@ import { getUsageDataAction } from "./usage";
|
|||||||
import { updateTimeIntervalAction } from "./global";
|
import { updateTimeIntervalAction } from "./global";
|
||||||
|
|
||||||
export enum ActionTypes {
|
export enum ActionTypes {
|
||||||
updateTraceFilters= "UPDATE_TRACES_FILTER",
|
updateTraceFilters = "UPDATE_TRACES_FILTER",
|
||||||
updateInput = "UPDATE_INPUT",
|
updateInput = "UPDATE_INPUT",
|
||||||
fetchTraces = "FETCH_TRACES",
|
fetchTraces = "FETCH_TRACES",
|
||||||
fetchTraceItem = "FETCH_TRACE_ITEM",
|
fetchTraceItem = "FETCH_TRACE_ITEM",
|
||||||
|
@ -2,6 +2,7 @@ import { Dispatch } from "redux";
|
|||||||
import metricsAPI from "../api/metricsAPI";
|
import metricsAPI from "../api/metricsAPI";
|
||||||
import { ActionTypes } from "./types";
|
import { ActionTypes } from "./types";
|
||||||
import { GlobalTime } from "./global";
|
import { GlobalTime } from "./global";
|
||||||
|
import { toUTCEpoch } from "../utils/timeUtils";
|
||||||
|
|
||||||
export interface usageDataItem {
|
export interface usageDataItem {
|
||||||
timestamp: number;
|
timestamp: number;
|
||||||
@ -13,14 +14,16 @@ export interface getUsageDataAction {
|
|||||||
payload: usageDataItem[];
|
payload: usageDataItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getUsageData = (globalTime: GlobalTime) => {
|
export const getUsageData = (
|
||||||
|
minTime: number,
|
||||||
|
maxTime: number,
|
||||||
|
step: number,
|
||||||
|
service: string,
|
||||||
|
) => {
|
||||||
return async (dispatch: Dispatch) => {
|
return async (dispatch: Dispatch) => {
|
||||||
let request_string =
|
let request_string = `usage?start=${toUTCEpoch(minTime)}&end=${toUTCEpoch(
|
||||||
"usage?start=" +
|
maxTime,
|
||||||
globalTime.minTime +
|
)}&step=${step}&service=${service ? service : ""}`;
|
||||||
"&end=" +
|
|
||||||
globalTime.maxTime +
|
|
||||||
"&step=3600&service=driver";
|
|
||||||
//Step can only be multiple of 3600
|
//Step can only be multiple of 3600
|
||||||
const response = await metricsAPI.get<usageDataItem[]>(request_string);
|
const response = await metricsAPI.get<usageDataItem[]>(request_string);
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { ENVIRONMENT } from "../constants/env";
|
import { ENVIRONMENT } from "../constants/env";
|
||||||
|
import { Token } from "../utils/token";
|
||||||
|
|
||||||
// No auth for the API
|
// No auth for the API
|
||||||
export default axios.create({
|
export default axios.create({
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { ENVIRONMENT } from "../constants/env";
|
import { ENVIRONMENT } from "../constants/env";
|
||||||
|
import { Token } from "../utils/token";
|
||||||
|
|
||||||
export default axios.create({
|
export default axios.create({
|
||||||
// baseURL: 'https://api.telegram.org/bot1518273960:AAHcgVvym9a0Qkl-PKiCI84X1VZaVbkTud0/',
|
// baseURL: 'https://api.telegram.org/bot1518273960:AAHcgVvym9a0Qkl-PKiCI84X1VZaVbkTud0/',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { ENVIRONMENT } from "../constants/env";
|
import { ENVIRONMENT } from "../constants/env";
|
||||||
|
import { Token } from "../utils/token";
|
||||||
//import { format } from 'path';
|
//import { format } from 'path';
|
||||||
|
|
||||||
export default axios.create({
|
export default axios.create({
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
@import "~antd/dist/antd.dark.css";
|
@import "~antd/dist/antd.dark.css";
|
||||||
@import "~antd/dist/antd.compact.css";
|
@import "~antd/dist/antd.compact.css";
|
||||||
|
|
||||||
|
.ant-space-item {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
/* #components-layout-demo-side .logo {
|
/* #components-layout-demo-side .logo {
|
||||||
height: 32px;
|
height: 32px;
|
||||||
margin: 16px;
|
margin: 16px;
|
||||||
@ -10,3 +13,17 @@
|
|||||||
.site-layout .site-layout-background {
|
.site-layout .site-layout-background {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
} */
|
} */
|
||||||
|
.instrument-card{
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #313131;
|
||||||
|
padding: 33px 23px;
|
||||||
|
max-width: 800px;
|
||||||
|
margin-top: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#chart svg{
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
#chart{
|
||||||
|
width: 100%;
|
||||||
|
}
|
@ -13,22 +13,43 @@ import {
|
|||||||
BarChartOutlined,
|
BarChartOutlined,
|
||||||
DeploymentUnitOutlined,
|
DeploymentUnitOutlined,
|
||||||
AlignLeftOutlined,
|
AlignLeftOutlined,
|
||||||
|
AppstoreOutlined,
|
||||||
|
SettingOutlined,
|
||||||
|
ApiOutlined
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
|
|
||||||
import DateTimeSelector from "./DateTimeSelector";
|
import DateTimeSelector from "Src/components/DateTimeSelector";
|
||||||
import ShowBreadcrumbs from "./ShowBreadcrumbs";
|
import ShowBreadcrumbs from "Src/components/ShowBreadcrumbs";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
|
|
||||||
const { Content, Footer, Sider } = Layout;
|
const { Content, Footer, Sider } = Layout;
|
||||||
|
|
||||||
const ServiceMetrics = React.lazy(() => import("./metrics/ServiceMetricsDef"));
|
const ServiceMetrics = React.lazy(
|
||||||
const ServiceMap = React.lazy(() => import("./servicemap/ServiceMap"));
|
() => import("Src/components/metrics/ServiceMetricsDef"),
|
||||||
const TraceDetail = React.lazy(() => import("./traces/TraceDetail"));
|
);
|
||||||
const TraceGraph = React.lazy(() => import("./traces/TraceGraphDef"));
|
const ServiceMap = React.lazy(
|
||||||
const UsageExplorer = React.lazy(() => import("./usage/UsageExplorerDef"));
|
() => import("Src/components/servicemap/ServiceMap"),
|
||||||
const ServicesTable = React.lazy(() => import("./metrics/ServicesTableDef"));
|
);
|
||||||
// const Signup = React.lazy(() => import('./Signup'));
|
const TraceDetail = React.lazy(
|
||||||
|
() => import("Src/components/traces/TraceDetail"),
|
||||||
|
);
|
||||||
|
const TraceGraph = React.lazy(
|
||||||
|
() => import("Src/components/traces/TraceGraphDef"),
|
||||||
|
);
|
||||||
|
const UsageExplorer = React.lazy(
|
||||||
|
() => import("Src/components/usage/UsageExplorerDef"),
|
||||||
|
);
|
||||||
|
const ServicesTable = React.lazy(
|
||||||
|
() => import("Src/components/metrics/ServicesTableDef"),
|
||||||
|
);
|
||||||
|
const Signup = React.lazy(() => import("Src/components/Signup"));
|
||||||
|
const SettingsPage = React.lazy(
|
||||||
|
() => import("Src/components/settings/settingsPage"),
|
||||||
|
);
|
||||||
|
|
||||||
|
const IntstrumentationPage = React.lazy(
|
||||||
|
() => import("Src/components/add-instrumentation/instrumentationPage"),
|
||||||
|
);
|
||||||
//PNOTE
|
//PNOTE
|
||||||
//React. lazy currently only supports default exports. If the module you want to import uses named exports, you can create an intermediate module that reexports it as the default. This ensures that tree shaking keeps working and that you don't pull in unused components.
|
//React. lazy currently only supports default exports. If the module you want to import uses named exports, you can create an intermediate module that reexports it as the default. This ensures that tree shaking keeps working and that you don't pull in unused components.
|
||||||
|
|
||||||
@ -112,16 +133,26 @@ const App = () => {
|
|||||||
Usage Explorer
|
Usage Explorer
|
||||||
</NavLink>
|
</NavLink>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item key="5" icon={<SettingOutlined />}>
|
||||||
|
<NavLink to="/settings" style={{ fontSize: 12, textDecoration: "none" }}>
|
||||||
|
Settings
|
||||||
|
</NavLink>
|
||||||
|
</Menu.Item>
|
||||||
|
<Menu.Item key="6" icon={<ApiOutlined />}>
|
||||||
|
<NavLink to="/add-instrumentation" style={{ fontSize: 12, textDecoration: "none" }}>
|
||||||
|
Add instrumentation
|
||||||
|
</NavLink>
|
||||||
|
</Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
</Sider>
|
</Sider>
|
||||||
<Layout className="site-layout">
|
<Layout className="site-layout">
|
||||||
<Content style={{ margin: "0 16px" }}>
|
<Content style={{ margin: "0 16px" }}>
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={20}>
|
<Col span={16}>
|
||||||
<ShowBreadcrumbs />
|
<ShowBreadcrumbs />
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col span={4}>
|
<Col span={8}>
|
||||||
<DateTimeSelector />
|
<DateTimeSelector />
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -134,10 +165,11 @@ const App = () => {
|
|||||||
<Route path="/service-map" component={ServiceMap} />
|
<Route path="/service-map" component={ServiceMap} />
|
||||||
<Route path="/traces" exact component={TraceDetail} />
|
<Route path="/traces" exact component={TraceDetail} />
|
||||||
<Route path="/traces/:id" component={TraceGraph} />
|
<Route path="/traces/:id" component={TraceGraph} />
|
||||||
|
<Route path="/settings" exact component={SettingsPage} />
|
||||||
|
<Route path="/add-instrumentation" exact component={IntstrumentationPage} />
|
||||||
<Route path="/usage-explorer" component={UsageExplorer} />
|
<Route path="/usage-explorer" component={UsageExplorer} />
|
||||||
<Route path="/" component={ServicesTable} />
|
<Route path="/" component={ServicesTable} />
|
||||||
<Route path="/application" exact component={ServicesTable} />
|
<Route path="/application" exact component={ServicesTable} />
|
||||||
{/* <Route path="/signup" component={Signup} /> */}
|
|
||||||
</Switch>
|
</Switch>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Content>
|
</Content>
|
||||||
|
@ -1,45 +1,35 @@
|
|||||||
import React, { Suspense, useState } from "react";
|
import React, { Suspense, useState } from "react";
|
||||||
import { Spin } from "antd";
|
import { Spin } from "antd";
|
||||||
|
import { Route, Switch, Redirect } from "react-router-dom";
|
||||||
import {
|
import Signup from "./Signup";
|
||||||
BrowserRouter as Router,
|
const App = React.lazy(() => import("Src/components/App"));
|
||||||
Route,
|
|
||||||
Switch,
|
|
||||||
Redirect,
|
|
||||||
} from "react-router-dom";
|
|
||||||
|
|
||||||
const Signup = React.lazy(() => import("./Signup"));
|
|
||||||
const App = React.lazy(() => import("./App"));
|
|
||||||
|
|
||||||
const AppWrapper = () => {
|
const AppWrapper = () => {
|
||||||
const [isUserAuthenticated, setIsUserAuthenticated] = useState(false);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Router basename="/">
|
<Suspense fallback={<Spin size="large" />}>
|
||||||
<Suspense fallback={<Spin size="large" />}>
|
<Switch>
|
||||||
<Switch>
|
<Route path="/application" exact component={App} />
|
||||||
<Route path="/signup" exact component={Signup} />
|
<Route path="/application/:servicename" component={App} />
|
||||||
<Route path="/application" exact component={App} />
|
<Route path="/service-map" component={App} />
|
||||||
<Route path="/application/:servicename" component={App} />
|
<Route path="/traces" exact component={App} />
|
||||||
<Route path="/service-map" component={App} />
|
<Route path="/traces/:id" component={App} />
|
||||||
<Route path="/traces" exact component={App} />
|
<Route path="/usage-explorer" component={App} />
|
||||||
<Route path="/traces/:id" component={App} />
|
<Route path="/settings" component={App} />
|
||||||
<Route path="/usage-explorer" component={App} />
|
<Route path="/add-instrumentation" component={App} />
|
||||||
|
<Route path="/signup" component={Signup} />
|
||||||
<Route
|
<Route
|
||||||
path="/"
|
path="/"
|
||||||
exact
|
exact
|
||||||
render={() => {
|
render={() => {
|
||||||
return localStorage.getItem("isLoggedIn") === "yes" ? (
|
return localStorage.getItem("isLoggedIn") === "yes" ? (
|
||||||
<Redirect to="/application" />
|
<Redirect to="/application" />
|
||||||
) : (
|
) : (
|
||||||
<Redirect to="/signup" />
|
<Redirect to="/signup" />
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Switch>
|
</Switch>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Router>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -36,9 +36,11 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
const [startTime, setStartTime] = useState<moment.Moment | null>(null);
|
const [startTime, setStartTime] = useState<moment.Moment | null>(null);
|
||||||
const [endTime, setEndTime] = useState<moment.Moment | null>(null);
|
const [endTime, setEndTime] = useState<moment.Moment | null>(null);
|
||||||
const [refreshButtonHidden, setRefreshButtonHidden] = useState(false);
|
const [refreshButtonHidden, setRefreshButtonHidden] = useState(false);
|
||||||
|
const [refreshText, setRefreshText] = useState("");
|
||||||
|
const [refreshButtonClick, setRefreshButtoClick] = useState(0);
|
||||||
const [form_dtselector] = Form.useForm();
|
const [form_dtselector] = Form.useForm();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const updateTimeOnQueryParamChange = ()=>{
|
const updateTimeOnQueryParamChange = () => {
|
||||||
const timeDurationInLocalStorage = localStorage.getItem(
|
const timeDurationInLocalStorage = localStorage.getItem(
|
||||||
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
||||||
);
|
);
|
||||||
@ -46,13 +48,18 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const intervalInQueryParam = urlParams.get(METRICS_PAGE_QUERY_PARAM.interval);
|
const intervalInQueryParam = urlParams.get(METRICS_PAGE_QUERY_PARAM.interval);
|
||||||
const startTimeString = urlParams.get(METRICS_PAGE_QUERY_PARAM.startTime);
|
const startTimeString = urlParams.get(METRICS_PAGE_QUERY_PARAM.startTime);
|
||||||
const endTimeString = urlParams.get(METRICS_PAGE_QUERY_PARAM.endTime);
|
const endTimeString = urlParams.get(METRICS_PAGE_QUERY_PARAM.endTime);
|
||||||
|
|
||||||
// first pref: handle both startTime and endTime
|
// first pref: handle both startTime and endTime
|
||||||
if(startTimeString && startTimeString.length>0 && endTimeString && endTimeString.length>0){
|
if (
|
||||||
|
startTimeString &&
|
||||||
|
startTimeString.length > 0 &&
|
||||||
|
endTimeString &&
|
||||||
|
endTimeString.length > 0
|
||||||
|
) {
|
||||||
const startTime = moment(Number(startTimeString));
|
const startTime = moment(Number(startTimeString));
|
||||||
const endTime = moment(Number(endTimeString));
|
const endTime = moment(Number(endTimeString));
|
||||||
setCustomTime(startTime,endTime,true)
|
setCustomTime(startTime, endTime, true);
|
||||||
}
|
}
|
||||||
// first pref: handle intervalInQueryParam
|
// first pref: handle intervalInQueryParam
|
||||||
else if (intervalInQueryParam) {
|
else if (intervalInQueryParam) {
|
||||||
@ -64,8 +71,7 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
} else if (timeDurationInLocalStorage) {
|
} else if (timeDurationInLocalStorage) {
|
||||||
setMetricsTimeInterval(timeDurationInLocalStorage);
|
setMetricsTimeInterval(timeDurationInLocalStorage);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
}
|
|
||||||
|
|
||||||
// On URL Change
|
// On URL Change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -77,22 +83,20 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
updateTimeOnQueryParamChange();
|
updateTimeOnQueryParamChange();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const setMetricsTimeInterval= (value: string) => {
|
const setMetricsTimeInterval = (value: string) => {
|
||||||
props.updateTimeInterval(value);
|
props.updateTimeInterval(value);
|
||||||
setTimeInterval(value);
|
setTimeInterval(value);
|
||||||
setEndTime(null);
|
setEndTime(null);
|
||||||
setStartTime(null);
|
setStartTime(null);
|
||||||
|
|
||||||
window.localStorage.setItem(
|
window.localStorage.setItem(LOCAL_STORAGE.METRICS_TIME_IN_DURATION, value);
|
||||||
LOCAL_STORAGE.METRICS_TIME_IN_DURATION,
|
|
||||||
value,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
const setCustomTime= (startTime: moment.Moment, endTime: moment.Moment, triggeredByURLChange = false) => {
|
const setCustomTime = (
|
||||||
props.updateTimeInterval("custom", [
|
startTime: moment.Moment,
|
||||||
startTime.valueOf(),
|
endTime: moment.Moment,
|
||||||
endTime.valueOf(),
|
triggeredByURLChange = false,
|
||||||
]);
|
) => {
|
||||||
|
props.updateTimeInterval("custom", [startTime.valueOf(), endTime.valueOf()]);
|
||||||
setEndTime(endTime);
|
setEndTime(endTime);
|
||||||
setStartTime(startTime);
|
setStartTime(startTime);
|
||||||
};
|
};
|
||||||
@ -103,10 +107,17 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
}); //pass time in URL query param for all choices except custom in datetime picker
|
}); //pass time in URL query param for all choices except custom in datetime picker
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateUrlForCustomTime= (startTime: moment.Moment, endTime: moment.Moment, triggeredByURLChange = false) => {
|
const updateUrlForCustomTime = (
|
||||||
props.history.push(`?${METRICS_PAGE_QUERY_PARAM.startTime}=${startTime.valueOf()}&${METRICS_PAGE_QUERY_PARAM.endTime}=${endTime.valueOf()}`);
|
startTime: moment.Moment,
|
||||||
}
|
endTime: moment.Moment,
|
||||||
|
triggeredByURLChange = false,
|
||||||
|
) => {
|
||||||
|
props.history.push(
|
||||||
|
`?${METRICS_PAGE_QUERY_PARAM.startTime}=${startTime.valueOf()}&${
|
||||||
|
METRICS_PAGE_QUERY_PARAM.endTime
|
||||||
|
}=${endTime.valueOf()}`,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnSelect = (value: string) => {
|
const handleOnSelect = (value: string) => {
|
||||||
if (value === "custom") {
|
if (value === "custom") {
|
||||||
@ -129,7 +140,7 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
const startTime = dateTimeRange[0].valueOf();
|
const startTime = dateTimeRange[0].valueOf();
|
||||||
const endTime = dateTimeRange[1].valueOf();
|
const endTime = dateTimeRange[1].valueOf();
|
||||||
|
|
||||||
updateUrlForCustomTime(moment(startTime),moment(endTime))
|
updateUrlForCustomTime(moment(startTime), moment(endTime));
|
||||||
//setting globaltime
|
//setting globaltime
|
||||||
setRefreshButtonHidden(true);
|
setRefreshButtonHidden(true);
|
||||||
form_dtselector.setFieldsValue({
|
form_dtselector.setFieldsValue({
|
||||||
@ -143,25 +154,37 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const timeSinceLastRefresh = () => {
|
const timeSinceLastRefresh = () => {
|
||||||
let timeDiffSec = Math.round(
|
const currentTime = moment();
|
||||||
(Date.now() - Math.round(props.globalTime.maxTime / 1000000)) / 1000,
|
const lastRefresh = moment(props.globalTime.maxTime / 1000000);
|
||||||
);
|
const duration = moment.duration(currentTime.diff(lastRefresh));
|
||||||
|
|
||||||
//How will Refresh button get updated? Needs to be periodically updated via timer.
|
const secondsDiff = Math.floor(duration.asSeconds());
|
||||||
// For now, not returning any text here
|
const minutedDiff = Math.floor(duration.asMinutes());
|
||||||
// if (timeDiffSec < 60)
|
const hoursDiff = Math.floor(duration.asHours());
|
||||||
// return timeDiffSec.toString()+' s';
|
|
||||||
// else if (timeDiffSec < 3600)
|
if (hoursDiff > 0) {
|
||||||
// return Math.round(timeDiffSec/60).toString()+' min';
|
return `Last refresh - ${hoursDiff} hrs ago`;
|
||||||
// else
|
} else if (minutedDiff > 0) {
|
||||||
// return Math.round(timeDiffSec/3600).toString()+' hr';
|
return `Last refresh - ${minutedDiff} mins ago`;
|
||||||
return null;
|
}
|
||||||
|
return `Last refresh - ${secondsDiff} sec ago`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRefresh = () => {
|
const handleRefresh = () => {
|
||||||
|
setRefreshButtoClick(refreshButtonClick + 1);
|
||||||
setMetricsTimeInterval(timeInterval);
|
setMetricsTimeInterval(timeInterval);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setRefreshText("");
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
setRefreshText(timeSinceLastRefresh());
|
||||||
|
}, 2000);
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, [props.location, refreshButtonClick]);
|
||||||
|
|
||||||
const options = [
|
const options = [
|
||||||
{ value: "custom", label: "Custom" },
|
{ value: "custom", label: "Custom" },
|
||||||
{ value: "15min", label: "Last 15 min" },
|
{ value: "15min", label: "Last 15 min" },
|
||||||
@ -174,31 +197,47 @@ const _DateTimeSelector = (props: DateTimeSelectorProps) => {
|
|||||||
if (props.location.pathname.startsWith("/usage-explorer")) {
|
if (props.location.pathname.startsWith("/usage-explorer")) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
|
const inputLabeLToShow =
|
||||||
const inputLabeLToShow = startTime && endTime? (`${startTime.format("YYYY/MM/DD HH:mm")} - ${endTime.format("YYYY/MM/DD HH:mm")}`):timeInterval
|
startTime && endTime
|
||||||
|
? `${startTime.format("YYYY/MM/DD HH:mm")} - ${endTime.format(
|
||||||
|
"YYYY/MM/DD HH:mm",
|
||||||
|
)}`
|
||||||
|
: timeInterval;
|
||||||
return (
|
return (
|
||||||
<DateTimeWrapper>
|
<DateTimeWrapper>
|
||||||
<Space>
|
<Space style={{ float: "right", display: "block" }}>
|
||||||
<Form
|
<Space>
|
||||||
form={form_dtselector}
|
<Form
|
||||||
layout="inline"
|
form={form_dtselector}
|
||||||
initialValues={{ interval: "15min" }}
|
layout="inline"
|
||||||
style={{ marginTop: 10, marginBottom: 10 }}
|
initialValues={{ interval: "15min" }}
|
||||||
>
|
style={{ marginTop: 10, marginBottom: 10 }}
|
||||||
<FormItem></FormItem>
|
>
|
||||||
<Select onSelect={handleOnSelect} value={inputLabeLToShow}>
|
<Select onSelect={handleOnSelect} value={inputLabeLToShow}>
|
||||||
{options.map(({ value, label }) => (
|
{options.map(({ value, label }) => (
|
||||||
<Option value={value}>{label}</Option>
|
<Option value={value}>{label}</Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
|
||||||
<FormItem hidden={refreshButtonHidden} name="refresh_button">
|
<FormItem hidden={refreshButtonHidden} name="refresh_button">
|
||||||
<Button type="primary" onClick={handleRefresh}>
|
<Button type="primary" onClick={handleRefresh}>
|
||||||
Refresh {timeSinceLastRefresh()}
|
Refresh
|
||||||
</Button>
|
</Button>
|
||||||
{/* if refresh time is more than x min, give a message? */}
|
</FormItem>
|
||||||
</FormItem>
|
</Form>
|
||||||
</Form>
|
</Space>
|
||||||
|
<Space
|
||||||
|
style={{
|
||||||
|
float: "right",
|
||||||
|
display: "block",
|
||||||
|
marginRight: 20,
|
||||||
|
minHeight: 23,
|
||||||
|
width: 200,
|
||||||
|
textAlign: "right",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{refreshText}
|
||||||
|
</Space>
|
||||||
<CustomDateTimeModal
|
<CustomDateTimeModal
|
||||||
visible={customDTPickerVisible}
|
visible={customDTPickerVisible}
|
||||||
onCreate={handleCustomDate}
|
onCreate={handleCustomDate}
|
||||||
|
@ -14,6 +14,8 @@ const breadcrumbNameMap: any = {
|
|||||||
"/traces": "Traces",
|
"/traces": "Traces",
|
||||||
"/service-map": "Service Map",
|
"/service-map": "Service Map",
|
||||||
"/usage-explorer": "Usage Explorer",
|
"/usage-explorer": "Usage Explorer",
|
||||||
|
"/add-instrumentation": "Add instrumentation",
|
||||||
|
"/settings": "Settings",
|
||||||
};
|
};
|
||||||
|
|
||||||
const ShowBreadcrumbs = withRouter((props) => {
|
const ShowBreadcrumbs = withRouter((props) => {
|
||||||
|
@ -22,33 +22,16 @@ const Signup = (props: SignUpProps) => {
|
|||||||
|
|
||||||
const updateForm = (name: any, target: any, valueAttr = "value") => {
|
const updateForm = (name: any, target: any, valueAttr = "value") => {
|
||||||
/* Validate password (if applicable) */
|
/* Validate password (if applicable) */
|
||||||
if (name === "password") {
|
if (name === "firstName") {
|
||||||
let password = target[valueAttr];
|
|
||||||
const valid = password.length >= 8;
|
|
||||||
setFormState({
|
|
||||||
...formState,
|
|
||||||
password: { ...formState.password, valid, value: target[valueAttr] },
|
|
||||||
});
|
|
||||||
} else if (name === "firstName") {
|
|
||||||
setFormState({
|
setFormState({
|
||||||
...formState,
|
...formState,
|
||||||
firstName: { ...formState.firstName, value: target[valueAttr] },
|
firstName: { ...formState.firstName, value: target[valueAttr] },
|
||||||
});
|
});
|
||||||
} else if (name === "companyName") {
|
|
||||||
setFormState({
|
|
||||||
...formState,
|
|
||||||
companyName: { ...formState.companyName, value: target[valueAttr] },
|
|
||||||
});
|
|
||||||
} else if (name === "email") {
|
} else if (name === "email") {
|
||||||
setFormState({
|
setFormState({
|
||||||
...formState,
|
...formState,
|
||||||
email: { ...formState.email, value: target[valueAttr] },
|
email: { ...formState.email, value: target[valueAttr] },
|
||||||
});
|
});
|
||||||
} else if (name === "emailOptIn") {
|
|
||||||
setFormState({
|
|
||||||
...formState,
|
|
||||||
emailOptIn: { ...formState.emailOptIn, value: target[valueAttr] },
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,41 +42,14 @@ const Signup = (props: SignUpProps) => {
|
|||||||
|
|
||||||
setState({ ...state, submitted: true });
|
setState({ ...state, submitted: true });
|
||||||
|
|
||||||
/* Password has custom validation */
|
|
||||||
if (!formState.password.valid) {
|
|
||||||
// if (passwordInput.current){
|
|
||||||
// passwordInput.current.focus()
|
|
||||||
// }
|
|
||||||
// return
|
|
||||||
}
|
|
||||||
const payload = {
|
const payload = {
|
||||||
first_name: formState.firstName,
|
first_name: formState.firstName,
|
||||||
company_name: formState.companyName || undefined,
|
|
||||||
email: formState.email,
|
email: formState.email,
|
||||||
password: formState.password,
|
|
||||||
email_opt_in: formState.emailOptIn.value,
|
|
||||||
// plan, // Pass it along if on QS, won't have any effect unless on multitenancy
|
|
||||||
};
|
};
|
||||||
// createAccount(payload)
|
|
||||||
|
|
||||||
// axios.get(`https://jsonplaceholder.typicode.com/users`)
|
|
||||||
// .then(res => {
|
|
||||||
// console.log(res);
|
|
||||||
// console.log(res.data);
|
|
||||||
// })
|
|
||||||
|
|
||||||
let texttolog = JSON.stringify(payload);
|
let texttolog = JSON.stringify(payload);
|
||||||
|
|
||||||
// submitForm.get('sendMessage', {
|
|
||||||
// params: {
|
|
||||||
// chat_id: 351813222,
|
|
||||||
// text:texttolog,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ).then(res => {
|
|
||||||
// console.log(res);
|
|
||||||
// console.log(res.data);
|
|
||||||
// })
|
|
||||||
|
|
||||||
submitForm.post("user?email=" + texttolog).then((res) => {
|
submitForm.post("user?email=" + texttolog).then((res) => {
|
||||||
console.log(res);
|
console.log(res);
|
||||||
@ -162,29 +118,7 @@ const Signup = (props: SignUpProps) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
|
||||||
className={`input-set ${
|
|
||||||
state.submitted && !formState.password.valid ? "errored" : ""
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<label htmlFor="signupPassword">Password</label>
|
|
||||||
<Input.Password
|
|
||||||
value={formState.password.value}
|
|
||||||
onChange={(e) => updateForm("password", e.target)}
|
|
||||||
required
|
|
||||||
ref={passwordInput}
|
|
||||||
// disabled={accountLoading}
|
|
||||||
id="signupPassword"
|
|
||||||
/>
|
|
||||||
<Suspense fallback={<span />}>
|
|
||||||
{/* <PasswordStrength password={formState.password.value} /> */}
|
|
||||||
</Suspense>
|
|
||||||
{!formState.password && (
|
|
||||||
<span className="caption">
|
|
||||||
Your password must have at least 8 characters.
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="input-set">
|
<div className="input-set">
|
||||||
<label htmlFor="signupFirstName">First Name</label>
|
<label htmlFor="signupFirstName">First Name</label>
|
||||||
@ -199,28 +133,7 @@ const Signup = (props: SignUpProps) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="input-set">
|
<div className="text-center space-top" style={{marginTop: 12}}>
|
||||||
<label htmlFor="signupCompanyName">Company or Project</label>
|
|
||||||
<Input
|
|
||||||
placeholder="Netflix"
|
|
||||||
value={formState.companyName.value}
|
|
||||||
onChange={(e) => updateForm("companyName", e.target)}
|
|
||||||
// disabled={accountLoading}
|
|
||||||
id="signupCompanyName"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<Checkbox
|
|
||||||
checked={formState.emailOptIn.value}
|
|
||||||
onChange={(e) => updateForm("emailOptIn", e.target, "checked")}
|
|
||||||
// disabled={accountLoading}
|
|
||||||
>
|
|
||||||
Send me occasional emails about security and product updates. You may
|
|
||||||
unsubscribe at any time.
|
|
||||||
</Checkbox>
|
|
||||||
</div>
|
|
||||||
<div className="text-center space-top">
|
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
htmlType="submit"
|
htmlType="submit"
|
||||||
|
5
frontend/src/components/Test.tsx
Normal file
5
frontend/src/components/Test.tsx
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const Test = () => {
|
||||||
|
return <div>INSIDE PUBLIC CODE</div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Test;
|
@ -0,0 +1,51 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Form, Input, Space } from "antd";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { Tooltip } from "antd";
|
||||||
|
import {
|
||||||
|
InfoCircleOutlined,
|
||||||
|
EyeTwoTone,
|
||||||
|
EyeInvisibleOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import { StoreState } from "../../reducers";
|
||||||
|
import { useAuthenticationData } from "../../hooks/authentication";
|
||||||
|
import { TOKEN_DATE } from "../../../../../sass/frontend/src/constants/accessToken";
|
||||||
|
import { Alert } from "antd";
|
||||||
|
|
||||||
|
interface InstrumentationPageProps {}
|
||||||
|
|
||||||
|
|
||||||
|
const InstrumentationPage = (props: InstrumentationPageProps) => {
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
|
||||||
|
|
||||||
|
<Space style={{ marginLeft: 60, marginTop: 48, display: 'block' }}>
|
||||||
|
<div>
|
||||||
|
<h2>
|
||||||
|
Instrument your application
|
||||||
|
</h2>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={"instrument-card"}>
|
||||||
|
Congrats, you have successfully installed SigNoz!<br/>
|
||||||
|
To start seeing YOUR application data here, follow the instructions in the docs -
|
||||||
|
<a href={"https://signoz.io/docs/instrumentation/overview"}> https://signoz.io/docs/instrumentation/overview</a>
|
||||||
|
<br/>
|
||||||
|
If you face any issues, join our <a href={"https://signoz-community.slack.com/join/shared_invite/zt-lrjknbbp-J_mI13rlw8pGF4EWBnorJA"}>
|
||||||
|
slack community</a> to ask any questions or mail us at <a href={"mailto:support@signoz.io"}>
|
||||||
|
support@signoz.io
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</Space>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state: StoreState): {} => {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, {})(InstrumentationPage);
|
31
frontend/src/components/common/Modal.tsx
Normal file
31
frontend/src/components/common/Modal.tsx
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import React, { ReactElement, useState } from "react";
|
||||||
|
import { Modal, Button } from "antd";
|
||||||
|
|
||||||
|
export const CustomModal = ({
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
isModalVisible,
|
||||||
|
setIsModalVisible,
|
||||||
|
footer,
|
||||||
|
closable = true,
|
||||||
|
}: {
|
||||||
|
isModalVisible: boolean;
|
||||||
|
closable?: boolean;
|
||||||
|
setIsModalVisible: Function;
|
||||||
|
footer?: any;
|
||||||
|
title: string;
|
||||||
|
children: ReactElement;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
title={title}
|
||||||
|
visible={isModalVisible}
|
||||||
|
footer={footer}
|
||||||
|
closable={closable}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</Modal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -90,7 +90,7 @@ class ErrorRateChart extends React.Component<ErrorRateChartProps> {
|
|||||||
|
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: "Error per sec",
|
text: "",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
position: "top",
|
position: "top",
|
||||||
padding: 2,
|
padding: 2,
|
||||||
@ -202,7 +202,7 @@ class ErrorRateChart extends React.Component<ErrorRateChartProps> {
|
|||||||
labels: ndata.map((s) => new Date(s.timestamp / 1000000)), // converting from nano second to mili second
|
labels: ndata.map((s) => new Date(s.timestamp / 1000000)), // converting from nano second to mili second
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Errors per sec",
|
label: "",
|
||||||
data: ndata.map((s) => s.errorRate),
|
data: ndata.map((s) => s.errorRate),
|
||||||
pointRadius: 0.5,
|
pointRadius: 0.5,
|
||||||
borderColor: "rgba(227, 74, 51,1)", // Can also add transparency in border color
|
borderColor: "rgba(227, 74, 51,1)", // Can also add transparency in border color
|
||||||
@ -215,6 +215,7 @@ class ErrorRateChart extends React.Component<ErrorRateChartProps> {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{this.GraphTracePopUp()}
|
{this.GraphTracePopUp()}
|
||||||
|
<div style={{textAlign: "center"}}>Errors per sec</div>
|
||||||
<ChartJSLine
|
<ChartJSLine
|
||||||
ref={this.chartRef}
|
ref={this.chartRef}
|
||||||
data={data_chartJS}
|
data={data_chartJS}
|
||||||
|
@ -15,7 +15,7 @@ interface GenericVisualizationsProps {
|
|||||||
|
|
||||||
const GenericVisualizations = (props: GenericVisualizationsProps) => {
|
const GenericVisualizations = (props: GenericVisualizationsProps) => {
|
||||||
const data = {
|
const data = {
|
||||||
labels: props.data.map((s) => new Date(s.timestamp / 1000000)),
|
labels: props.data !== undefined && props.data.map((s) => new Date(s.timestamp / 1000000)),
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
data: props.data.map((s) => s.value),
|
data: props.data.map((s) => s.value),
|
||||||
|
@ -96,7 +96,7 @@ class LatencyLineChart extends React.Component<LatencyLineChartProps> {
|
|||||||
|
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: "Application Latency in ms",
|
text: "",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
position: "top",
|
position: "top",
|
||||||
padding: 8,
|
padding: 8,
|
||||||
@ -187,7 +187,7 @@ class LatencyLineChart extends React.Component<LatencyLineChartProps> {
|
|||||||
>
|
>
|
||||||
<PopUpElements
|
<PopUpElements
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
this.props.popupClickHandler(this.state.firstpoint_ts)
|
this.props.popupClickHandler(this.state.firstpoint_ts);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
View Traces
|
View Traces
|
||||||
@ -237,11 +237,14 @@ class LatencyLineChart extends React.Component<LatencyLineChartProps> {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{this.GraphTracePopUp()}
|
{this.GraphTracePopUp()}
|
||||||
<ChartJSLine
|
<div>
|
||||||
ref={this.chartRef}
|
<div style={{textAlign: "center"}}>Application latency in ms</div>
|
||||||
data={data_chartJS}
|
<ChartJSLine
|
||||||
options={this.options_charts}
|
ref={this.chartRef}
|
||||||
/>
|
data={data_chartJS}
|
||||||
|
options={this.options_charts}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ class RequestRateChart extends React.Component<RequestRateChartProps> {
|
|||||||
|
|
||||||
title: {
|
title: {
|
||||||
display: true,
|
display: true,
|
||||||
text: "Request per sec",
|
text: "",
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
position: "top",
|
position: "top",
|
||||||
padding: 2,
|
padding: 2,
|
||||||
@ -207,6 +207,7 @@ class RequestRateChart extends React.Component<RequestRateChartProps> {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{this.GraphTracePopUp()}
|
{this.GraphTracePopUp()}
|
||||||
|
<div style={{textAlign: "center"}}>Request per sec</div>
|
||||||
<ChartJSLine
|
<ChartJSLine
|
||||||
ref={this.chartRef}
|
ref={this.chartRef}
|
||||||
data={data_chartJS}
|
data={data_chartJS}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { Tabs, Card, Row, Col } from "antd";
|
import { Tabs, Card, Row, Col } from "antd";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { useParams, RouteComponentProps } from "react-router-dom";
|
import { useParams, RouteComponentProps } from "react-router-dom";
|
||||||
@ -31,7 +31,7 @@ interface ServicesMetricsProps extends RouteComponentProps<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _ServiceMetrics = (props: ServicesMetricsProps) => {
|
const _ServiceMetrics = (props: ServicesMetricsProps) => {
|
||||||
const {servicename} = useParams<{ servicename?: string }>();
|
const { servicename } = useParams<{ servicename?: string }>();
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.getServicesMetrics(servicename, props.globalTime);
|
props.getServicesMetrics(servicename, props.globalTime);
|
||||||
props.getTopEndpoints(servicename, props.globalTime);
|
props.getTopEndpoints(servicename, props.globalTime);
|
||||||
@ -41,20 +41,18 @@ const _ServiceMetrics = (props: ServicesMetricsProps) => {
|
|||||||
const tMinus15Min = timestamp / 1000000 - 15 * 60 * 1000;
|
const tMinus15Min = timestamp / 1000000 - 15 * 60 * 1000;
|
||||||
const currentTime = timestamp / 1000000;
|
const currentTime = timestamp / 1000000;
|
||||||
|
|
||||||
props.updateTimeInterval("custom", [
|
props.updateTimeInterval("custom", [tMinus15Min, currentTime]); // updateTimeInterval takes second range in ms -- give -5 min to selected time,
|
||||||
tMinus15Min,
|
|
||||||
currentTime,
|
|
||||||
]); // updateTimeInterval takes second range in ms -- give -5 min to selected time,
|
|
||||||
|
|
||||||
const urlParams = new URLSearchParams();
|
const urlParams = new URLSearchParams();
|
||||||
urlParams.set(METRICS_PAGE_QUERY_PARAM.startTime,tMinus15Min.toString())
|
urlParams.set(METRICS_PAGE_QUERY_PARAM.startTime, tMinus15Min.toString());
|
||||||
urlParams.set(METRICS_PAGE_QUERY_PARAM.endTime,currentTime.toString())
|
urlParams.set(METRICS_PAGE_QUERY_PARAM.endTime, currentTime.toString());
|
||||||
if(servicename){
|
if (servicename) {
|
||||||
urlParams.set(METRICS_PAGE_QUERY_PARAM.service,servicename)
|
urlParams.set(METRICS_PAGE_QUERY_PARAM.service, servicename);
|
||||||
}
|
}
|
||||||
|
|
||||||
props.history.push(`/traces?${urlParams.toString()}`);
|
props.history.push(`/traces?${urlParams.toString()}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs defaultActiveKey="1">
|
<Tabs defaultActiveKey="1">
|
||||||
<TabPane tab="Application Metrics" key="1">
|
<TabPane tab="Application Metrics" key="1">
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { NavLink } from "react-router-dom";
|
import { NavLink } from "react-router-dom";
|
||||||
import { Spin, Table } from "antd";
|
import { Button, Space, Spin, Table } from "antd";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { getServicesList, GlobalTime, servicesListItem } from "../../actions";
|
import { getServicesList, GlobalTime, servicesListItem } from "../../actions";
|
||||||
import { StoreState } from "../../reducers";
|
import { StoreState } from "../../reducers";
|
||||||
|
import { CustomModal } from "../common/Modal";
|
||||||
|
|
||||||
interface ServicesTableProps {
|
interface ServicesTableProps {
|
||||||
servicesList: servicesListItem[];
|
servicesList: servicesListItem[];
|
||||||
@ -31,14 +32,14 @@ const Wrapper = styled.div`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
const TableLoadingWrapper = styled.div`
|
const TableLoadingWrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-top: 80px;
|
margin-top: 80px;
|
||||||
`
|
`;
|
||||||
|
|
||||||
const LoadingText = styled.div`
|
const LoadingText = styled.div`
|
||||||
margin-left: 16px;
|
margin-left: 16px;
|
||||||
`
|
`;
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@ -80,25 +81,93 @@ const columns = [
|
|||||||
const _ServicesTable = (props: ServicesTableProps) => {
|
const _ServicesTable = (props: ServicesTableProps) => {
|
||||||
const search = useLocation().search;
|
const search = useLocation().search;
|
||||||
const time_interval = new URLSearchParams(search).get("time");
|
const time_interval = new URLSearchParams(search).get("time");
|
||||||
const [dataFetched, setDataFetched] = useState(false)
|
const [initialDataFetch, setDataFetched] = useState(false);
|
||||||
useEffect(() => {
|
const [errorObject, setErrorObject] = useState({
|
||||||
/*
|
message: "",
|
||||||
@Note - Change this from action to thunk
|
isError: false,
|
||||||
*/
|
});
|
||||||
props.getServicesList(props.globalTime).then(()=>{
|
const isEmptyServiceList =
|
||||||
setDataFetched(true)
|
!initialDataFetch && props.servicesList.length === 0;
|
||||||
}).catch((e:string)=>{
|
const refetchFromBackend = isEmptyServiceList || errorObject.isError;
|
||||||
alert(e)
|
const [skipOnboarding, setSkipOnboarding] = useState(
|
||||||
});
|
localStorage.getItem("skip_onboarding") === "true",
|
||||||
}, [props.globalTime]);
|
);
|
||||||
|
|
||||||
if(!dataFetched){
|
const onContinueClick = () => {
|
||||||
|
localStorage.setItem("skip_onboarding", "true");
|
||||||
|
setSkipOnboarding(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
function getApiServiceData() {
|
||||||
|
props
|
||||||
|
.getServicesList(props.globalTime)
|
||||||
|
.then(() => {
|
||||||
|
setDataFetched(true);
|
||||||
|
setErrorObject({ message: "", isError: false });
|
||||||
|
})
|
||||||
|
.catch((e: string) => {
|
||||||
|
setErrorObject({ message: e, isError: true });
|
||||||
|
setDataFetched(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(getApiServiceData, [props.globalTime]);
|
||||||
|
useEffect(() => {
|
||||||
|
if (props.servicesList.length > 1) {
|
||||||
|
localStorage.removeItem("skip_onboarding");
|
||||||
|
}
|
||||||
|
|
||||||
|
refetchFromBackend && setTimeout(getApiServiceData, 50000);
|
||||||
|
}, [props.servicesList, errorObject]);
|
||||||
|
|
||||||
|
if (!initialDataFetch) {
|
||||||
return (
|
return (
|
||||||
<TableLoadingWrapper>
|
<TableLoadingWrapper>
|
||||||
<Spin/>
|
<Spin />
|
||||||
<LoadingText>Fetching data</LoadingText>
|
<LoadingText>Fetching data</LoadingText>
|
||||||
</TableLoadingWrapper>
|
</TableLoadingWrapper>
|
||||||
)
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (refetchFromBackend && !skipOnboarding) {
|
||||||
|
return (
|
||||||
|
<CustomModal
|
||||||
|
title={"Setup instrumentation"}
|
||||||
|
isModalVisible={true}
|
||||||
|
closable={false}
|
||||||
|
setIsModalVisible={() => {}}
|
||||||
|
footer={[
|
||||||
|
<Button key="submit" type="primary" onClick={onContinueClick}>
|
||||||
|
Continue without instrumentation
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<iframe
|
||||||
|
width="100%"
|
||||||
|
height="265"
|
||||||
|
src="https://www.youtube.com/embed/Ly34WBQ2640"
|
||||||
|
frameBorder="0"
|
||||||
|
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||||
|
allowFullScreen
|
||||||
|
></iframe>
|
||||||
|
<div style={{ margin: "20px 0" }}>
|
||||||
|
<Spin />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
No instrumentation data.
|
||||||
|
<br />
|
||||||
|
Please instrument your application as mentioned{" "}
|
||||||
|
<a
|
||||||
|
href={"https://signoz.io/docs/instrumentation/overview"}
|
||||||
|
target={"_blank"}
|
||||||
|
>
|
||||||
|
here
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CustomModal>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -108,6 +177,22 @@ const _ServicesTable = (props: ServicesTableProps) => {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
pagination={false}
|
pagination={false}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{props.servicesList[0] !== undefined && props.servicesList[0].numCalls === 0 && (
|
||||||
|
<Space
|
||||||
|
style={{ width: "100%", margin: "40px 0", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
No applications present. Please add instrumentation (follow this
|
||||||
|
<a
|
||||||
|
href={"https://signoz.io/docs/instrumentation/overview"}
|
||||||
|
target={"_blank"}
|
||||||
|
style={{ marginLeft: 3 }}
|
||||||
|
>
|
||||||
|
guide
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
63
frontend/src/components/settings/settingsPage.tsx
Normal file
63
frontend/src/components/settings/settingsPage.tsx
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import { Form, Input, Space } from "antd";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { Tooltip } from "antd";
|
||||||
|
import {
|
||||||
|
InfoCircleOutlined,
|
||||||
|
EyeTwoTone,
|
||||||
|
EyeInvisibleOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import { StoreState } from "../../reducers";
|
||||||
|
import { useAuthenticationData } from "../../hooks/authentication";
|
||||||
|
import { TOKEN_DATE } from "../../../../../sass/frontend/src/constants/accessToken";
|
||||||
|
import { Alert } from "antd";
|
||||||
|
|
||||||
|
interface SettingsPageProps {}
|
||||||
|
|
||||||
|
const layout = {
|
||||||
|
labelCol: { span: 3 },
|
||||||
|
wrapperCol: { span: 6 },
|
||||||
|
};
|
||||||
|
|
||||||
|
const SettingsPage = (props: SettingsPageProps) => {
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
form.setFieldsValue({
|
||||||
|
retention_period: "3 days",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<Form
|
||||||
|
{...layout}
|
||||||
|
name="basic"
|
||||||
|
initialValues={{ remember: true }}
|
||||||
|
style={{ marginLeft: 20 }}
|
||||||
|
form={form}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label="Retention Period"
|
||||||
|
name="retention_period"
|
||||||
|
rules={[{ required: false }]}
|
||||||
|
>
|
||||||
|
<Input style={{ marginLeft: 60 }} disabled={true} />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
|
||||||
|
<Space style={{ marginLeft: 60, marginTop: 48 }}>
|
||||||
|
<Alert
|
||||||
|
message="Mail us at support@signoz.io to get instructions on how to change your retention period"
|
||||||
|
type="info"
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapStateToProps = (state: StoreState): {} => {
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, {})(SettingsPage);
|
@ -5,12 +5,13 @@ import { Store } from "antd/lib/form/interface";
|
|||||||
interface LatencyModalFormProps {
|
interface LatencyModalFormProps {
|
||||||
onCreate: (values: Store) => void; //Store is defined in antd forms library
|
onCreate: (values: Store) => void; //Store is defined in antd forms library
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
latencyFilterValues: {min: string, max: string}
|
latencyFilterValues: { min: string; max: string };
|
||||||
}
|
}
|
||||||
|
|
||||||
const LatencyModalForm: React.FC<LatencyModalFormProps> = ({
|
const LatencyModalForm: React.FC<LatencyModalFormProps> = ({
|
||||||
onCreate,
|
onCreate,
|
||||||
onCancel,latencyFilterValues
|
onCancel,
|
||||||
|
latencyFilterValues,
|
||||||
}) => {
|
}) => {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
return (
|
return (
|
||||||
|
@ -43,18 +43,31 @@ const _TraceFilter = (props: TraceFilterProps) => {
|
|||||||
const [serviceList, setServiceList] = useState<string[]>([]);
|
const [serviceList, setServiceList] = useState<string[]>([]);
|
||||||
const [operationList, setOperationsList] = useState<string[]>([]);
|
const [operationList, setOperationsList] = useState<string[]>([]);
|
||||||
const [tagKeyOptions, setTagKeyOptions] = useState<TagKeyOptionItem[]>([]);
|
const [tagKeyOptions, setTagKeyOptions] = useState<TagKeyOptionItem[]>([]);
|
||||||
const location = useLocation()
|
const location = useLocation();
|
||||||
const urlParams = new URLSearchParams(location.search.split("?")[1]);
|
const urlParams = new URLSearchParams(location.search.split("?")[1]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
console.log("Mera")
|
||||||
|
handleApplyFilterForm({
|
||||||
|
service: "",
|
||||||
|
tags: [],
|
||||||
|
operation: "",
|
||||||
|
latency: { min: "", max: "" },
|
||||||
|
})
|
||||||
|
},[])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
metricsAPI.get<string[]>("services/list").then((response) => {
|
metricsAPI
|
||||||
setServiceList(response.data);
|
.get<string[]>("services/list")
|
||||||
}).then(()=>{
|
.then((response) => {
|
||||||
const serviceName =urlParams.get(METRICS_PAGE_QUERY_PARAM.service);
|
setServiceList(response.data);
|
||||||
if(serviceName){
|
})
|
||||||
handleChangeService(serviceName)
|
.then(() => {
|
||||||
|
const serviceName = urlParams.get(METRICS_PAGE_QUERY_PARAM.service);
|
||||||
|
if (serviceName) {
|
||||||
|
handleChangeService(serviceName);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -120,7 +133,10 @@ const _TraceFilter = (props: TraceFilterProps) => {
|
|||||||
const [loading] = useState(false);
|
const [loading] = useState(false);
|
||||||
|
|
||||||
const [tagKeyValueApplied, setTagKeyValueApplied] = useState([""]);
|
const [tagKeyValueApplied, setTagKeyValueApplied] = useState([""]);
|
||||||
const [latencyFilterValues, setLatencyFilterValues] = useState<{min: string, max: string}>({
|
const [latencyFilterValues, setLatencyFilterValues] = useState<{
|
||||||
|
min: string;
|
||||||
|
max: string;
|
||||||
|
}>({
|
||||||
min: "100",
|
min: "100",
|
||||||
max: "500",
|
max: "500",
|
||||||
});
|
});
|
||||||
@ -158,7 +174,7 @@ const _TraceFilter = (props: TraceFilterProps) => {
|
|||||||
|
|
||||||
const onLatencyModalApply = (values: Store) => {
|
const onLatencyModalApply = (values: Store) => {
|
||||||
setModalVisible(false);
|
setModalVisible(false);
|
||||||
const { min, max}= values
|
const { min, max } = values;
|
||||||
props.updateTraceFilters({
|
props.updateTraceFilters({
|
||||||
...props.traceFilters,
|
...props.traceFilters,
|
||||||
latency: {
|
latency: {
|
||||||
@ -167,7 +183,7 @@ const _TraceFilter = (props: TraceFilterProps) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
setLatencyFilterValues({min, max})
|
setLatencyFilterValues({ min, max });
|
||||||
};
|
};
|
||||||
|
|
||||||
const onTagFormSubmit = (values: any) => {
|
const onTagFormSubmit = (values: any) => {
|
||||||
@ -278,6 +294,17 @@ const _TraceFilter = (props: TraceFilterProps) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
return ()=>{
|
||||||
|
props.updateTraceFilters({
|
||||||
|
service: "",
|
||||||
|
operation: "",
|
||||||
|
tags: [],
|
||||||
|
latency: { min: "", max: "" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},[])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div>Filter Traces</div>
|
<div>Filter Traces</div>
|
||||||
@ -382,13 +409,15 @@ const _TraceFilter = (props: TraceFilterProps) => {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
{modalVisible && <LatencyModalForm
|
{modalVisible && (
|
||||||
onCreate={onLatencyModalApply}
|
<LatencyModalForm
|
||||||
latencyFilterValues={latencyFilterValues}
|
onCreate={onLatencyModalApply}
|
||||||
onCancel={() => {
|
latencyFilterValues={latencyFilterValues}
|
||||||
setModalVisible(false);
|
onCancel={() => {
|
||||||
}}
|
setModalVisible(false);
|
||||||
/>}
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -46,7 +46,7 @@ const _TraceGraph = (props: TraceGraphProps) => {
|
|||||||
.default()
|
.default()
|
||||||
.attr("class", "d3-tip")
|
.attr("class", "d3-tip")
|
||||||
.html(function (d: any) {
|
.html(function (d: any) {
|
||||||
return d.data.name + "<br>duration: " + d.data.value/1000000+'ms';
|
return d.data.name + "<br>duration: " + d.data.value / 1000000 + "ms";
|
||||||
});
|
});
|
||||||
|
|
||||||
const onClick = (z: any) => {
|
const onClick = (z: any) => {
|
||||||
@ -55,12 +55,11 @@ const _TraceGraph = (props: TraceGraphProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const chart = flamegraph()
|
const chart = flamegraph()
|
||||||
.width(640)
|
|
||||||
.cellHeight(18)
|
.cellHeight(18)
|
||||||
.transitionDuration(500)
|
.transitionDuration(500)
|
||||||
.inverted(true)
|
.inverted(true)
|
||||||
.tooltip(tip)
|
.tooltip(tip)
|
||||||
.minFrameSize(10)
|
.minFrameSize(10)
|
||||||
.elided(false)
|
.elided(false)
|
||||||
.differential(false)
|
.differential(false)
|
||||||
.sort(true)
|
.sort(true)
|
||||||
@ -68,23 +67,25 @@ const _TraceGraph = (props: TraceGraphProps) => {
|
|||||||
// In that case it's doing step function sort of stuff thru computation.
|
// In that case it's doing step function sort of stuff thru computation.
|
||||||
// Source flamegraph.js line 557 and 573.
|
// Source flamegraph.js line 557 and 573.
|
||||||
// .selfValue(true)
|
// .selfValue(true)
|
||||||
.onClick(onClick)
|
.onClick(onClick);
|
||||||
.title("Trace Flame graph");
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
|
<Row gutter={{ xs: 8, sm: 16, md: 24, lg: 32 }}>
|
||||||
<Col md={8} sm={24}>
|
{/*<Col md={8} sm={24}>*/}
|
||||||
<TraceGraphColumn />
|
{/* <TraceGraphColumn />*/}
|
||||||
</Col>
|
{/*</Col>*/}
|
||||||
<Col md={16} sm={24}>
|
<Col md={24} sm={24}>
|
||||||
{/* <Card style={{ width: 640 }}> */}
|
{/* <Card style={{ width: 640 }}> */}
|
||||||
<Space direction="vertical" size="middle">
|
<Space direction="vertical" size="middle" style={{width: '100%'}}>
|
||||||
<Card bodyStyle={{ padding: 80 }} style={{ height: 320 }}>
|
<Card bodyStyle={{ padding: 80 }} style={{ height: 320,
|
||||||
<div>Trace Graph component ID is {params.id} </div>
|
}}>
|
||||||
<Button type="primary" onClick={setResetZoom.bind(this, true)}>
|
<div style={{display: 'flex', justifyContent: 'center', flexDirection: 'column', alignItems: 'center'}}>
|
||||||
Reset Zoom
|
<div style={{textAlign: "center"}}>Trace Graph component ID is {params.id} </div>
|
||||||
</Button>
|
<Button type="primary" onClick={setResetZoom.bind(this, true)} style={{width: 160}}>
|
||||||
<div id="chart" style={{ fontSize: 12, marginTop: 20}}></div>
|
Reset Zoom
|
||||||
|
</Button>
|
||||||
|
<div id="chart" style={{ fontSize: 12, marginTop: 20 }}></div>
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
<SelectedSpanDetails clickedSpanTags={clickedSpanTags} />
|
<SelectedSpanDetails clickedSpanTags={clickedSpanTags} />
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { NavLink } from "react-router-dom";
|
import { NavLink } from "react-router-dom";
|
||||||
import { Table } from "antd";
|
import { Space, Table } from "antd";
|
||||||
|
|
||||||
import { traceResponseNew, fetchTraces, pushDStree } from "../../actions";
|
import { traceResponseNew, fetchTraces, pushDStree } from "../../actions";
|
||||||
import { StoreState } from "../../reducers";
|
import { StoreState } from "../../reducers";
|
||||||
|
import { isOnboardingSkipped } from "../../utils/app";
|
||||||
|
|
||||||
interface TraceListProps {
|
interface TraceListProps {
|
||||||
traces: traceResponseNew;
|
traces: traceResponseNew;
|
||||||
@ -106,6 +107,23 @@ const _TraceList = (props: TraceListProps) => {
|
|||||||
|
|
||||||
return <Table dataSource={dataSource} columns={columns} size="middle" />;
|
return <Table dataSource={dataSource} columns={columns} size="middle" />;
|
||||||
} else {
|
} else {
|
||||||
|
if (isOnboardingSkipped()) {
|
||||||
|
return (
|
||||||
|
<Space
|
||||||
|
style={{ width: "100%", margin: "40px 0", justifyContent: "center" }}
|
||||||
|
>
|
||||||
|
No spans found. Please add instrumentation (follow this
|
||||||
|
<a
|
||||||
|
href={"https://signoz.io/docs/instrumentation/overview"}
|
||||||
|
target={"_blank"}
|
||||||
|
style={{ marginLeft: 3 }}
|
||||||
|
>
|
||||||
|
guide
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
return <div> No spans found for given filter!</div>;
|
return <div> No spans found for given filter!</div>;
|
||||||
}
|
}
|
||||||
}; // end of renderTraces
|
}; // end of renderTraces
|
||||||
|
@ -1,24 +1,83 @@
|
|||||||
import React, { useEffect } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Bar } from "react-chartjs-2";
|
import { Bar } from "react-chartjs-2";
|
||||||
import { Card } from "antd";
|
import { Card, Form, Select, Space } from "antd";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
import { getUsageData, GlobalTime, usageDataItem } from "../../actions";
|
import {
|
||||||
|
getServicesList,
|
||||||
|
getUsageData,
|
||||||
|
GlobalTime,
|
||||||
|
servicesListItem,
|
||||||
|
usageDataItem,
|
||||||
|
} from "../../actions";
|
||||||
import { StoreState } from "../../reducers";
|
import { StoreState } from "../../reducers";
|
||||||
|
import moment from "moment";
|
||||||
|
import { isOnboardingSkipped } from "../../utils/app";
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
interface UsageExplorerProps {
|
interface UsageExplorerProps {
|
||||||
usageData: usageDataItem[];
|
usageData: usageDataItem[];
|
||||||
getUsageData: Function;
|
getUsageData: Function;
|
||||||
|
getServicesList: Function;
|
||||||
globalTime: GlobalTime;
|
globalTime: GlobalTime;
|
||||||
|
servicesList: servicesListItem[];
|
||||||
|
totalCount: number;
|
||||||
}
|
}
|
||||||
|
const timeDaysOptions = [
|
||||||
|
{ value: 30, label: "Last 30 Days" },
|
||||||
|
{ value: 7, label: "Last week" },
|
||||||
|
{ value: 1, label: "Last day" },
|
||||||
|
];
|
||||||
|
|
||||||
|
const interval = [
|
||||||
|
{
|
||||||
|
value: 604800,
|
||||||
|
chartDivideMultiplier: 1,
|
||||||
|
label: "Weekly",
|
||||||
|
applicableOn: [timeDaysOptions[0]],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 86400,
|
||||||
|
chartDivideMultiplier: 30,
|
||||||
|
label: "Daily",
|
||||||
|
applicableOn: [timeDaysOptions[0], timeDaysOptions[1]],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 3600,
|
||||||
|
chartDivideMultiplier: 10,
|
||||||
|
label: "Hours",
|
||||||
|
applicableOn: [timeDaysOptions[2], timeDaysOptions[1]],
|
||||||
|
},
|
||||||
|
,
|
||||||
|
];
|
||||||
|
|
||||||
const _UsageExplorer = (props: UsageExplorerProps) => {
|
const _UsageExplorer = (props: UsageExplorerProps) => {
|
||||||
|
const [selectedTime, setSelectedTime] = useState(timeDaysOptions[1]);
|
||||||
|
const [selectedInterval, setSelectedInterval] = useState(interval[2]);
|
||||||
|
const [selectedService, setSelectedService] = useState<string>("");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
props.getUsageData(props.globalTime);
|
if (selectedTime && selectedInterval) {
|
||||||
}, [props.globalTime]);
|
const maxTime = new Date().getTime() * 1000000;
|
||||||
|
const minTime = maxTime - selectedTime.value * 24 * 3600000 * 1000000;
|
||||||
|
|
||||||
|
props.getUsageData(
|
||||||
|
minTime,
|
||||||
|
maxTime,
|
||||||
|
selectedInterval!.value,
|
||||||
|
selectedService,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, [selectedTime, selectedInterval, selectedService]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
props.getServicesList(props.globalTime);
|
||||||
|
}, []);
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
labels: props.usageData.map((s) => new Date(s.timestamp / 1000000)),
|
labels: props.usageData.map((s) =>
|
||||||
|
moment(s.timestamp / 1000000).format("MMM Do h a"),
|
||||||
|
),
|
||||||
datasets: [
|
datasets: [
|
||||||
{
|
{
|
||||||
label: "Span Count",
|
label: "Span Count",
|
||||||
@ -40,17 +99,6 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
xAxes: [
|
|
||||||
{
|
|
||||||
type: "time",
|
|
||||||
// distribution: 'linear', // Bar graph doesn't take lineardistribution type?
|
|
||||||
|
|
||||||
ticks: {
|
|
||||||
beginAtZero: true,
|
|
||||||
fontSize: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
display: false,
|
display: false,
|
||||||
@ -60,7 +108,79 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
|
|||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
{/* PNOTE - TODO - Keep it in reponsive row column tab */}
|
{/* PNOTE - TODO - Keep it in reponsive row column tab */}
|
||||||
<Card style={{ width: "50%", margin: 20 }} bodyStyle={{ padding: 20 }}>
|
<Space style={{ marginTop: 40, marginLeft: 20 }}>
|
||||||
|
<Space>
|
||||||
|
<Select
|
||||||
|
onSelect={(value, option) => {
|
||||||
|
setSelectedTime(
|
||||||
|
timeDaysOptions.filter((item) => item.value == parseInt(value))[0],
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={selectedTime.label}
|
||||||
|
>
|
||||||
|
{timeDaysOptions.map(({ value, label }) => (
|
||||||
|
<Option value={value}>{label}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Space>
|
||||||
|
<Space>
|
||||||
|
<Select
|
||||||
|
onSelect={(value) => {
|
||||||
|
setSelectedInterval(
|
||||||
|
interval.filter((item) => item!.value === parseInt(value))[0],
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
value={selectedInterval!.label}
|
||||||
|
>
|
||||||
|
{interval
|
||||||
|
.filter((interval) => interval!.applicableOn.includes(selectedTime))
|
||||||
|
.map((item) => (
|
||||||
|
<Option value={item!.value}>{item!.label}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Space>
|
||||||
|
|
||||||
|
<Space>
|
||||||
|
<Select
|
||||||
|
onSelect={(value) => {
|
||||||
|
setSelectedService(value);
|
||||||
|
}}
|
||||||
|
value={selectedService || "All Services"}
|
||||||
|
>
|
||||||
|
<Option value={""}>All Services</Option>
|
||||||
|
{props.servicesList.map((service) => (
|
||||||
|
<Option value={service.serviceName}>{service.serviceName}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Space>
|
||||||
|
|
||||||
|
{isOnboardingSkipped() && props.totalCount === 0 ? (
|
||||||
|
<Space
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
margin: "40px 0",
|
||||||
|
marginLeft: 20,
|
||||||
|
justifyContent: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
No spans found. Please add instrumentation (follow this
|
||||||
|
<a
|
||||||
|
href={"https://signoz.io/docs/instrumentation/overview"}
|
||||||
|
target={"_blank"}
|
||||||
|
style={{ marginLeft: 3 }}
|
||||||
|
>
|
||||||
|
guide
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
</Space>
|
||||||
|
) : (
|
||||||
|
<Space style={{ display: "block", marginLeft: 20, width: 200 }}>
|
||||||
|
{`Total count is ${props.totalCount}`}
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
|
||||||
|
<Card style={{ width: "90%", margin: 20 }} bodyStyle={{ padding: 20 }}>
|
||||||
<Bar data={data} options={options} />
|
<Bar data={data} options={options} />
|
||||||
</Card>
|
</Card>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
@ -69,10 +189,25 @@ const _UsageExplorer = (props: UsageExplorerProps) => {
|
|||||||
|
|
||||||
const mapStateToProps = (
|
const mapStateToProps = (
|
||||||
state: StoreState,
|
state: StoreState,
|
||||||
): { usageData: usageDataItem[]; globalTime: GlobalTime } => {
|
): {
|
||||||
return { usageData: state.usageDate, globalTime: state.globalTime };
|
totalCount: number;
|
||||||
|
globalTime: GlobalTime;
|
||||||
|
servicesList: servicesListItem[];
|
||||||
|
usageData: usageDataItem[];
|
||||||
|
} => {
|
||||||
|
let totalCount = 0;
|
||||||
|
for (let item of state.usageDate) {
|
||||||
|
totalCount = totalCount + item.count;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
totalCount: totalCount,
|
||||||
|
usageData: state.usageDate,
|
||||||
|
globalTime: state.globalTime,
|
||||||
|
servicesList: state.servicesList,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const UsageExplorer = connect(mapStateToProps, {
|
export const UsageExplorer = connect(mapStateToProps, {
|
||||||
getUsageData: getUsageData,
|
getUsageData: getUsageData,
|
||||||
|
getServicesList: getServicesList,
|
||||||
})(_UsageExplorer);
|
})(_UsageExplorer);
|
||||||
|
5
frontend/src/constants/app.ts
Normal file
5
frontend/src/constants/app.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const WITHOUT_SESSION_PATH = ["/redirect"];
|
||||||
|
|
||||||
|
export const AUTH0_REDIRECT_PATH = "/redirect";
|
||||||
|
|
||||||
|
export const DEFAULT_AUTH0_APP_REDIRECTION_PATH = "/application";
|
@ -1,4 +0,0 @@
|
|||||||
export const ENVIRONMENT = {
|
|
||||||
baseURL: "",
|
|
||||||
// baseURL: "http://104.211.113.204:8080",
|
|
||||||
};
|
|
@ -2,6 +2,5 @@ export enum METRICS_PAGE_QUERY_PARAM {
|
|||||||
interval = "interval",
|
interval = "interval",
|
||||||
startTime = "startTime",
|
startTime = "startTime",
|
||||||
endTime = "endTime",
|
endTime = "endTime",
|
||||||
service = "service"
|
service = "service",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
39
frontend/src/index.html.ejs
Normal file
39
frontend/src/index.html.ejs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<title data-react-helmet="true">Open source Observability platform | SigNoz</title><meta data-react-helmet="true" property="og:title" content="Open source Observability platform | SigNoz"><meta data-react-helmet="true" name="description" content="SigNoz is an opensource observability platform to help you find issues in your deployed applications & solve them quickly. It provides an integrated UI for metrics and traces with deep filtering and aggregation to pin down specific issues very quickly. Built on Kafka and Druid, it is designed to handle enterprise scale."><meta data-react-helmet="true" property="og:description" content="SigNoz is an opensource observability platform to help you find issues in your deployed applications & solve them quickly. It provides an integrated UI for metrics and traces with deep filtering and aggregation to pin down specific issues very quickly. Built on Kafka and Druid, it is designed to handle enterprise scale."><meta data-react-helmet="true" property="og:image" content="https://signoz.io/img/HeroShot-3.jpg"><meta data-react-helmet="true" name="twitter:image" content="https://signoz.io/img/HeroShot-3.jpg"><meta data-react-helmet="true" name="twitter:image:alt" content="Image for Open source Observability platform | SigNoz"><meta data-react-helmet="true" name="twitter:card" content="summary_large_image"><meta data-react-helmet="true" name="docusaurus_locale" content="en"><meta data-react-helmet="true" name="docusaurus_tag" content="default"><link data-react-helmet="true" rel="shortcut icon" href="/img/favicon.ico">
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||||
|
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
/>
|
||||||
|
<!--
|
||||||
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
|
-->
|
||||||
|
<!--
|
||||||
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
Only files inside the `public` folder can be referenced from the HTML.
|
||||||
|
|
||||||
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
|
-->
|
||||||
|
<title>Signoz</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
<!--
|
||||||
|
This HTML file is a template.
|
||||||
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
||||||
|
You can add webfonts, meta tags, or analytics to this file.
|
||||||
|
The build step will place the bundled scripts into the <body> tag.
|
||||||
|
|
||||||
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
|
-->
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -5,26 +5,30 @@ import { createStore, applyMiddleware, compose } from "redux";
|
|||||||
import { ThemeSwitcherProvider } from "react-css-theme-switcher";
|
import { ThemeSwitcherProvider } from "react-css-theme-switcher";
|
||||||
import thunk from "redux-thunk";
|
import thunk from "redux-thunk";
|
||||||
// import { NavLink, BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
// import { NavLink, BrowserRouter as Router, Route, Switch } from 'react-router-dom';
|
||||||
|
import { Auth0Provider } from "@auth0/auth0-react";
|
||||||
|
|
||||||
import AppWrapper from "./components/AppWrapper";
|
import AppWrapper from "Src/components/AppWrapper";
|
||||||
import "./assets/index.css";
|
import "Src/assets/index.css";
|
||||||
import { reducers } from "./reducers";
|
import { reducers } from "Src/reducers";
|
||||||
|
import { BrowserRouter as Router } from "react-router-dom";
|
||||||
|
import { AUTH0_CLIENT_ID, AUTH0_DOMAIN } from "./constants/env";
|
||||||
// import Signup from './components/Signup';
|
// import Signup from './components/Signup';
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
|
||||||
const store = createStore(reducers, composeEnhancers(applyMiddleware(thunk)));
|
const store = createStore(reducers, composeEnhancers(applyMiddleware(thunk)));
|
||||||
|
|
||||||
const themes = {
|
const themes = {
|
||||||
dark: `${process.env.PUBLIC_URL}/dark-theme.css`,
|
dark: `/dark-theme.css`,
|
||||||
light: `${process.env.PUBLIC_URL}/light-theme.css`,
|
light: `/light-theme.css`,
|
||||||
};
|
};
|
||||||
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<ThemeSwitcherProvider themeMap={themes} defaultTheme="dark">
|
<ThemeSwitcherProvider themeMap={themes} defaultTheme="dark">
|
||||||
<AppWrapper />
|
<Router basename="/">
|
||||||
{/* <App /> */}
|
<AppWrapper />
|
||||||
|
</Router>
|
||||||
</ThemeSwitcherProvider>
|
</ThemeSwitcherProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
|
@ -3,7 +3,7 @@ import { ActionTypes, Action, GlobalTime } from "../actions";
|
|||||||
export const updateGlobalTimeReducer = (
|
export const updateGlobalTimeReducer = (
|
||||||
state: GlobalTime = {
|
state: GlobalTime = {
|
||||||
maxTime: Date.now() * 1000000,
|
maxTime: Date.now() * 1000000,
|
||||||
minTime: (Date.now() - 15 * 60 * 1000) * 1000000
|
minTime: (Date.now() - 15 * 60 * 1000) * 1000000,
|
||||||
},
|
},
|
||||||
action: Action,
|
action: Action,
|
||||||
) => {
|
) => {
|
||||||
|
3
frontend/src/utils/app.ts
Normal file
3
frontend/src/utils/app.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export const isOnboardingSkipped = () => {
|
||||||
|
return localStorage.getItem("skip_onboarding") === "true";
|
||||||
|
};
|
4
frontend/src/utils/timeUtils.ts
Normal file
4
frontend/src/utils/timeUtils.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export const toUTCEpoch = (time: number): number => {
|
||||||
|
const x = new Date();
|
||||||
|
return time + x.getTimezoneOffset() * 60 * 1000;
|
||||||
|
};
|
3
frontend/src/utils/token.ts
Normal file
3
frontend/src/utils/token.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export class Token {
|
||||||
|
static auth0Token = "";
|
||||||
|
}
|
58
frontend/webpack.config.js
Normal file
58
frontend/webpack.config.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
// shared config (dev and prod)
|
||||||
|
const { resolve } = require("path");
|
||||||
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
|
console.log(resolve(__dirname, "./src/"));
|
||||||
|
module.exports = {
|
||||||
|
mode: "development",
|
||||||
|
devtool: "source-map",
|
||||||
|
entry: resolve(__dirname, "./src/index.tsx"),
|
||||||
|
devServer: {
|
||||||
|
historyApiFallback: true,
|
||||||
|
publicPath: "/",
|
||||||
|
transportMode: "ws",
|
||||||
|
contentBase: [resolve(__dirname, "./public")],
|
||||||
|
hot: true,
|
||||||
|
liveReload: false,
|
||||||
|
inline: true,
|
||||||
|
port: 3000,
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: "js/bundle.[chunkhash].min.js",
|
||||||
|
path: resolve(__dirname, "./build"),
|
||||||
|
publicPath: "/",
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
Src: resolve(__dirname, "./src/"),
|
||||||
|
},
|
||||||
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: [/\.jsx?$/, /\.tsx?$/],
|
||||||
|
use: ["babel-loader"],
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ["style-loader", "css-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(scss|sass)$/,
|
||||||
|
use: ["style-loader", "css-loader", "sass-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||||
|
use: [
|
||||||
|
"file-loader?hash=sha512&digest=hex&name=img/[chunkhash].[ext]",
|
||||||
|
"image-webpack-loader?bypassOnDebug&optipng.optimizationLevel=7&gifsicle.interlaced=false",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [new HtmlWebpackPlugin({ template: "src/index.html.ejs" })],
|
||||||
|
performance: {
|
||||||
|
hints: false,
|
||||||
|
},
|
||||||
|
};
|
55
frontend/webpack.config.prod.js
Normal file
55
frontend/webpack.config.prod.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
// shared config (dev and prod)
|
||||||
|
const { resolve } = require("path");
|
||||||
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
|
const CopyPlugin = require("copy-webpack-plugin");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
mode: "production",
|
||||||
|
devtool: "source-map",
|
||||||
|
entry: resolve(__dirname, "./src/index.tsx"),
|
||||||
|
output: {
|
||||||
|
filename: "js/bundle.[chunkhash].min.js",
|
||||||
|
path: resolve(__dirname, "./build"),
|
||||||
|
publicPath: "/",
|
||||||
|
},
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
Src: resolve(__dirname, "./src/"),
|
||||||
|
},
|
||||||
|
extensions: [".ts", ".tsx", ".js", ".jsx"],
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: [/\.jsx?$/, /\.tsx?$/],
|
||||||
|
use: ["babel-loader"],
|
||||||
|
exclude: /node_modules/,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ["style-loader", "css-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(scss|sass)$/,
|
||||||
|
use: ["style-loader", "css-loader", "sass-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(jpe?g|png|gif|svg)$/i,
|
||||||
|
use: [
|
||||||
|
"file-loader?hash=sha512&digest=hex&name=img/[chunkhash].[ext]",
|
||||||
|
"image-webpack-loader?bypassOnDebug&optipng.optimizationLevel=7&gifsicle.interlaced=false",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new HtmlWebpackPlugin({ template: "src/index.html.ejs" }),
|
||||||
|
new CopyPlugin({
|
||||||
|
patterns: [{ from: resolve(__dirname, "public/"), to: "." }],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
performance: {
|
||||||
|
hints: false,
|
||||||
|
},
|
||||||
|
};
|
5096
frontend/yarn.lock
5096
frontend/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user