Compare commits

..

56 Commits

Author SHA1 Message Date
Ankit Nayan
a5fd338a9d release: v0.4.1 2021-09-28 20:32:09 +05:30
Ankit Nayan
8a781076e1 Revert "fix: frontend/package.json, frontend/yarn.lock & frontend/.snyk to reduce vulnerabilities (#310)" (#315)
This reverts commit e756cefa75.
2021-09-28 19:25:32 +05:30
Palash
18fc697b91 Fix dark theme mode (#314)
* theme address is fixed

* theme address is fixed
2021-09-28 19:03:19 +05:30
Palash
93b347d25e Fix(FE): dark mode (#301)
* fix: fav icon is fixed and bootstrap is removed

* fix: return type is updated for the global time reducer

* fix: theme.css is replaced with .min.css

* update: useThemeSwitcher is removed from the graph component and value is grabed from the reducer

* update: instrumentation page is updated

* update: react-css-theme-switcher package is removed

* update: darkMode is updated

* fix: Sider component is updated
2021-09-28 18:50:10 +05:30
Palash
ea5b40c7ea Feat(FE): Delete Query, Save Layout (#306)
* feat: Delete Query functionality is added

* feat: save layout is updated
2021-09-28 18:38:34 +05:30
Palash
cc91242e9a Fix(FE): Fix date dashboard (#311)
* chore: getFormatedDate function is added

* fix: date format in the all dashboard is updated to mm/dd/yyyy HH:MM
2021-09-28 18:32:02 +05:30
Snyk bot
e756cefa75 fix: frontend/package.json, frontend/yarn.lock & frontend/.snyk to reduce vulnerabilities (#310)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-JS-ANSIREGEX-1583908
- https://snyk.io/vuln/SNYK-JS-AXIOS-1579269
- https://snyk.io/vuln/SNYK-JS-D3COLOR-1076592
- https://snyk.io/vuln/SNYK-JS-GLOBPARENT-1016905


The following vulnerabilities are fixed with a Snyk patch:
- https://snyk.io/vuln/npm:debug:20170905
2021-09-28 18:25:41 +05:30
Palash
da653681cf fix: color for the graph is updated (#305) 2021-09-28 18:20:38 +05:30
Palash
93b5a945a4 fix: Chart.js plugins are not register at each and every render (#303) 2021-09-28 18:20:14 +05:30
Palash
9ab1093d81 fix: createdBy is renamed to createdAt (#302) 2021-09-28 18:19:30 +05:30
Palash
b4754053aa fix: fav icon is fixed and bootstrap is removed (#299) 2021-09-28 18:18:30 +05:30
Ankit Nayan
8fef964485 feat: persisting database for dashboards 2021-09-28 18:14:12 +05:30
Ankit Nayan
004dda200c feat: signoz can now scale up in docker swarm (#309)
* feat: signoz can now scale up in docker swarm

* chore: adding empty folders for volume mount

* chore: using image 0.4.0

* chore: adding folder to persist signoz.db
2021-09-28 18:10:44 +05:30
Ankit Nayan
6a01ce88cb chore: exit application if clickhouse is not reachable (#308) 2021-09-27 23:20:27 +05:30
Ankit Nayan
ade8cda91c release: 0.4.0 2021-09-24 16:51:13 +05:30
Ankit Nayan
3b7484f423 Merge branch 'main' of https://github.com/SigNoz/signoz 2021-09-23 16:19:42 +05:30
Ankit Nayan
959aad252c release: 0.4.0 2021-09-23 16:18:36 +05:30
Palash
7b70cfb0c4 feat: Metrics (#281)
* refactor: store is updated

* temp

* fix: eslint error is fixed

* fix:eslint linting error is updated

* chore: react-grid-layout is added

* chore: linting changes are updated

* chore: linting changes are updated

* chore: @types/node is moved to devDependecies and @types/react-grid-layout is added

* chore: tsconfig is updated

* chore: updateUrl function is updated

* feat: All Dashboard is updated

* feat: All Dashboard page is updated

* feat: New Dashboard is added

* feat: App Layout is updated

* feat: Add Tags is updated

* chore: uuid package is added

* chore: AppRoutes is updated

* chore: UI components are updated

* chore: baseUrl is added in the apiUrl and removed from other api request

* chore: commonApi Response is updated

* chore: ErrorResponse handler is updated

* chore: useFetch hook is made

* chore: axios instance is updated

* chore:some of the changes are updated

* chore: list of all dashboard types is updated

* chore: logic is updated to the global state

* chore: all dashboard data is fetched from the global state

* chore: unnessary prop is removed

* chore: changes are updated

* chore: getAll and create is updated

* chore: getDashboard is updated

* chore: isEditMode is moved to the global state

* chore: get,getAll is updated

* chore: update title,tags,description is now fixed

* chore: new widget is updated

* chore: graph is updated

* chore: input component accept input props

* chore: name of the dashboard is updated

* chore: Widgets page in WIP

* chore: types for the error api is updated

* chore: getQuery data is updated

* chore: widget types is updated

* default widget is updated

* chore: getQuery is updated

* chore: Add Query is updated

* fix: creating new widget bug is resolved

* chore: widget type is updated

* chore: Query error is updated

* chore: query error and success state is handled

* chore: label of graph in WIP

* chore: legend input placeholder is updated

* chore: changes are updated

* chore: no data component is updated and error component is rendered along with the data

* chore: data fetching over the initial render is fixed over the initial mount

* chore: convertDateToAndPm is updated

* chore: x-axis label is now fixed

* chore: label is updated

* chore: labels name is updated

* chore: labels name is updated

* chore: labels color is updated

* chore: values are parsed in float

* chore: tags is updated

* chore: datasets type is updated

* chore: graph is updated

* chore: more eslint rules are updated

* chore: some of the linting changes and data is updated

* chore: chart.js version is updated

* chore: gitignore is updated

* chore: graph component is updated

* chore: apply functionality is updated

* chore: dashboard is now saved

* chore: getChartData is updated

* feat: Dashboard graph is reflected

* chore: some of the bugs is resolved

* fix: aspect ratio is made false

* chore: some small css are fixed

* chore: widgetId and graphType is preAdded if present in the search params

* chore: user is now able to change the time via global time and reflect new graph values

* chore: query is updated

* chore: onBlurHandler is updated

* fix: usage explorer is now fixed

* chore: bar element is updated

* chore: chartjs adapter is added

* chore: old instance for the charts are removed via re-chart

* chore: re-chart is removed

* chore: get chart data is updated

* chore: added the counter in the useEffect

* chore: history is added

* chore: some of the features are updated

* chore: history package is updated

* chore: AppRoutes is updated

* fix: some are components breaking while moving from BrowserRouter to Router

* chore: Dashboard icon is updated

* chore: Full screen component is updated

* stepSize (optional) is added in the widgets type

* fix: fetching query result is fixed

* update: start and end time function is updated

* fix: Alert color is updated

* update: Query fetching is updated

* fix: start and end time is fixed

* fix: chartjs data is compatable for larger data set and no ajax call for empty query is fixed

* fix: last 1 week selection is fixed

* fix: legends is added

* update: antd version is updated

* feat: value graph is updated

* feat: Title is added for the value graph

* fix: Full Screen view is updated with refresh functionality and alignment is updated to flex-end

* fix: Graph component is updated

* fix: metric graph are fixed

* feature: Delete widget functionality is updated

* fix: empty value bug is resolved

* fix: delete widget position is fixed

* fix: resize functionality is fixed

* fix: sumation of the query is fixed

* update: default legend is removed

* update: resize handlers is removed and service metric component is updated

* fix: legends is updated

* update: querySuccess reducer is updated

* Modal component is updated

* fix: ant-d tab css is updated of the tabs

* update: stringToHTML is made

* update: graph component is updated

* fix: several component in the metric and traces are updated

* wip: build error is fixed

* fix: metric section is fixed

* update: console.log are commented

* fix: onClick graph re-render is stopped

* fix: trace graph is updated

* fix: updated the min,max time for the value type graph

* getQueryMaxMin Time is updated

* fix: trace chart is updated

* fix: re-render is fixed

* fix: localstorage persistance is there

* update: if label is not present legend is not displayed

* fix: graph is changed while updated the global time

* fix: default title is updated while creation of the dashboard

* update: external database call tabs are made of same size

* fix: query graph max-min time is updated in the full screen mode

* fix: Request per sec graph is fixed

* fix: ErrorChart is fixed

Co-authored-by: Palash gupta <palashgdev@gmail.com>
2021-09-23 15:43:43 +05:30
Ankit Nayan
53d5e37b5f feat: enable data persistence in clickhouse docker (#297) 2021-09-20 16:15:02 +05:30
Pranay Prateek
69821cc13c Update README.md 2021-09-18 13:00:18 +05:30
Lucas Barbosa
a555c2cb93 docs: translate readme.md into portuguese-brazil (#238) (#296) 2021-09-18 12:57:18 +05:30
Pranay Prateek
24d51e3c3a Update install.sh 2021-09-16 20:57:32 +05:30
Vamsi Krishna
368e11e17a fix: updated the footer year (#290)
Co-authored-by: Palash <88981777+palash-signoz@users.noreply.github.com>
2021-09-06 22:04:43 +05:30
Ankit Nayan
118ee9dd90 fix: fixed cors error for PUT (#287) 2021-09-02 14:55:07 +05:30
Ankit Nayan
30961da59f Crud APIs for dashboards (#286)
* added signoz.db to gitignore

* model and crud methods for dashboard package

* added signoz.db to dockerignore

* feat: dashboards crud WIP

* chore: moving response format to correct file

* chore: adding dependencies for sqlite3

* feat: CRUD APIs ready for dashboards

* fix: sqlite needs cgo enabled and hence need to add some flags in building go code

* feat: provision dashboards using json

* chore: mounting dashboard folder to container
2021-09-02 13:18:47 +05:30
Jacoberson
9692b9985a fix: hot reload issue (#279)
* fixing hot reload issue

* Update webpack.config.js

removed duplicate key-value pairs.

Co-authored-by: Palash <88981777+palash-signoz@users.noreply.github.com>
2021-09-02 11:34:40 +05:30
Ankit Nayan
98ab64cb94 chore: query-service 0.4.0 2021-08-30 17:16:32 +05:30
Raj Babu Das
f883d02ff7 fixing codeql workflow (#283)
* fixing codeql

Signed-off-by: rajdas98 <mail.rajdas@gmail.com>

* fixing codeql

Signed-off-by: rajdas98 <mail.rajdas@gmail.com>
2021-08-29 13:01:38 +05:30
Raj Babu Das
fff9031bf7 Adding codeql (#253)
Signed-off-by: rajdas98 <mail.rajdas@gmail.com>

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-29 10:37:34 +05:30
Ankit Nayan
32ad4ef571 Feat: enables metrics ingestion to signoz (#271)
* WIP promql support

* forked prometheus and promhouse integrated

* removing __debug_bin from  git

* feat: prometheus config file to load

* feat: read prometheus config from args

* fix: WIP fixing errors in docker build

* feat: added clickhousemetricswrite exporter in metrics

* feat: changing otelcol image tag

* fix: read prometheus.yml from config flag in docker-compose

* fix: WIP clickhouse connection error

* fix: used signoz/prometheus tag v1.9.4

* chore: response format as in prometheus

* chore: query_range works with clickhouse reader and throws not implemented error for druid

* chore: moved ApiError struct to model

* feat: enabled instant query api for metrics

* chore: parser for instant query api params
2021-08-29 10:28:40 +05:30
palash-signoz
66b423588e Feature(FE): cypress base test case are updated (#275)
* chore: video config is updated as it will not generate any video while running cypress

* chore: cypress.env.json is added in the env file

* chore: tsConfig is updated

* feature: Cypress is updated with some of the test cases

* chore: default test case is removed

* chore: convertToNanoSecondsToSecond function is updated

* chore: lock files, node_modules are ignored in git

* test: metric are updated

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-27 12:21:24 +05:30
palash-signoz
e0be48a527 refactor(frontend): Sidebar is updated (#276) 2021-08-27 12:13:32 +05:30
palash-signoz
4143e313da Fix(FE): Eslint Prettier are configured (#269)
* fix(FE): eslint

* chore: run eslint on frontend folder

* chore: run eslint on src

* chore: eslint fixing is updated

* chore: linting errors are updated

Co-authored-by: Nidhi Tandon <nidhitandon08@gmail.com>
2021-08-26 11:50:47 +05:30
Pranay Prateek
e1fbe265d8 Update README.md 2021-08-23 20:47:14 +05:30
Pranay Prateek
84002fa123 Update README.md 2021-08-23 20:46:40 +05:30
Ankit Nayan
7f2546ec97 release: 0.3.6 2021-08-23 12:07:09 +05:30
Yash Joshi
68b1b8d975 chore: remove old scripts (#267)
Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-23 11:53:05 +05:30
palash-signoz
ac789ffcf0 bug: commitlint.yml is fixed (#266)
Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-23 11:52:28 +05:30
palash-signoz
1272e18672 Feature(FE): Setup cypress (#263)
* gitignore is updated

* cypress is updated

* json is updated

* default test case is updated

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-23 11:52:02 +05:30
palash-signoz
9008d19a7b fix(FE): AppRoutes is refactored (#260)
* react-app-env.d.ts is moved to the typings

* webpack config for development and production is updated

* extra browser router component is removed

* loable component is made

* spinner component is updated

* route are updated

* routes are imported is Loadable fashion with chunkName

* AppRoute is updated

* AppWrapper is changed to AppRouter

* merge conflits are resolved

* Loadable component is updated

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-23 11:38:25 +05:30
Ankit Nayan
f394f72bfb feat: grpc error calculation added to druid query (#268)
* feat: added statusCode for grpc

* feat: errors will now have grpc errors too

* removing dependency on viper

* grpc error calculation added to druid queries
2021-08-23 10:13:14 +05:30
Ankit Nayan
45cb0353e6 Feat: Enables error from grpc calls (#265)
* feat: added statusCode for grpc

* feat: errors will now have grpc errors too
2021-08-23 09:19:54 +05:30
Ankit Nayan
506c34f385 release: 0.3.5 2021-08-20 12:45:37 +05:30
Ankit Nayan
aca67d4f33 fix: removing action on pr as secret is not shared by forked repos 2021-08-20 12:42:49 +05:30
palash-signoz
c00e9f5236 contribution.md for frontend local instruction is updated (#264)
Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-19 23:15:08 +05:30
palash-signoz
8cef9de35c fix: css issue for the tabs is updated (#259)
Co-authored-by: FIPalash Gupta <palash@indiagold.co>
Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-19 23:13:44 +05:30
palash-signoz
4817a17320 fix(FE): onFocusSelected bug is resolved (#258)
* fix: onFocusSelected bug is resolved

* dependecies array is updated

* updated the dependency array

* fix: TraceGantt chart is updated

Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-19 23:13:16 +05:30
palash-signoz
0055eaf656 fix: css issue for the SelectedSpanDetails is updated (#257)
Co-authored-by: FIPalash Gupta <palash@indiagold.co>
Co-authored-by: Ankit Nayan <ankit@signoz.io>
2021-08-19 23:04:15 +05:30
palash-signoz
4b205e61c8 fix(FE): tsConfig baseUrl is used rather than using the alias for module (#256)
* tsconfig-paths-webpack-plugin package is added

* baseUrl is updated

* webpack config for development and production are updated

* baseUrl is removed in the file

* more .. is being removed

* chore: removed the commented part in the webpack.config

Co-authored-by: FIPalash Gupta <palash@indiagold.co>
2021-08-19 22:53:33 +05:30
Ankit Nayan
77c0237ba1 feat: PR will trigger build and push of docker image in pattern pull-NUMBER 2021-08-19 20:23:24 +05:30
palash-signoz
a2acee209c commit lint is fixed (#261) 2021-08-18 18:56:44 +05:30
Ankit Nayan
5381dc7e56 preparing for release 0.3.4 2021-08-10 23:39:27 +05:30
Ankit Nayan
76848b8925 fix: api method allowed 2021-08-10 23:32:28 +05:30
Ankit Nayan
3f32322385 chore: adding commitlint 2021-08-03 02:06:34 +05:30
Ankit Nayan
29c26777b6 fix: fixed branch name in release drafter 2021-08-03 01:31:41 +05:30
Ankit Nayan
f861a5c77d adding release-drafter 2021-08-03 01:04:59 +05:30
299 changed files with 14676 additions and 77160 deletions

29
.github/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
template: |
# What's Changed
$CHANGES
autolabeler:
- label: 'chore'
title:
- '/chore/i'
- label: 'bug'
title:
- '/fix/i'
- label: 'enhancement'
title:
- '/feat/i'
categories:
- title: '🚀 Features'
label: 'enhancement'
- title: '🐛 Bug Fixes'
labels:
- 'bug'
- title: '🧰 Maintenance'
label: 'chore'
- title: 'Breaking'
label: 'breaking'
exclude-labels:
- 'skip-changelog'

71
.github/workflows/codeql.yaml vendored Normal file
View File

@@ -0,0 +1,71 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ main, v* ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ main ]
schedule:
- cron: '32 5 * * 5'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'go', 'javascript', 'python' ]
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
# Learn more:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- name: Checkout repository
uses: actions/checkout@v2
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

18
.github/workflows/commitlint.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
name: commitlint
on: [pull_request]
defaults:
run:
working-directory: frontend
jobs:
lint-commits:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.1
with:
# we actually need "github.event.pull_request.commits + 1" commit
fetch-depth: 0
- uses: actions/setup-node@v2.1.0
# or just "yarn" if you depend on "@commitlint/cli" already
- run: yarn add @commitlint/cli
- run: yarn add @commitlint/config-conventional
- run: yarn run commitlint --config ./node_modules/@commitlint/config-conventional/index.js --from HEAD~${{ github.event.pull_request.commits }} --to HEAD

View File

@@ -6,7 +6,13 @@ on:
- ^v[0-9]*.[0-9]*.x$
tags:
- "*"
# pull_request:
# branches:
# - main
# - v*
# paths:
# - 'pkg/**'
# - 'frontend/**'
jobs:
get-envs:
runs-on: ubuntu-latest
@@ -21,6 +27,9 @@ jobs:
then
echo "tag build"
img_tag=${GITHUB_REF#refs/*/v}
elif [ ${array[1]} == "pull" ]
then
img_tag="pull-${{ github.event.number }}"
else
echo "non tag build"
img_tag="latest"
@@ -74,7 +83,7 @@ jobs:
run: |
branch=${GITHUB_REF#refs/*/}
array=(`echo ${GITHUB_REF} | sed 's/\//\n/g'`)
if [ $branch == "main" ] || [ ${array[1]} == "tags" ] || [[ $branch =~ ^v[0-9]*.[0-9]*.x$ ]]
if [ $branch == "main" ] || [ ${array[1]} == "tags" ] || [ ${array[1]} == "pull" ] || [[ $branch =~ ^v[0-9]*.[0-9]*.x$ ]]
then
source env-vars
make build-push-frontend
@@ -115,7 +124,7 @@ jobs:
run: |
branch=${GITHUB_REF#refs/*/}
array=(`echo ${GITHUB_REF} | sed 's/\//\n/g'`)
if [ $branch == "main" ] || [ ${array[1]} == "tags" ] || [[ $branch =~ ^v[0-9]*.[0-9]*.x$ ]]
if [ $branch == "main" ] || [ ${array[1]} == "tags" ] || [ ${array[1]} == "pull" ] ||[[ $branch =~ ^v[0-9]*.[0-9]*.x$ ]]
then
source env-vars
make build-push-query-service
@@ -156,7 +165,7 @@ jobs:
run: |
branch=${GITHUB_REF#refs/*/}
array=(`echo ${GITHUB_REF} | sed 's/\//\n/g'`)
if [ $branch == "main" ] || [ ${array[1]} == "tags" ] || [[ $branch =~ ^v[0-9]*.[0-9]*.x$ ]]
if [ $branch == "main" ] || [ ${array[1]} == "tags" ] || [ ${array[1]} == "pull" ] || [[ $branch =~ ^v[0-9]*.[0-9]*.x$ ]]
then
source env-vars
make build-push-flattener

29
.github/workflows/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,29 @@
name: Release Drafter
on:
push:
# branches to consider in the event; optional, defaults to all
branches:
- main
# pull_request event is required only for autolabeler
pull_request:
# Only following types are handled by the action, but one can default to all as well
types: [opened, reopened, synchronize]
jobs:
update_release_draft:
runs-on: ubuntu-latest
steps:
# (Optional) GitHub Enterprise requires GHE_HOST variable set
#- name: Set GHE_HOST
# run: |
# echo "GHE_HOST=${GITHUB_SERVER_URL##https:\/\/}" >> $GITHUB_ENV
# Drafts your next Release notes as Pull Requests are merged into "master"
- uses: release-drafter/release-drafter@v5
# (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml
# with:
# config-name: my-config.yml
# disable-autolabeler: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

10
.gitignore vendored
View File

@@ -1,3 +1,7 @@
node_modules
yarn.lock
package.json
deploy/docker/environment_tiny/common_test
frontend/node_modules
frontend/.pnp
@@ -21,6 +25,10 @@ frontend/npm-debug.log*
frontend/yarn-debug.log*
frontend/yarn-error.log*
frontend/src/constants/env.ts
frontend/cypress/**/*.mp4
# env file for cypress
frontend/cypress.env.json
.idea
@@ -29,5 +37,7 @@ frontend/src/constants/env.ts
**/build
**/storage
**/locust-scripts/__pycache__/
**/__debug_bin
frontend/*.env
pkg/query-service/signoz.db

View File

@@ -26,7 +26,7 @@ Need to update [https://github.com/SigNoz/signoz/tree/main/frontend](https://git
If you don't want to install SigNoz backend just for doing frontend development, we can provide you with test environments which you can use as the backend. Please ping us in #contributing channel in our [slack community](https://join.slack.com/t/signoz-community/shared_invite/zt-lrjknbbp-J_mI13rlw8pGF4EWBnorJA) and we will DM you with `<test environment URL>`
- `git clone https://github.com/SigNoz/signoz.git && cd signoz/frontend`
- change baseURL to `<test environment URL>` in file `src/constants/env.ts`
- Create a file `.env` with `FRONTEND_API_ENDPOINT=<test environment URL>`
- `yarn install`
- `yarn dev`
@@ -64,11 +64,12 @@ You can always reach out to `ankit@signoz.io` to understand more about the repo
- If you want to discuss something about the product, start a new [discussion](https://github.com/SigNoz/signoz/discussions)
### Conventions to follow when submitting commits, PRs
1. We try to follow https://www.conventionalcommits.org/en/v1.0.0/
More specifically the commits and PRs should have type specifiers prefixed in the name. [This](https://www.conventionalcommits.org/en/v1.0.0/#specification) should give you a better idea.
e.g. If you are submitting a fix for an issue in frontend - PR name should be prefixed with `fix(FE):`
e.g. If you are submitting a fix for an issue in frontend - PR name should be prefixed with `fix(FE):`
2. Follow [GitHub Flow](https://guides.github.com/introduction/flow/) guidelines for your contribution flows

View File

@@ -16,6 +16,7 @@
<h3 align="center">
<a href="https://signoz.io/docs"><b>Documentation</b></a> &bull;
<a href="https://github.com/SigNoz/signoz/blob/main/README.zh-cn.md"><b>ReadMe in Chinese</b></a> &bull;
<a href="https://github.com/SigNoz/signoz/blob/main/README.pt-br.md"><b>ReadMe in Portuguese</b></a> &bull;
<a href="https://bit.ly/signoz-slack"><b>Slack Community</b></a> &bull;
<a href="https://twitter.com/SigNozHq"><b>Twitter</b></a>
</h3>
@@ -28,6 +29,8 @@ SigNoz helps developers monitor applications and troubleshoot problems in their
👉 You can find the root cause of the problem by going to the exact traces which are causing the problem and see detailed flamegraphs of individual request traces.
👉 Run aggregates on trace data to get business relevant metrics
![SigNoz Feature](https://signoz-public.s3.us-east-2.amazonaws.com/signoz_hero_github.png)
@@ -49,7 +52,7 @@ Come say Hi to us on [Slack](https://join.slack.com/t/signoz-community/shared_in
- Slowest endpoints in your application
- See exact request trace to figure out issues in downstream services, slow DB queries, call to 3rd party services like payment gateways, etc
- Filter traces by service name, operation, latency, error, tags/annotations.
- Aggregate metrics on filtered traces. Eg, you can get error rate and 99th percentile latency of `customer_type: gold` or `deployment_version: v2` or `external_call: paypal`
- Run aggregates on trace data (events/spans) to get business relevant metrics. e.g. You can get error rate and 99th percentile latency of `customer_type: gold` or `deployment_version: v2` or `external_call: paypal`
- Unified UI for metrics and traces. No need to switch from Prometheus to Jaeger to debug issues.
<br /><br />

159
README.pt-br.md Normal file
View File

@@ -0,0 +1,159 @@
<p align="center">
<img src="https://res.cloudinary.com/dcv3epinx/image/upload/v1618904450/signoz-images/LogoGithub_sigfbu.svg" alt="SigNoz-logo" width="240" />
<p align="center">Monitore seus aplicativos e solucione problemas em seus aplicativos implantados, uma alternativa de código aberto para soluções como DataDog, New Relic, entre outras.</p>
</p>
<p align="center">
<img alt="License" src="https://img.shields.io/badge/license-MIT-brightgreen"> </a>
<img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/frontend?label=Downloads"> </a>
<img alt="GitHub issues" src="https://img.shields.io/github/issues/signoz/signoz"> </a>
<a href="https://twitter.com/intent/tweet?text=Monitor%20your%20applications%20and%20troubleshoot%20problems%20with%20SigNoz,%20an%20open-source%20alternative%20to%20DataDog,%20NewRelic.&url=https://signoz.io/&via=SigNozHQ&hashtags=opensource,signoz,observability">
<img alt="tweet" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"> </a>
</p>
<h3 align="center">
<a href="https://signoz.io/docs"><b>Documentação</b></a> &bull;
<a href="https://bit.ly/signoz-slack"><b>Comunidade no Slack</b></a> &bull;
<a href="https://twitter.com/SigNozHq"><b>Twitter</b></a>
</h3>
##
SigNoz auxilia os desenvolvedores a monitorarem aplicativos e solucionar problemas em seus aplicativos implantados. SigNoz usa rastreamento distribuído para obter visibilidade em sua pilha de software.
👉 Você pode verificar métricas como latência p99, taxas de erro em seus serviços, requisições às APIs externas e endpoints individuais.
👉 Você pode encontrar a causa raiz do problema acessando os rastreamentos exatos que estão causando o problema e verificar os quadros detalhados de cada requisição individual.
👉 Execute agregações em dados de rastreamento para obter métricas de negócios relevantes.
![SigNoz Feature](https://signoz-public.s3.us-east-2.amazonaws.com/signoz_hero_github.png)
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/Contributing.svg" width="50px" />
## Junte-se à nossa comunidade no Slack
Venha dizer oi para nós no [Slack](https://join.slack.com/t/signoz-community/shared_invite/zt-lrjknbbp-J_mI13rlw8pGF4EWBnorJA) 👋
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/Features.svg" width="50px" />
## Funções:
- Métricas de visão geral do aplicativo, como RPS, latências de percentual 50/90/99 e taxa de erro
- Endpoints mais lentos em seu aplicativo
- Visualize o rastreamento preciso de requisições de rede para descobrir problemas em serviços downstream, consultas lentas de banco de dados, chamadas para serviços de terceiros, como gateways de pagamento, etc.
- Filtre os rastreamentos por nome de serviço, operação, latência, erro, tags / anotações.
- Execute agregações em dados de rastreamento (eventos / extensões) para obter métricas de negócios relevantes, como por exemplo, você pode obter a taxa de erro e a latência do 99º percentil de `customer_type: gold` or `deployment_version: v2` or `external_call: paypal`
- Interface de Usuário unificada para métricas e rastreios. Não há necessidade de mudar de Prometheus para Jaeger para depurar problemas.
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/WhatsCool.svg" width="50px" />
## Por que escolher SigNoz?
Sendo desenvolvedores, achamos irritante contar com fornecedores de SaaS de código fechado para cada pequeno recurso que queríamos. Fornecedores de código fechado costumam surpreendê-lo com enormes contas no final do mês de uso sem qualquer transparência .
Queríamos fazer uma versão auto-hospedada e de código aberto de ferramentas como DataDog, NewRelic para empresas que têm preocupações com privacidade e segurança em ter dados de clientes indo para serviços de terceiros.
Ser open source também oferece controle completo de sua configuração, amostragem e tempos de atividade. Você também pode construir módulos sobre o SigNoz para estender recursos específicos do negócio.
### Linguagens Suportadas:
Nós apoiamos a biblioteca [OpenTelemetry](https://opentelemetry.io) como a biblioteca que você pode usar para instrumentar seus aplicativos. Em outras palavras, SigNoz oferece suporte a qualquer framework e linguagem que suporte a biblioteca OpenTelemetry. As principais linguagens suportadas incluem:
- Java
- Python
- NodeJS
- Go
Você pode encontrar a lista completa de linguagens aqui - https://opentelemetry.io/docs/
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/Philosophy.svg" width="50px" />
## Iniciando
### Implantar usando Docker
Siga as etapas listadas [aqui](https://signoz.io/docs/deployment/docker/) para instalar usando o Docker.
Esse [guia para solução de problemas](https://signoz.io/docs/deployment/troubleshooting) pode ser útil se você enfrentar quaisquer problemas.
<p>&nbsp </p>
### Implentar no Kubernetes usando Helm
Siga as etapas listadas [aqui](https://signoz.io/docs/deployment/helm_chart) para instalar usando helm charts.
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/UseSigNoz.svg" width="50px" />
## Comparações com ferramentas similares
### SigNoz ou Prometheus
Prometheus é bom se você quiser apenas fazer métricas. Mas se você quiser ter uma experiência perfeita entre métricas e rastreamentos, a experiência atual de unir Prometheus e Jaeger não é ótima.
Nosso objetivo é fornecer uma interface do usuário integrada entre métricas e rastreamentos - semelhante ao que fornecedores de SaaS como o Datadog fornecem - e fornecer filtragem e agregação avançada sobre rastreamentos, algo que a Jaeger atualmente carece.
<p>&nbsp </p>
### SigNoz ou Jaeger
Jaeger só faz rastreamento distribuído. SigNoz faz métricas e rastreia, e também temos gerenciamento de log em nossos planos.
Além disso, SigNoz tem alguns recursos mais avançados do que Jaeger:
- A interface de usuário do Jaegar não mostra nenhuma métrica em traces ou em traces filtrados
- Jaeger não pode obter agregados em rastros filtrados. Por exemplo, latência p99 de solicitações que possuem tag - customer_type='premium'. Isso pode ser feito facilmente com SigNoz.
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/Contributors.svg" width="50px" />
## Contribuindo
Nós ❤️ contribuições grandes ou pequenas. Leia [CONTRIBUTING.md](CONTRIBUTING.md) para começar a fazer contribuições para o SigNoz.
Não sabe como começar? Basta enviar um sinal para nós no canal `#contributing` em nossa [comunidade no Slack.](https://join.slack.com/t/signoz-community/shared_invite/zt-lrjknbbp-J_mI13rlw8pGF4EWBnorJA)
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/DevelopingLocally.svg" width="50px" />
## Documentação
Você pode encontrar a documentação em https://signoz.io/docs/. Se você tiver alguma dúvida ou sentir falta de algo, sinta-se à vontade para criar uma issue com a tag `documentation` no GitHub ou entre em contato conosco no canal da comunidade no Slack.
<br /><br />
<img align="left" src="https://signoz-public.s3.us-east-2.amazonaws.com/Contributing.svg" width="50px" />
## Comunidade
Junte-se a [comunidade no Slack](https://join.slack.com/t/signoz-community/shared_invite/zt-lrjknbbp-J_mI13rlw8pGF4EWBnorJA) para saber mais sobre rastreamento distribuído, observabilidade ou SigNoz e para se conectar com outros usuários e colaboradores.
Se você tiver alguma ideia, pergunta ou feedback, compartilhe em nosso [Github Discussões](https://github.com/SigNoz/signoz/discussions)
Como sempre, obrigado aos nossos incríveis colaboradores!
<a href="https://github.com/signoz/signoz/graphs/contributors">
<img src="https://contrib.rocks/image?repo=signoz/signoz" />
</a>

View File

@@ -0,0 +1,517 @@
<?xml version="1.0"?>
<yandex>
<logger>
<level>trace</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>10</count>
</logger>
<http_port>8123</http_port>
<tcp_port>9000</tcp_port>
<!-- For HTTPS and SSL over native protocol. -->
<!--
<https_port>8443</https_port>
<tcp_ssl_port>9440</tcp_ssl_port>
-->
<!-- Used with https_port and tcp_ssl_port. Full ssl options list: https://github.com/yandex/ClickHouse/blob/master/contrib/libpoco/NetSSL_OpenSSL/include/Poco/Net/SSLManager.h#L71 -->
<openSSL>
<server> <!-- Used for https server AND secure tcp port -->
<!-- openssl req -subj "/CN=localhost" -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout /etc/clickhouse-server/server.key -out /etc/clickhouse-server/server.crt -->
<certificateFile>/etc/clickhouse-server/server.crt</certificateFile>
<privateKeyFile>/etc/clickhouse-server/server.key</privateKeyFile>
<!-- openssl dhparam -out /etc/clickhouse-server/dhparam.pem 4096 -->
<dhParamsFile>/etc/clickhouse-server/dhparam.pem</dhParamsFile>
<verificationMode>none</verificationMode>
<loadDefaultCAFile>true</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
</server>
<client> <!-- Used for connecting to https dictionary source -->
<loadDefaultCAFile>true</loadDefaultCAFile>
<cacheSessions>true</cacheSessions>
<disableProtocols>sslv2,sslv3</disableProtocols>
<preferServerCiphers>true</preferServerCiphers>
<!-- Use for self-signed: <verificationMode>none</verificationMode> -->
<invalidCertificateHandler>
<!-- Use for self-signed: <name>AcceptCertificateHandler</name> -->
<name>RejectCertificateHandler</name>
</invalidCertificateHandler>
</client>
</openSSL>
<!-- Default root page on http[s] server. For example load UI from https://tabix.io/ when opening http://localhost:8123 -->
<!--
<http_server_default_response><![CDATA[<html ng-app="SMI2"><head><base href="http://ui.tabix.io/"></head><body><div ui-view="" class="content-ui"></div><script src="http://loader.tabix.io/master.js"></script></body></html>]]></http_server_default_response>
-->
<!-- Port for communication between replicas. Used for data exchange. -->
<interserver_http_port>9009</interserver_http_port>
<!-- Hostname that is used by other replicas to request this server.
If not specified, than it is determined analoguous to 'hostname -f' command.
This setting could be used to switch replication to another network interface.
-->
<!--
<interserver_http_host>example.yandex.ru</interserver_http_host>
-->
<!-- Listen specified host. use :: (wildcard IPv6 address), if you want to accept connections both with IPv4 and IPv6 from everywhere. -->
<listen_host>::</listen_host>
<!-- Same for hosts with disabled ipv6: -->
<!-- <listen_host>0.0.0.0</listen_host> -->
<!-- Default values - try listen localhost on ipv4 and ipv6: -->
<!-- <listen_host>0.0.0.0</listen_host> -->
<max_connections>4096</max_connections>
<keep_alive_timeout>3</keep_alive_timeout>
<!-- Maximum number of concurrent queries. -->
<max_concurrent_queries>100</max_concurrent_queries>
<!-- Set limit on number of open files (default: maximum). This setting makes sense on Mac OS X because getrlimit() fails to retrieve
correct maximum value. -->
<!-- <max_open_files>262144</max_open_files> -->
<!-- Size of cache of uncompressed blocks of data, used in tables of MergeTree family.
In bytes. Cache is single for server. Memory is allocated only on demand.
Cache is used when 'use_uncompressed_cache' user setting turned on (off by default).
Uncompressed cache is advantageous only for very short queries and in rare cases.
-->
<uncompressed_cache_size>8589934592</uncompressed_cache_size>
<!-- Approximate size of mark cache, used in tables of MergeTree family.
In bytes. Cache is single for server. Memory is allocated only on demand.
You should not lower this value.
-->
<mark_cache_size>5368709120</mark_cache_size>
<!-- Path to data directory, with trailing slash. -->
<path>/var/lib/clickhouse/</path>
<!-- Path to temporary data for processing hard queries. -->
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
<!-- Path to configuration file with users, access rights, profiles of settings, quotas. -->
<users_config>users.xml</users_config>
<!-- Default profile of settings.. -->
<default_profile>default</default_profile>
<!-- Default database. -->
<default_database>default</default_database>
<!-- Server time zone could be set here.
Time zone is used when converting between String and DateTime types,
when printing DateTime in text formats and parsing DateTime from text,
it is used in date and time related functions, if specific time zone was not passed as an argument.
Time zone is specified as identifier from IANA time zone database, like UTC or Africa/Abidjan.
If not specified, system time zone at server startup is used.
Please note, that server could display time zone alias instead of specified name.
Example: W-SU is an alias for Europe/Moscow and Zulu is an alias for UTC.
-->
<!-- <timezone>Europe/Moscow</timezone> -->
<!-- You can specify umask here (see "man umask"). Server will apply it on startup.
Number is always parsed as octal. Default umask is 027 (other users cannot read logs, data files, etc; group can only read).
-->
<!-- <umask>022</umask> -->
<!-- Configuration of clusters that could be used in Distributed tables.
https://clickhouse.yandex/reference_en.html#Distributed
-->
<remote_servers incl="clickhouse_remote_servers" >
<!-- Test only shard config for testing distributed storage -->
<test_shard_localhost>
<shard>
<replica>
<host>localhost</host>
<port>9000</port>
</replica>
</shard>
</test_shard_localhost>
</remote_servers>
<!-- If element has 'incl' attribute, then for it's value will be used corresponding substitution from another file.
By default, path to file with substitutions is /etc/metrika.xml. It could be changed in config in 'include_from' element.
Values for substitutions are specified in /yandex/name_of_substitution elements in that file.
-->
<!-- ZooKeeper is used to store metadata about replicas, when using Replicated tables.
Optional. If you don't use replicated tables, you could omit that.
See https://clickhouse.yandex/reference_en.html#Data%20replication
-->
<zookeeper incl="zookeeper-servers" optional="true" />
<!-- Substitutions for parameters of replicated tables.
Optional. If you don't use replicated tables, you could omit that.
See https://clickhouse.yandex/reference_en.html#Creating%20replicated%20tables
-->
<macros incl="macros" optional="true" />
<!-- Reloading interval for embedded dictionaries, in seconds. Default: 3600. -->
<builtin_dictionaries_reload_interval>3600</builtin_dictionaries_reload_interval>
<!-- Maximum session timeout, in seconds. Default: 3600. -->
<max_session_timeout>3600</max_session_timeout>
<!-- Default session timeout, in seconds. Default: 60. -->
<default_session_timeout>60</default_session_timeout>
<!-- Sending data to Graphite for monitoring. Several sections can be defined. -->
<!--
interval - send every X second
root_path - prefix for keys
hostname_in_path - append hostname to root_path (default = true)
metrics - send data from table system.metrics
events - send data from table system.events
asynchronous_metrics - send data from table system.asynchronous_metrics
-->
<!--
<graphite>
<host>localhost</host>
<port>42000</port>
<timeout>0.1</timeout>
<interval>60</interval>
<root_path>one_min</root_path>
<hostname_in_path>true<hostname_in_path>
<metrics>true</metrics>
<events>true</events>
<asynchronous_metrics>true</asynchronous_metrics>
</graphite>
<graphite>
<host>localhost</host>
<port>42000</port>
<timeout>0.1</timeout>
<interval>1</interval>
<root_path>one_sec</root_path>
<metrics>true</metrics>
<events>true</events>
<asynchronous_metrics>false</asynchronous_metrics>
</graphite>
-->
<!-- Query log. Used only for queries with setting log_queries = 1. -->
<query_log>
<!-- What table to insert data. If table is not exist, it will be created.
When query log structure is changed after system update,
then old table will be renamed and new table will be created automatically.
-->
<database>system</database>
<table>query_log</table>
<!-- Interval of flushing data. -->
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</query_log>
<!-- Uncomment if use part_log
<part_log>
<database>system</database>
<table>part_log</table>
<flush_interval_milliseconds>7500</flush_interval_milliseconds>
</part_log>
-->
<!-- Parameters for embedded dictionaries, used in Yandex.Metrica.
See https://clickhouse.yandex/reference_en.html#Internal%20dictionaries
-->
<!-- Path to file with region hierarchy. -->
<!-- <path_to_regions_hierarchy_file>/opt/geo/regions_hierarchy.txt</path_to_regions_hierarchy_file> -->
<!-- Path to directory with files containing names of regions -->
<!-- <path_to_regions_names_files>/opt/geo/</path_to_regions_names_files> -->
<!-- Configuration of external dictionaries. See:
https://clickhouse.yandex/reference_en.html#External%20Dictionaries
-->
<dictionaries_config>*_dictionary.xml</dictionaries_config>
<!-- Uncomment if you want data to be compressed 30-100% better.
Don't do that if you just started using ClickHouse.
-->
<compression incl="clickhouse_compression">
<!--
<!- - Set of variants. Checked in order. Last matching case wins. If nothing matches, lz4 will be used. - ->
<case>
<!- - Conditions. All must be satisfied. Some conditions may be omitted. - ->
<min_part_size>10000000000</min_part_size> <!- - Min part size in bytes. - ->
<min_part_size_ratio>0.01</min_part_size_ratio> <!- - Min size of part relative to whole table size. - ->
<!- - What compression method to use. - ->
<method>zstd</method>
</case>
-->
</compression>
<!-- Allow to execute distributed DDL queries (CREATE, DROP, ALTER, RENAME) on cluster.
Works only if ZooKeeper is enabled. Comment it if such functionality isn't required. -->
<distributed_ddl>
<!-- Path in ZooKeeper to queue with DDL queries -->
<path>/clickhouse/task_queue/ddl</path>
</distributed_ddl>
<!-- Settings to fine tune MergeTree tables. See documentation in source code, in MergeTreeSettings.h -->
<!--
<merge_tree>
<max_suspicious_broken_parts>5</max_suspicious_broken_parts>
</merge_tree>
-->
<!-- Protection from accidental DROP.
If size of a MergeTree table is greater than max_table_size_to_drop (in bytes) than table could not be dropped with any DROP query.
If you want do delete one table and don't want to restart clickhouse-server, you could create special file <clickhouse-path>/flags/force_drop_table and make DROP once.
By default max_table_size_to_drop is 50GB, max_table_size_to_drop=0 allows to DROP any tables.
Uncomment to disable protection.
-->
<!-- <max_table_size_to_drop>0</max_table_size_to_drop> -->
<!-- Example of parameters for GraphiteMergeTree table engine -->
<graphite_rollup>
<!-- carbon -->
<pattern>
<regexp>^carbon\.</regexp>
<function>any</function>
<retention>
<age>0</age>
<precision>60</precision>
</retention>
<retention>
<age>7776000</age>
<precision>3600</precision>
</retention>
<retention>
<age>10368000</age>
<precision>21600</precision>
</retention>
<retention>
<age>34560000</age>
<precision>43200</precision>
</retention>
<retention>
<age>63072000</age>
<precision>86400</precision>
</retention>
<retention>
<age>94608000</age>
<precision>604800</precision>
</retention>
</pattern>
<!-- collectd -->
<pattern>
<regexp>^collectd\.</regexp>
<function>any</function>
<retention>
<age>0</age>
<precision>10</precision>
</retention>
<retention>
<age>43200</age>
<precision>60</precision>
</retention>
<retention>
<age>864000</age>
<precision>900</precision>
</retention>
<retention>
<age>1728000</age>
<precision>1800</precision>
</retention>
<retention>
<age>3456000</age>
<precision>3600</precision>
</retention>
<retention>
<age>10368000</age>
<precision>21600</precision>
</retention>
<retention>
<age>34560000</age>
<precision>43200</precision>
</retention>
<retention>
<age>63072000</age>
<precision>86400</precision>
</retention>
<retention>
<age>94608000</age>
<precision>604800</precision>
</retention>
</pattern>
<!-- high -->
<pattern>
<regexp>^high\.</regexp>
<function>any</function>
<retention>
<age>0</age>
<precision>10</precision>
</retention>
<retention>
<age>172800</age>
<precision>60</precision>
</retention>
<retention>
<age>864000</age>
<precision>900</precision>
</retention>
<retention>
<age>1728000</age>
<precision>1800</precision>
</retention>
<retention>
<age>3456000</age>
<precision>3600</precision>
</retention>
<retention>
<age>10368000</age>
<precision>21600</precision>
</retention>
<retention>
<age>34560000</age>
<precision>43200</precision>
</retention>
<retention>
<age>63072000</age>
<precision>86400</precision>
</retention>
<retention>
<age>94608000</age>
<precision>604800</precision>
</retention>
</pattern>
<!-- medium -->
<pattern>
<regexp>^medium\.</regexp>
<function>any</function>
<retention>
<age>0</age>
<precision>60</precision>
</retention>
<retention>
<age>864000</age>
<precision>900</precision>
</retention>
<retention>
<age>1728000</age>
<precision>1800</precision>
</retention>
<retention>
<age>3456000</age>
<precision>3600</precision>
</retention>
<retention>
<age>10368000</age>
<precision>21600</precision>
</retention>
<retention>
<age>34560000</age>
<precision>43200</precision>
</retention>
<retention>
<age>63072000</age>
<precision>86400</precision>
</retention>
<retention>
<age>94608000</age>
<precision>604800</precision>
</retention>
</pattern>
<!-- low -->
<pattern>
<regexp>^low\.</regexp>
<function>any</function>
<retention>
<age>0</age>
<precision>600</precision>
</retention>
<retention>
<age>15552000</age>
<precision>1800</precision>
</retention>
<retention>
<age>31536000</age>
<precision>3600</precision>
</retention>
<retention>
<age>63072000</age>
<precision>21600</precision>
</retention>
<retention>
<age>126144000</age>
<precision>43200</precision>
</retention>
<retention>
<age>252288000</age>
<precision>86400</precision>
</retention>
<retention>
<age>315360000</age>
<precision>604800</precision>
</retention>
</pattern>
<!-- default -->
<default>
<function>any</function>
<retention>
<age>0</age>
<precision>60</precision>
</retention>
<retention>
<age>864000</age>
<precision>900</precision>
</retention>
<retention>
<age>1728000</age>
<precision>1800</precision>
</retention>
<retention>
<age>3456000</age>
<precision>3600</precision>
</retention>
<retention>
<age>10368000</age>
<precision>21600</precision>
</retention>
<retention>
<age>34560000</age>
<precision>43200</precision>
</retention>
<retention>
<age>63072000</age>
<precision>86400</precision>
</retention>
<retention>
<age>94608000</age>
<precision>604800</precision>
</retention>
</default>
</graphite_rollup>
<!-- Directory in <clickhouse-path> containing schema files for various input formats.
The directory will be created if it doesn't exist.
-->
<format_schema_path>/var/lib/clickhouse/format_schemas/</format_schema_path>
</yandex>

View File

@@ -0,0 +1,113 @@
version: "3"
services:
clickhouse:
image: yandex/clickhouse-server
expose:
- 8123
- 9000
ports:
- 9001:9000
- 8123:8123
volumes:
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
- ./docker-entrypoint-initdb.d/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
- ./data/clickhouse/:/var/lib/clickhouse/
healthcheck:
# "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'"
test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"]
interval: 30s
timeout: 5s
retries: 3
query-service:
image: signoz/query-service:0.4.1
container_name: query-service
restart: always
command: ["-config=/root/config/prometheus.yml"]
ports:
- "8080:8080"
volumes:
- ./prometheus.yml:/root/config/prometheus.yml
- ../dashboards:/root/config/dashboards
- ./data/signoz/:/var/lib/signoz/
environment:
- ClickHouseUrl=tcp://clickhouse:9000
- STORAGE=clickhouse
- POSTHOG_API_KEY=H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w
- GODEBUG=netdns=go
depends_on:
- clickhouse
frontend:
image: signoz/frontend:0.4.1
container_name: frontend
depends_on:
- query-service
links:
- "query-service"
ports:
- "3000:3000"
volumes:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/otelcontribcol:0.4.0
command: ["--config=/etc/otel-collector-config.yaml", "--mem-ballast-size-mib=2000"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
ports:
- "1777:1777" # pprof extension
- "8887:8888" # Prometheus metrics exposed by the agent
- "14268:14268" # Jaeger receiver
- "55678" # OpenCensus receiver
- "55680:55680" # OTLP HTTP/2.0 legacy port
- "55681:55681" # OTLP HTTP/1.0 receiver
- "4317:4317" # OTLP GRPC receiver
- "55679:55679" # zpages extension
- "13133" # health_check
deploy:
mode: replicated
replicas: 3
depends_on:
- clickhouse
otel-collector-hostmetrics:
image: signoz/otelcontribcol:0.4.0
command: ["--config=/etc/otel-collector-config-hostmetrics.yaml", "--mem-ballast-size-mib=683"]
volumes:
- ./otel-collector-config-hostmetrics.yaml:/etc/otel-collector-config-hostmetrics.yaml
depends_on:
- clickhouse
hotrod:
image: jaegertracing/example-hotrod:latest
container_name: hotrod
ports:
- "9000:8080"
command: ["all"]
environment:
- JAEGER_ENDPOINT=http://otel-collector:14268/api/traces
load-hotrod:
image: "grubykarol/locust:1.2.3-python3.9-alpine3.12"
container_name: load-hotrod
hostname: load-hotrod
ports:
- "8089:8089"
environment:
ATTACKED_HOST: http://hotrod:8080
LOCUST_MODE: standalone
NO_PROXY: standalone
TASK_DELAY_FROM: 5
TASK_DELAY_TO: 30
QUIET_MODE: "${QUIET_MODE:-false}"
LOCUST_OPTS: "--headless -u 10 -r 1"
volumes:
- ../common/locust-scripts:/locust

View File

@@ -0,0 +1,27 @@
CREATE TABLE IF NOT EXISTS signoz_index (
timestamp DateTime64(9) CODEC(Delta, ZSTD(1)),
traceID String CODEC(ZSTD(1)),
spanID String CODEC(ZSTD(1)),
parentSpanID String CODEC(ZSTD(1)),
serviceName LowCardinality(String) CODEC(ZSTD(1)),
name LowCardinality(String) CODEC(ZSTD(1)),
kind Int32 CODEC(ZSTD(1)),
durationNano UInt64 CODEC(ZSTD(1)),
tags Array(String) CODEC(ZSTD(1)),
tagsKeys Array(String) CODEC(ZSTD(1)),
tagsValues Array(String) CODEC(ZSTD(1)),
statusCode Int64 CODEC(ZSTD(1)),
references String CODEC(ZSTD(1)),
externalHttpMethod Nullable(String) CODEC(ZSTD(1)),
externalHttpUrl Nullable(String) CODEC(ZSTD(1)),
component Nullable(String) CODEC(ZSTD(1)),
dbSystem Nullable(String) CODEC(ZSTD(1)),
dbName Nullable(String) CODEC(ZSTD(1)),
dbOperation Nullable(String) CODEC(ZSTD(1)),
peerService Nullable(String) CODEC(ZSTD(1)),
INDEX idx_tagsKeys tagsKeys TYPE bloom_filter(0.01) GRANULARITY 64,
INDEX idx_tagsValues tagsValues TYPE bloom_filter(0.01) GRANULARITY 64,
INDEX idx_duration durationNano TYPE minmax GRANULARITY 1
) ENGINE MergeTree()
PARTITION BY toDate(timestamp)
ORDER BY (serviceName, -toUnixTimestamp(timestamp))

View File

@@ -0,0 +1,72 @@
receivers:
otlp:
protocols:
grpc:
http:
jaeger:
protocols:
grpc:
thrift_http:
hostmetrics:
collection_interval: 60s
scrapers:
cpu:
load:
memory:
disk:
filesystem:
network:
# Data sources: metrics
prometheus:
config:
scrape_configs:
- job_name: "otel-collector"
dns_sd_configs:
- names:
- 'tasks.signoz_otel-collector'
type: 'A'
port: 8888
- job_name: "otel-collector-hostmetrics"
scrape_interval: 10s
static_configs:
- targets: ["otel-collector-hostmetrics:8888"]
processors:
batch:
send_batch_size: 1000
timeout: 10s
memory_limiter:
# Same as --mem-ballast-size-mib CLI argument
ballast_size_mib: 683
# 80% of maximum memory up to 2G
limit_mib: 1500
# 25% of limit up to 2G
spike_limit_mib: 512
check_interval: 5s
# queued_retry:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
extensions:
health_check: {}
zpages: {}
exporters:
clickhouse:
datasource: tcp://clickhouse:9000
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
resource_to_telemetry_conversion:
enabled: true
service:
extensions: [health_check, zpages]
pipelines:
traces:
receivers: [jaeger, otlp]
processors: [batch]
exporters: [clickhouse]
metrics:
receivers: [otlp, prometheus, hostmetrics]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -0,0 +1,47 @@
receivers:
otlp:
protocols:
grpc:
http:
jaeger:
protocols:
grpc:
thrift_http:
processors:
batch:
send_batch_size: 1000
timeout: 10s
memory_limiter:
# Same as --mem-ballast-size-mib CLI argument
ballast_size_mib: 683
# 80% of maximum memory up to 2G
limit_mib: 1500
# 25% of limit up to 2G
spike_limit_mib: 512
check_interval: 5s
# queued_retry:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
extensions:
health_check: {}
zpages: {}
exporters:
clickhouse:
datasource: tcp://clickhouse:9000
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
resource_to_telemetry_conversion:
enabled: true
service:
extensions: [health_check, zpages]
pipelines:
traces:
receivers: [jaeger, otlp]
processors: [batch]
exporters: [clickhouse]
metrics:
receivers: [otlp]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -0,0 +1,25 @@
# my global config
global:
scrape_interval: 5s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
remote_read:
- url: tcp://clickhouse:9000/?database=signoz_metrics

View File

@@ -0,0 +1,16 @@
from locust import HttpUser, task, between
class UserTasks(HttpUser):
wait_time = between(5, 15)
@task
def rachel(self):
self.client.get("/dispatch?customer=123&nonse=0.6308392664170006")
@task
def trom(self):
self.client.get("/dispatch?customer=392&nonse=0.015296363321630757")
@task
def japanese(self):
self.client.get("/dispatch?customer=731&nonse=0.8022286220408668")
@task
def coffee(self):
self.client.get("/dispatch?customer=567&nonse=0.0022220379420636593")

View File

@@ -0,0 +1,30 @@
server {
listen 3000;
server_name _;
gzip on;
gzip_static on;
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
gzip_proxied any;
gzip_vary on;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api {
proxy_pass http://query-service:8080/api;
}
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

View File

@@ -12,6 +12,8 @@ services:
volumes:
- ./clickhouse-config.xml:/etc/clickhouse-server/config.xml
- ./docker-entrypoint-initdb.d/init-db.sql:/docker-entrypoint-initdb.d/init-db.sql
- ./data/clickhouse/:/var/lib/clickhouse/
healthcheck:
# "clickhouse", "client", "-u ${CLICKHOUSE_USER}", "--password ${CLICKHOUSE_PASSWORD}", "-q 'SELECT 1'"
test: ["CMD", "wget", "--spider", "-q", "localhost:8123/ping"]
@@ -20,23 +22,28 @@ services:
retries: 3
query-service:
image: signoz/query-service:0.3.3
image: signoz/query-service:0.4.1
container_name: query-service
command: ["-config=/root/config/prometheus.yml"]
ports:
- "8080:8080"
volumes:
- ./prometheus.yml:/root/config/prometheus.yml
- ../dashboards:/root/config/dashboards
- ./data/signoz/:/var/lib/signoz/
environment:
- ClickHouseUrl=tcp://clickhouse:9000
- STORAGE=clickhouse
- POSTHOG_API_KEY=H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w
- GODEBUG=netdns=go
depends_on:
clickhouse:
condition: service_healthy
frontend:
image: signoz/frontend:0.3.3
image: signoz/frontend:0.4.1
container_name: frontend
depends_on:
@@ -50,7 +57,7 @@ services:
otel-collector:
image: signoz/otelcol:latest
image: signoz/otelcontribcol:0.4.0
command: ["--config=/etc/otel-collector-config.yaml", "--mem-ballast-size-mib=683"]
volumes:
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml

View File

@@ -7,6 +7,11 @@ receivers:
protocols:
grpc:
thrift_http:
hostmetrics:
collection_interval: 10s
scrapers:
load:
memory:
processors:
batch:
send_batch_size: 1000
@@ -29,6 +34,10 @@ extensions:
exporters:
clickhouse:
datasource: tcp://clickhouse:9000
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
resource_to_telemetry_conversion:
enabled: true
service:
extensions: [health_check, zpages]
@@ -36,4 +45,8 @@ service:
traces:
receivers: [jaeger, otlp]
processors: [batch]
exporters: [clickhouse]
exporters: [clickhouse]
metrics:
receivers: [otlp, hostmetrics]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -0,0 +1,25 @@
# my global config
global:
scrape_interval: 5s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
# scrape_timeout is set to the global default (10s).
# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:
# - alertmanager:9093
# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
# - "first_rules.yml"
# - "second_rules.yml"
# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
remote_read:
- url: tcp://clickhouse:9000/?database=signoz_metrics

View File

@@ -147,7 +147,7 @@ services:
retries: 5
flatten-processor:
image: signoz/flattener-processor:0.3.3
image: signoz/flattener-processor:0.4.0
container_name: flattener-processor
depends_on:
@@ -163,26 +163,29 @@ services:
query-service:
image: signoz.docker.scarf.sh/signoz/query-service:0.3.3
image: signoz.docker.scarf.sh/signoz/query-service:0.4.1
container_name: query-service
depends_on:
- router
ports:
- "8080:8080"
volumes:
- ../dashboards:/root/config/dashboards
- ./data/signoz/:/var/lib/signoz/
environment:
- DruidClientUrl=http://router:8888
- DruidDatasource=flattened_spans
- STORAGE=druid
- POSTHOG_API_KEY=H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w
- GODEBUG=netdns=go
depends_on:
router:
condition: service_healthy
frontend:
image: signoz/frontend:0.3.3
image: signoz/frontend:0.4.1
container_name: frontend
depends_on:

View File

@@ -142,7 +142,7 @@ services:
retries: 5
flatten-processor:
image: signoz/flattener-processor:0.3.3
image: signoz/flattener-processor:0.4.0
container_name: flattener-processor
depends_on:
@@ -158,26 +158,30 @@ services:
query-service:
image: signoz.docker.scarf.sh/signoz/query-service:0.3.3
image: signoz.docker.scarf.sh/signoz/query-service:0.4.1
container_name: query-service
depends_on:
- router
ports:
- "8080:8080"
volumes:
- ../dashboards:/root/config/dashboards
- ./data/signoz/:/var/lib/signoz/
environment:
- DruidClientUrl=http://router:8888
- DruidDatasource=flattened_spans
- STORAGE=druid
- POSTHOG_API_KEY=H-htDCae7CR3RV57gUzmol6IAKtm5IMCvbcm_fwnL-w
- GODEBUG=netdns=go
depends_on:
router:
condition: service_healthy
frontend:
image: signoz/frontend:0.3.3
image: signoz/frontend:0.4.1
container_name: frontend
depends_on:

View File

@@ -317,7 +317,7 @@ echo ""
echo -e "👉 ${RED}Two ways to go forward\n"
echo -e "${RED}1) ClickHouse as database (default)\n"
echo -e "${RED}2) Kafka + Druid setup to handle scale (recommended for production use)\n"
echo -e "${RED}2) Kafka + Druid as datastore \n"
read -p "⚙️ Enter your preference (1/2):" choice_setup
while [[ $choice_setup != "1" && $choice_setup != "2" && $choice_setup != "" ]]
@@ -508,4 +508,4 @@ else
fi
echo -e "\n🙏 Thank you!\n"
echo -e "\n🙏 Thank you!\n"

View File

@@ -10,12 +10,12 @@ dependencies:
version: 0.2.18
- name: flattener-processor
repository: file://./signoz-charts/flattener-processor
version: 0.3.3
version: 0.3.6
- name: query-service
repository: file://./signoz-charts/query-service
version: 0.3.3
version: 0.3.6
- name: frontend
repository: file://./signoz-charts/frontend
version: 0.3.3
digest: sha256:3d9f7f0f9fc4162ccffae7aa9cc29be5885fe78d32c9e0ff7b1f0e0927f64525
generated: "2021-08-02T22:14:12.043486+05:30"
version: 0.3.6
digest: sha256:b160e903c630a90644683c512eb8ba018e18d2c08051e255edd3749cb9cc7228
generated: "2021-08-23T12:06:37.231066+05:30"

View File

@@ -34,10 +34,10 @@ dependencies:
version: 0.2.18
- name: flattener-processor
repository: "file://./signoz-charts/flattener-processor"
version: 0.3.3
version: 0.3.6
- name: query-service
repository: "file://./signoz-charts/query-service"
version: 0.3.3
version: 0.3.6
- name: frontend
repository: "file://./signoz-charts/frontend"
version: 0.3.3
version: 0.3.6

View File

@@ -14,8 +14,8 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 0.3.3
version: 0.3.6
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application.
appVersion: 0.3.3
appVersion: 0.3.6

View File

@@ -14,8 +14,8 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 0.3.3
version: 0.3.6
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application.
appVersion: 0.3.3
appVersion: 0.3.6

View File

@@ -14,8 +14,8 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
version: 0.3.3
version: 0.3.6
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application.
appVersion: 0.3.3
appVersion: 0.3.6

2
frontend/.eslintignore Normal file
View File

@@ -0,0 +1,2 @@
node_modules
build

62
frontend/.eslintrc.js Normal file
View File

@@ -0,0 +1,62 @@
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
},
extends: [
'eslint:recommended',
'plugin:react/recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:prettier/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 12,
sourceType: 'module',
},
plugins: [
'react',
'@typescript-eslint',
'simple-import-sort',
'react-hooks',
'prettier',
],
settings: {
react: {
version: 'latest',
},
},
rules: {
'react/jsx-filename-extension': [
'error',
{
extensions: ['.tsx', '.js', '.jsx'],
},
],
'react/prop-types': 'off',
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/no-var-requires': 0,
'linebreak-style': ['error', 'unix'],
// simple sort error
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
// hooks
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
'prettier/prettier': [
'error',
{},
{
usePrettierrc: true,
},
],
},
};

View File

@@ -2,6 +2,7 @@
"trailingComma": "all",
"useTabs": true,
"tabWidth": 1,
"singleQuote": false,
"jsxSingleQuote": false
"singleQuote": true,
"jsxSingleQuote": false,
"semi": true
}

3
frontend/cypress.json Normal file
View File

@@ -0,0 +1,3 @@
{
"video": false
}

View File

@@ -0,0 +1,45 @@
import ROUTES from 'constants/routes';
const Login = ({ email, name }: LoginProps): void => {
const emailInput = cy.findByPlaceholderText('mike@netflix.com');
emailInput.then((emailInput) => {
const element = emailInput[0];
// element is present
expect(element).not.undefined;
expect(element.nodeName).to.be.equal('INPUT');
});
emailInput.type(email).then((inputElements) => {
const inputElement = inputElements[0];
const inputValue = inputElement.getAttribute('value');
expect(inputValue).to.be.equals(email);
});
const firstNameInput = cy.findByPlaceholderText('Mike');
firstNameInput.then((firstNameInput) => {
const element = firstNameInput[0];
// element is present
expect(element).not.undefined;
expect(element.nodeName).to.be.equal('INPUT');
});
firstNameInput.type(name).then((inputElements) => {
const inputElement = inputElements[0];
const inputValue = inputElement.getAttribute('value');
expect(inputValue).to.be.equals(name);
});
const gettingStartedButton = cy.get('button');
gettingStartedButton.click();
cy.location('pathname').then((e) => {
expect(e).to.be.equal(ROUTES.APPLICATION);
});
};
export interface LoginProps {
email: string;
name: string;
}
export default Login;

View File

@@ -0,0 +1,35 @@
[
{
"serviceName": "frontend",
"p99": 1134610000,
"avgDuration": 744523000,
"numCalls": 267,
"callRate": 0.89,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
},
{
"serviceName": "customer",
"p99": 734422400,
"avgDuration": 348678530,
"numCalls": 267,
"callRate": 0.89,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
},
{
"serviceName": "driver",
"p99": 239234080,
"avgDuration": 204662290,
"numCalls": 267,
"callRate": 0.89,
"numErrors": 0,
"errorRate": 0,
"num4XX": 0,
"fourXXRate": 0
}
]

View File

@@ -0,0 +1,26 @@
/// <reference types="cypress" />
import ROUTES from 'constants/routes';
describe('App Layout', () => {
beforeEach(() => {
cy.visit(Cypress.env('baseUrl'));
});
it('Check the user is in Logged Out State', async () => {
cy.location('pathname').then((e) => {
expect(e).to.be.equal(ROUTES.SIGN_UP);
});
});
it('Logged In State', () => {
const testEmail = 'test@test.com';
const firstName = 'Test';
cy.login({
email: testEmail,
name: firstName,
});
});
});
export {};

View File

@@ -0,0 +1,63 @@
/// <reference types="cypress" />
import convertToNanoSecondsToSecond from 'lib/convertToNanoSecondsToSecond';
import defaultApps from '../../fixtures/defaultApp.json';
describe('Metrics', () => {
beforeEach(() => {
cy.visit(Cypress.env('baseUrl'));
const testEmail = 'test@test.com';
const firstName = 'Test';
cy
.intercept('GET', '/api/v1//services?start*', { fixture: 'defaultApp.json' })
.as('defaultApps');
cy.login({
email: testEmail,
name: firstName,
});
});
it('Default Apps', () => {
cy.wait('@defaultApps');
cy.get('tbody').then((elements) => {
const trElements = elements.children();
expect(trElements.length).to.be.equal(defaultApps.length);
const getChildren = (row: Element): Element => {
if (row.children.length === 0) {
return row;
}
return getChildren(row.children[0]);
};
// this is row element
trElements.map((index, element) => {
const [
applicationElement,
p99Element,
errorRateElement,
rpsElement,
] = element.children;
const applicationName = getChildren(applicationElement).innerHTML;
const p99Name = getChildren(p99Element).innerHTML;
const errorRateName = getChildren(errorRateElement).innerHTML;
const rpsName = getChildren(rpsElement).innerHTML;
const { serviceName, p99, errorRate, callRate } = defaultApps[index];
expect(applicationName).to.be.equal(serviceName);
expect(p99Name).to.be.equal(convertToNanoSecondsToSecond(p99).toString());
expect(errorRateName).to.be.equals(
parseFloat(errorRate.toString()).toFixed(2),
);
expect(rpsName).to.be.equals(callRate.toString());
});
});
});
});
export {};

View File

@@ -0,0 +1,24 @@
/// <reference types="cypress" />
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
// cypress/plugins/index.ts
/// <reference types="cypress" />
/**
* @type {Cypress.PluginConfig}
*/
module.exports = (on, config: Cypress.ConfigOptions) => {};
export {};

View File

@@ -0,0 +1,13 @@
import '@testing-library/cypress/add-commands';
import Login, { LoginProps } from '../CustomFunctions/Login';
Cypress.Commands.add('login', Login);
declare global {
namespace Cypress {
interface Chainable<Subject> {
login(props: LoginProps): void;
}
}
}

View File

@@ -0,0 +1,20 @@
// ***********************************************************
// This example support/index.js is processed and
// loaded automatically before your test files.
//
// This is a great place to put global configuration and
// behavior that modifies Cypress.
//
// You can change the location of this file or turn off
// automatically serving support files with the
// 'supportFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/configuration
// ***********************************************************
// Import commands.js using ES2015 syntax:
import './commands';
// Alternatively you can use CommonJS syntax:
// require('./commands')

View File

@@ -0,0 +1,12 @@
{
"extends": "../tsconfig.json",
"target": "es5",
"lib": ["es5", "dom"],
"compilerOptions": {
"noEmit": true,
// be explicit about types included
// to avoid clashing with Jest types
"types": ["cypress", "@testing-library/cypress"]
},
"include": ["../node_modules/cypress", "./**/*.ts"]
}

View File

@@ -1,24 +0,0 @@
module.exports = {
files: ["**/*.{ts,tsx}"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint/eslint-plugin"],
rules: {
"react/jsx-filename-extension": [
"error",
{
extensions: [".tsx"],
},
],
"react/prop-types": "off",
"@typescript-eslint/explicit-function-return-type": "error",
},
extends: [
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/eslint-recommended",
"prettier/@typescript-eslint",
],
env: {
browser: true,
jest: true,
},
};

View File

@@ -1,21 +1,21 @@
const gulp = require("gulp");
const gulpless = require("gulp-less");
const postcss = require("gulp-postcss");
const debug = require("gulp-debug");
var csso = require("gulp-csso");
const autteoprefixer = require("autoprefixer");
const NpmImportPlugin = require("less-plugin-npm-import");
const gulp = require('gulp');
const gulpless = require('gulp-less');
const postcss = require('gulp-postcss');
const debug = require('gulp-debug');
var csso = require('gulp-csso');
const autteoprefixer = require('autoprefixer');
const NpmImportPlugin = require('less-plugin-npm-import');
gulp.task("less", function () {
const plugins = [autoprefixer()];
gulp.task('less', function () {
const plugins = [autteoprefixer()];
return gulp
.src("src/themes/*-theme.less")
.pipe(debug({ title: "Less files:" }))
.src('src/themes/*-theme.less')
.pipe(debug({ title: 'Less files:' }))
.pipe(
gulpless({
javascriptEnabled: true,
plugins: [new NpmImportPlugin({ prefix: "~" })],
plugins: [new NpmImportPlugin({ prefix: '~' })],
}),
)
.pipe(postcss(plugins))
@@ -24,5 +24,5 @@ gulp.task("less", function () {
debug: true,
}),
)
.pipe(gulp.dest("./public"));
.pipe(gulp.dest('./public'));
});

21590
frontend/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -5,10 +5,12 @@
"main": "webpack.config.js",
"scripts": {
"dev": "NODE_ENV=development webpack serve --progress",
"start": "node scripts/start.js",
"build": "webpack --config=webpack.config.prod.js --progress",
"prettify": "prettier --write .",
"lint": "eslint src"
"lint": "eslint . --debug",
"lint:fix": "eslint . --fix --debug",
"cypress:open": "cypress open",
"cypress:run": "cypress run"
},
"engines": {
"node": ">=12.13.0"
@@ -24,10 +26,8 @@
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/chart.js": "^2.9.28",
"@types/d3": "^6.2.0",
"@types/jest": "^26.0.15",
"@types/node": "^14.14.7",
"@types/react": "^17.0.0",
"@types/react-dom": "^16.9.9",
"@types/react-redux": "^7.1.11",
@@ -35,9 +35,7 @@
"@types/redux": "^3.6.0",
"@types/styled-components": "^5.1.4",
"@types/vis": "^4.21.21",
"@typescript-eslint/eslint-plugin": "^4.5.0",
"@typescript-eslint/parser": "^4.5.0",
"antd": "^4.8.0",
"antd": "^4.16.13",
"axios": "^0.21.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.0",
@@ -48,24 +46,24 @@
"bfj": "^7.0.2",
"camelcase": "^6.1.0",
"case-sensitive-paths-webpack-plugin": "2.3.0",
"chart.js": "^2.9.4",
"chart.js": "^3.4.0",
"chartjs-adapter-date-fns": "^2.0.0",
"css-loader": "4.3.0",
"d3": "^6.2.0",
"d3-flame-graph": "^3.1.1",
"d3-tip": "^0.9.1",
"dotenv": "8.2.0",
"eslint": "^7.29.0",
"dotenv-expand": "5.1.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",
"history": "4.10.1",
"html-webpack-plugin": "5.1.0",
"identity-obj-proxy": "3.0.0",
"jest": "26.6.0",
@@ -80,13 +78,13 @@
"prop-types": "^15.6.2",
"react": "17.0.0",
"react-app-polyfill": "^2.0.0",
"react-chartjs-2": "^2.11.1",
"react-chips": "^0.8.0",
"react-css-theme-switcher": "^0.1.6",
"react-dev-utils": "^11.0.0",
"react-dom": "17.0.0",
"react-force-graph": "^1.41.0",
"react-graph-vis": "^1.0.5",
"react-grid-layout": "^1.2.5",
"react-modal": "^3.12.1",
"react-redux": "^7.2.2",
"react-refresh": "^0.8.3",
@@ -102,8 +100,10 @@
"styled-components": "^5.2.1",
"terser-webpack-plugin": "4.2.3",
"ts-pnp": "1.2.0",
"tsconfig-paths-webpack-plugin": "^3.5.1",
"typescript": "^4.0.5",
"url-loader": "4.1.1",
"uuid": "^8.3.2",
"web-vitals": "^0.2.4",
"webpack": "^5.23.0",
"webpack-dev-server": "^3.11.2",
@@ -129,11 +129,28 @@
"@babel/preset-env": "^7.12.17",
"@babel/preset-react": "^7.12.13",
"@babel/preset-typescript": "^7.12.17",
"@testing-library/cypress": "^8.0.0",
"@types/d3-tip": "^3.5.5",
"@types/lodash-es": "^4.17.4",
"@types/node": "^14.17.12",
"@types/react-grid-layout": "^1.1.2",
"@types/uuid": "^8.3.1",
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"autoprefixer": "^9.0.0",
"babel-plugin-styled-components": "^1.12.0",
"compression-webpack-plugin": "^8.0.0",
"copy-webpack-plugin": "^7.0.0",
"cypress": "^8.3.0",
"eslint": "^7.30.0",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
"eslint-plugin-promise": "^5.1.0",
"eslint-plugin-react": "^7.24.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"gulp": "^4.0.2",
"gulp-csso": "^4.0.1",
"gulp-debug": "^4.0.0",

10
frontend/public/css/antd.dark.min.css vendored Normal file

File diff suppressed because one or more lines are too long

10
frontend/public/css/antd.min.css vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

View File

@@ -0,0 +1,45 @@
import NotFound from 'components/NotFound';
import Spinner from 'components/Spinner';
import { IS_LOGGED_IN } from 'constants/auth';
import ROUTES from 'constants/routes';
import history from 'lib/history';
import AppLayout from 'modules/AppLayout';
import { RouteProvider } from 'modules/RouteProvider';
import React, { Suspense } from 'react';
import { Redirect, Route, Router, Switch } from 'react-router-dom';
import routes from './routes';
const App = (): JSX.Element => (
<Router history={history}>
<RouteProvider>
<AppLayout>
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
<Switch>
{routes.map(({ path, component, exact }, index) => {
return (
<Route key={index} exact={exact} path={path} component={component} />
);
})}
{/* This logic should be moved to app layout */}
<Route
path="/"
exact
render={(): JSX.Element => {
return localStorage.getItem(IS_LOGGED_IN) === 'yes' ? (
<Redirect to={ROUTES.APPLICATION} />
) : (
<Redirect to={ROUTES.SIGN_UP} />
);
}}
/>
<Route path="*" exact component={NotFound} />
</Switch>
</Suspense>
</AppLayout>
</RouteProvider>
</Router>
);
export default App;

View File

@@ -0,0 +1,74 @@
import Loadable from 'components/Loadable';
export const ServiceMetricsPage = Loadable(
() =>
import(
/* webpackChunkName: "ServiceMetricsPage" */ 'modules/Metrics/ServiceMetricsDef'
),
);
export const ServiceMapPage = Loadable(
() =>
import(
/* webpackChunkName: "ServiceMapPage" */ 'modules/Servicemap/ServiceMap'
),
);
export const TraceDetailPage = Loadable(
() =>
import(
/* webpackChunkName: "TraceDetailPage" */ 'modules/Traces/TraceDetail'
),
);
export const TraceGraphPage = Loadable(
() =>
import(
/* webpackChunkName: "TraceGraphPage" */ 'modules/Traces/TraceGraphDef'
),
);
export const UsageExplorerPage = Loadable(
() =>
import(
/* webpackChunkName: "UsageExplorerPage" */ 'modules/Usage/UsageExplorerDef'
),
);
export const ServicesTablePage = Loadable(
() =>
import(
/* webpackChunkName: "ServicesTablePage" */ 'modules/Metrics/ServicesTableDef'
),
);
export const SignupPage = Loadable(
() => import(/* webpackChunkName: "SignupPage" */ 'modules/Auth/Signup'),
);
export const SettingsPage = Loadable(
() =>
import(
/* webpackChunkName: "SettingsPage" */ 'modules/Settings/settingsPage'
),
);
export const InstrumentationPage = Loadable(
() =>
import(
/* webpackChunkName: "InstrumentationPage" */ 'modules/add-instrumentation/instrumentationPage'
),
);
export const DashboardPage = Loadable(
() => import(/* webpackChunkName: "DashboardPage" */ 'pages/Dashboard'),
);
export const NewDashboardPage = Loadable(
() => import(/* webpackChunkName: "New DashboardPage" */ 'pages/NewDashboard'),
);
export const DashboardWidget = Loadable(
() =>
import(/* webpackChunkName: "New DashboardPage" */ 'pages/DashboardWidget'),
);

View File

@@ -0,0 +1,89 @@
import ROUTES from 'constants/routes';
import DashboardWidget from 'pages/DashboardWidget';
import { RouteProps } from 'react-router-dom';
import {
DashboardPage,
InstrumentationPage,
NewDashboardPage,
ServiceMapPage,
ServiceMetricsPage,
ServicesTablePage,
SettingsPage,
SignupPage,
TraceDetailPage,
TraceGraphPage,
UsageExplorerPage,
} from './pageComponents';
const routes: AppRoutes[] = [
{
component: SignupPage,
path: ROUTES.SIGN_UP,
exact: true,
},
{
component: ServicesTablePage,
path: ROUTES.APPLICATION,
exact: true,
},
{
path: ROUTES.SERVICE_METRICS,
exact: true,
component: ServiceMetricsPage,
},
{
path: ROUTES.SERVICE_MAP,
component: ServiceMapPage,
exact: true,
},
{
path: ROUTES.TRACE_GRAPH,
exact: true,
component: TraceGraphPage,
},
{
path: ROUTES.SETTINGS,
exact: true,
component: SettingsPage,
},
{
path: ROUTES.USAGE_EXPLORER,
exact: true,
component: UsageExplorerPage,
},
{
path: ROUTES.INSTRUMENTATION,
exact: true,
component: InstrumentationPage,
},
{
path: ROUTES.TRACES,
exact: true,
component: TraceDetailPage,
},
{
path: ROUTES.ALL_DASHBOARD,
exact: true,
component: DashboardPage,
},
{
path: ROUTES.DASHBOARD,
exact: true,
component: NewDashboardPage,
},
{
path: ROUTES.DASHBOARD_WIDGET,
exact: true,
component: DashboardWidget,
},
];
interface AppRoutes {
component: RouteProps['component'];
path: RouteProps['path'];
exact: RouteProps['exact'];
isPrivate?: boolean;
}
export default routes;

View File

@@ -0,0 +1,57 @@
import { AxiosError } from 'axios';
import { ErrorResponse } from 'types/api';
import { ErrorStatusCode } from 'types/common';
export const ErrorResponseHandler = (error: AxiosError): ErrorResponse => {
if (error.response) {
// client received an error response (5xx, 4xx)
// making the error status code as standard Error Status Code
const statusCode = error.response.status as ErrorStatusCode;
if (statusCode >= 400 && statusCode < 500) {
const { data } = error.response;
if (statusCode === 404) {
return {
statusCode,
payload: null,
error: 'Not Found',
message: null,
};
}
return {
statusCode,
payload: null,
error: data.error,
message: null,
};
}
return {
statusCode,
payload: null,
error: 'Something went wrong',
message: null,
};
}
if (error.request) {
// client never received a response, or request never left
console.error('client never received a response, or request never left');
return {
statusCode: 500,
payload: null,
error: 'Something went wrong',
message: null,
};
}
// anything else
console.error('any');
return {
statusCode: 500,
payload: null,
error: error.toString(),
message: null,
};
};

View File

@@ -1,3 +1,3 @@
const apiV1 = "/api/v1/";
const apiV1 = '/api/v1/';
export default apiV1;

View File

@@ -0,0 +1,26 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/dashboard/create';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post('/dashboards', {
...props,
});
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default create;

View File

@@ -0,0 +1,24 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { Props } from 'types/api/dashboard/delete';
const deleteDashboard = async (
props: Props,
): Promise<SuccessResponse<undefined> | ErrorResponse> => {
try {
const response = await axios.delete(`/dashboards/${props.uuid}`);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default deleteDashboard;

View File

@@ -0,0 +1,24 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/dashboard/get';
const get = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.get(`/dashboards/${props.uuid}`);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default get;

View File

@@ -0,0 +1,24 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/dashboard/getAll';
const getAll = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try {
const response = await axios.get('/dashboards');
return {
statusCode: 200,
error: null,
message: response.data.message,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getAll;

View File

@@ -0,0 +1,26 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/dashboard/update';
const update = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.put(`/dashboards/${props.uuid}`, {
...props,
});
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default update;

View File

@@ -1,9 +1,10 @@
import axios, { AxiosRequestConfig } from "axios";
import { ENVIRONMENT } from "Src/constants/env";
import apiV1 from "./apiV1";
import axios from 'axios';
import { ENVIRONMENT } from 'constants/env';
import apiV1 from './apiV1';
export default axios.create({
baseURL: `${ENVIRONMENT.baseURL}`,
baseURL: `${ENVIRONMENT.baseURL}${apiV1}`,
});
export { apiV1 };

View File

@@ -0,0 +1,26 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/widgets/getQuery';
const getQuery = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.get(
`/query_range?query=${props.query}&start=${props.start}&end=${props.end}&step=${props.step}`,
);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default getQuery;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,18 @@
import React from 'react';
const Value = (): JSX.Element => (
<svg
width="78"
height="32"
viewBox="0 0 78 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M15.0215 17.875C14.2285 18.8184 13.2783 19.5771 12.1709 20.1514C11.0771 20.7256 9.87402 21.0127 8.56152 21.0127C6.83887 21.0127 5.33496 20.5889 4.0498 19.7412C2.77832 18.8936 1.79395 17.7041 1.09668 16.1729C0.399414 14.6279 0.0507812 12.9258 0.0507812 11.0664C0.0507812 9.07031 0.426758 7.27246 1.17871 5.67285C1.94434 4.07324 3.02441 2.84961 4.41895 2.00195C5.81348 1.1543 7.44043 0.730469 9.2998 0.730469C12.2529 0.730469 14.5771 1.83789 16.2725 4.05273C17.9814 6.25391 18.8359 9.26172 18.8359 13.0762V14.1836C18.8359 19.9941 17.6875 24.2393 15.3906 26.9189C13.0938 29.585 9.62793 30.9521 4.99316 31.0205H4.25488V27.8213H5.05469C8.18555 27.7666 10.5918 26.9531 12.2734 25.3809C13.9551 23.7949 14.8711 21.293 15.0215 17.875ZM9.17676 17.875C10.4482 17.875 11.6172 17.4854 12.6836 16.7061C13.7637 15.9268 14.5498 14.9629 15.042 13.8145V12.2969C15.042 9.80859 14.502 7.78516 13.4219 6.22656C12.3418 4.66797 10.9746 3.88867 9.32031 3.88867C7.65234 3.88867 6.3125 4.53125 5.30078 5.81641C4.28906 7.08789 3.7832 8.76953 3.7832 10.8613C3.7832 12.8984 4.26855 14.5801 5.23926 15.9062C6.22363 17.2188 7.53613 17.875 9.17676 17.875ZM24.5371 29.0107C24.5371 28.3545 24.7285 27.8076 25.1113 27.3701C25.5078 26.9326 26.0957 26.7139 26.875 26.7139C27.6543 26.7139 28.2422 26.9326 28.6387 27.3701C29.0488 27.8076 29.2539 28.3545 29.2539 29.0107C29.2539 29.6396 29.0488 30.166 28.6387 30.5898C28.2422 31.0137 27.6543 31.2256 26.875 31.2256C26.0957 31.2256 25.5078 31.0137 25.1113 30.5898C24.7285 30.166 24.5371 29.6396 24.5371 29.0107ZM51.1562 20.9717H55.2988V24.0684H51.1562V31H47.3418V24.0684H33.7451V21.833L47.1162 1.14062H51.1562V20.9717ZM38.0518 20.9717H47.3418V6.3291L46.8906 7.14941L38.0518 20.9717ZM73.6123 1.12012V4.33984H72.915C69.9619 4.39453 67.6104 5.26953 65.8604 6.96484C64.1104 8.66016 63.0986 11.0459 62.8252 14.1221C64.3975 12.3174 66.5439 11.415 69.2646 11.415C71.8623 11.415 73.9336 12.3311 75.4785 14.1631C77.0371 15.9951 77.8164 18.3604 77.8164 21.2588C77.8164 24.335 76.9756 26.7959 75.2939 28.6416C73.626 30.4873 71.3838 31.4102 68.5674 31.4102C65.71 31.4102 63.3926 30.3164 61.6152 28.1289C59.8379 25.9277 58.9492 23.0977 58.9492 19.6387V18.1826C58.9492 12.6865 60.1182 8.48926 62.4561 5.59082C64.8076 2.67871 68.3008 1.18848 72.9355 1.12012H73.6123ZM68.6289 14.5732C67.3301 14.5732 66.1338 14.9629 65.04 15.7422C63.9463 16.5215 63.1875 17.499 62.7637 18.6748V20.0693C62.7637 22.5303 63.3174 24.5127 64.4248 26.0166C65.5322 27.5205 66.9131 28.2725 68.5674 28.2725C70.2764 28.2725 71.6162 27.6436 72.5869 26.3857C73.5713 25.1279 74.0635 23.4805 74.0635 21.4434C74.0635 19.3926 73.5645 17.7383 72.5664 16.4805C71.582 15.209 70.2695 14.5732 68.6289 14.5732Z"
fill="white"
/>
</svg>
);
export default Value;

View File

@@ -1,4 +1,4 @@
import React from "react";
import React from 'react';
const NotFound = (): JSX.Element => {
return (
@@ -9,7 +9,7 @@ const NotFound = (): JSX.Element => {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g clip-path="url(#clip0)">
<g clipPath="url(#clip0)">
<path
d="M181.155 195.76C278.772 195.76 357.906 190.521 357.906 184.059C357.906 177.596 278.772 172.358 181.155 172.358C83.5382 172.358 4.40404 177.596 4.40404 184.059C4.40404 190.521 83.5382 195.76 181.155 195.76Z"
fill="#F2F2F2"
@@ -29,17 +29,17 @@ const NotFound = (): JSX.Element => {
<path
d="M110.947 141.154H99.0408V106.092C99.0408 105.17 98.8592 104.257 98.5063 103.405C98.1535 102.553 97.6362 101.779 96.9842 101.127C96.3322 100.475 95.5581 99.9579 94.7062 99.605C93.8543 99.2522 92.9412 99.0705 92.0191 99.0705H89.2291C87.3668 99.0705 85.5808 99.8103 84.264 101.127C82.9472 102.444 82.2074 104.23 82.2074 106.092V141.154H48.623C47.9321 141.154 47.2529 140.976 46.6513 140.636C46.0498 140.296 45.5463 139.806 45.1896 139.215C44.833 138.623 44.6354 137.949 44.616 137.258C44.5965 136.568 44.7559 135.884 45.0787 135.273L80.6241 67.9968C81.0672 67.1581 81.3358 66.2382 81.4137 65.2927C81.4915 64.3473 81.377 63.3959 81.077 62.4959C80.777 61.596 80.2977 60.7662 79.6681 60.0566C79.0386 59.3469 78.2717 58.7722 77.4139 58.3672L75.3156 57.3763C73.6863 56.6069 71.8235 56.4933 70.1128 57.059C68.402 57.6247 66.9742 58.8263 66.1248 60.4154L22.7725 141.514C22.0343 142.895 21.648 144.437 21.648 146.003V146.003C21.648 148.528 22.6512 150.95 24.4368 152.735C26.2224 154.521 28.6442 155.524 31.1694 155.524H82.2074V177.695C82.2074 178.8 82.4251 179.895 82.8481 180.916C83.271 181.937 83.891 182.865 84.6726 183.647C85.4541 184.428 86.382 185.048 87.4032 185.471C88.4243 185.894 89.5188 186.112 90.6241 186.112H90.6241C92.8564 186.112 94.9972 185.225 96.5756 183.647C98.1541 182.068 99.0408 179.927 99.0408 177.695V155.524H110.947C111.891 155.524 112.825 155.338 113.697 154.977C114.569 154.616 115.361 154.087 116.028 153.42C116.695 152.753 117.224 151.96 117.585 151.089C117.947 150.217 118.132 149.283 118.132 148.339V148.339C118.132 147.396 117.947 146.461 117.585 145.59C117.224 144.718 116.695 143.926 116.028 143.259C115.361 142.591 114.569 142.062 113.697 141.701C112.825 141.34 111.891 141.154 110.947 141.154V141.154Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M334.298 141.154H322.392V106.092C322.392 104.23 321.652 102.444 320.335 101.127C319.018 99.8103 317.232 99.0705 315.37 99.0705H312.58C311.658 99.0705 310.745 99.2522 309.893 99.605C309.041 99.9579 308.267 100.475 307.615 101.127C306.963 101.779 306.446 102.553 306.093 103.405C305.74 104.257 305.558 105.17 305.558 106.092V141.154H271.974C271.283 141.154 270.604 140.976 270.002 140.636C269.401 140.296 268.897 139.806 268.541 139.215C268.184 138.623 267.986 137.949 267.967 137.258C267.948 136.568 268.107 135.884 268.43 135.273L303.975 67.9968C304.418 67.1581 304.687 66.2382 304.765 65.2927C304.843 64.3473 304.728 63.3959 304.428 62.4959C304.128 61.596 303.649 60.7662 303.019 60.0566C302.39 59.3469 301.623 58.7722 300.765 58.3672L298.667 57.3763C297.037 56.6069 295.175 56.4933 293.464 57.059C291.753 57.6247 290.325 58.8263 289.476 60.4154L246.124 141.514C245.385 142.895 244.999 144.437 244.999 146.003C244.999 148.528 246.002 150.95 247.788 152.735C249.573 154.521 251.995 155.524 254.52 155.524H305.558V177.695C305.558 179.927 306.445 182.068 308.024 183.647C309.602 185.225 311.743 186.112 313.975 186.112V186.112C316.207 186.112 318.348 185.225 319.927 183.647C321.505 182.068 322.392 179.927 322.392 177.695V155.524H334.298C335.242 155.524 336.176 155.338 337.048 154.977C337.92 154.616 338.712 154.087 339.379 153.42C340.046 152.753 340.575 151.96 340.936 151.089C341.298 150.217 341.483 149.283 341.483 148.339V148.339C341.483 146.434 340.726 144.606 339.379 143.259C338.032 141.911 336.204 141.154 334.298 141.154V141.154Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M180.95 52.2653C152.152 52.2653 131.476 70.741 131.476 113.851C131.476 162.709 152.152 175.642 180.95 175.642C209.747 175.642 231.656 161.477 231.656 113.851C231.656 62.9402 209.747 52.2653 180.95 52.2653ZM181.139 159.425C161.193 159.425 150.773 147.723 150.773 113.883C150.773 84.0236 161.62 68.2776 181.566 68.2776C201.512 68.2776 212.359 78.6206 212.359 113.883C212.359 146.87 201.085 159.425 181.139 159.425V159.425Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M157.867 10.4381C160.254 10.4381 162.19 8.5027 162.19 6.11526C162.19 3.72782 160.254 1.79242 157.867 1.79242C155.479 1.79242 153.544 3.72782 153.544 6.11526C153.544 8.5027 155.479 10.4381 157.867 10.4381Z"
@@ -129,12 +129,12 @@ const NotFound = (): JSX.Element => {
<path
d="M345.776 182.211C345.176 179.158 347.774 176.452 350.34 174.693C352.906 172.934 355.904 171.205 356.779 168.22C358.037 163.93 354.29 160.001 351.373 156.613C349.208 154.098 347.35 151.336 345.836 148.384C345.229 147.2 344.671 145.963 344.512 144.643C344.282 142.741 344.893 140.848 345.508 139.034C347.559 132.992 349.751 126.999 352.085 121.058"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M337.66 139.656C338.675 140.025 339.762 140.153 340.835 140.03C341.908 139.908 342.938 139.537 343.844 138.949C344.749 138.36 345.506 137.569 346.053 136.638C346.601 135.708 346.925 134.662 347 133.585C347.075 132.507 346.898 131.427 346.484 130.43C346.071 129.432 345.431 128.544 344.615 127.836C343.8 127.128 342.831 126.619 341.785 126.349C340.739 126.079 339.645 126.056 338.589 126.281L338.764 129.871L337.065 126.794C335.399 127.578 334.111 128.99 333.486 130.722C333.263 131.329 333.128 131.964 333.084 132.609C332.977 134.121 333.366 135.627 334.192 136.899C335.017 138.171 336.235 139.138 337.66 139.656V139.656Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M344.924 119.818C345.322 118.719 345.99 117.738 346.868 116.965C347.745 116.192 348.802 115.653 349.943 115.396L350.517 118.808L351.582 115.225C353.06 115.246 354.493 115.738 355.673 116.627C356.854 117.516 357.722 118.758 358.151 120.172C358.58 121.587 358.548 123.101 358.061 124.497C357.573 125.892 356.655 127.097 355.438 127.936C354.221 128.776 352.769 129.207 351.292 129.167C349.814 129.127 348.387 128.619 347.217 127.716C346.047 126.813 345.194 125.561 344.782 124.141C344.37 122.722 344.419 121.208 344.924 119.818H344.924Z"
@@ -143,7 +143,7 @@ const NotFound = (): JSX.Element => {
<path
d="M345.306 118.586C345.705 117.487 346.373 116.506 347.251 115.733C348.128 114.96 349.185 114.421 350.326 114.164L350.9 117.576L351.965 113.992C353.443 114.014 354.875 114.505 356.056 115.395C357.237 116.284 358.105 117.526 358.534 118.94C358.963 120.355 358.931 121.869 358.444 123.265C357.956 124.66 357.038 125.864 355.821 126.704C354.604 127.543 353.152 127.974 351.675 127.935C350.197 127.895 348.77 127.387 347.6 126.484C346.43 125.58 345.577 124.329 345.165 122.909C344.753 121.489 344.802 119.976 345.306 118.586H345.306Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M350.148 156.682C351.758 157.266 353.527 157.237 355.116 156.601C356.706 155.965 358.006 154.766 358.769 153.233C359.532 151.7 359.704 149.939 359.252 148.288C358.801 146.636 357.757 145.208 356.32 144.276L355.502 147.03L354.922 143.578C354.916 143.575 354.911 143.573 354.904 143.571C354.043 143.258 353.129 143.118 352.214 143.159C351.299 143.199 350.401 143.42 349.571 143.807C348.741 144.195 347.995 144.743 347.377 145.419C346.759 146.095 346.28 146.886 345.967 147.747C345.655 148.608 345.515 149.523 345.556 150.438C345.597 151.353 345.818 152.251 346.207 153.081C346.595 153.91 347.143 154.656 347.819 155.273C348.496 155.891 349.287 156.37 350.148 156.682H350.148Z"
@@ -152,7 +152,7 @@ const NotFound = (): JSX.Element => {
<path
d="M350.48 155.434C352.09 156.018 353.858 155.989 355.448 155.353C357.038 154.717 358.338 153.518 359.101 151.985C359.864 150.452 360.036 148.691 359.584 147.04C359.132 145.388 358.089 143.96 356.652 143.028L355.834 145.782L355.254 142.33C355.248 142.327 355.242 142.325 355.236 142.323C354.375 142.01 353.461 141.87 352.546 141.911C351.631 141.951 350.732 142.172 349.902 142.559C349.072 142.947 348.327 143.495 347.709 144.171C347.091 144.847 346.611 145.638 346.299 146.499C345.987 147.36 345.847 148.274 345.888 149.19C345.929 150.105 346.15 151.003 346.538 151.833C346.927 152.662 347.475 153.407 348.151 154.025C348.827 154.643 349.619 155.122 350.48 155.434H350.48Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M342.888 168.263C343.165 169.838 343.975 171.269 345.182 172.318C346.389 173.367 347.92 173.968 349.519 174.022C351.117 174.076 352.685 173.579 353.96 172.614C355.235 171.649 356.139 170.275 356.521 168.722C356.903 167.169 356.74 165.532 356.058 164.086C355.377 162.639 354.219 161.471 352.778 160.777C351.338 160.083 349.702 159.905 348.146 160.274C346.59 160.643 345.208 161.535 344.232 162.802L347.339 167.478L343.094 164.996C342.765 166.053 342.694 167.173 342.888 168.263V168.263Z"
@@ -161,7 +161,7 @@ const NotFound = (): JSX.Element => {
<path
d="M343.176 167.339C343.452 168.913 344.262 170.345 345.469 171.394C346.677 172.443 348.208 173.044 349.806 173.098C351.404 173.152 352.972 172.655 354.247 171.69C355.522 170.725 356.426 169.35 356.808 167.798C357.191 166.245 357.027 164.608 356.346 163.162C355.664 161.715 354.506 160.547 353.065 159.853C351.625 159.159 349.989 158.981 348.433 159.35C346.877 159.719 345.495 160.611 344.519 161.878L347.627 166.554L343.381 164.072C343.052 165.129 342.981 166.249 343.176 167.339V167.339Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M3.01816 157.568C3.68505 157.81 4.39914 157.894 5.10415 157.814C5.80915 157.733 6.48579 157.49 7.08075 157.103C7.6757 156.716 8.17269 156.197 8.53256 155.585C8.89243 154.974 9.10533 154.287 9.15448 153.579C9.20364 152.871 9.0877 152.161 8.81581 151.506C8.54393 150.851 8.12352 150.267 7.58772 149.802C7.05193 149.337 6.4154 149.002 5.7283 148.825C5.04121 148.648 4.32233 148.633 3.62832 148.78L3.74301 151.139L2.62726 149.118C1.53221 149.632 0.686246 150.56 0.275259 151.698C0.129301 152.097 0.0405688 152.514 0.0117106 152.938C-0.0587161 153.931 0.19668 154.921 0.739195 155.757C1.28171 156.592 2.08178 157.228 3.01816 157.568V157.568Z"
@@ -170,12 +170,12 @@ const NotFound = (): JSX.Element => {
<path
d="M8.53892 184.92C8.14506 182.914 9.85174 181.136 11.5375 179.98C13.2233 178.825 15.1931 177.689 15.7683 175.728C16.595 172.909 14.1326 170.328 12.2161 168.102C10.7942 166.45 9.57311 164.635 8.57841 162.695C8.14597 161.933 7.85142 161.101 7.70834 160.237C7.55722 158.988 7.95864 157.744 8.36304 156.552C9.71024 152.582 11.1506 148.645 12.6842 144.741"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M3.20684 156.961C3.87373 157.203 4.58782 157.287 5.29282 157.207C5.99782 157.126 6.67447 156.883 7.26942 156.496C7.86437 156.109 8.36136 155.59 8.72123 154.978C9.08109 154.367 9.29399 153.68 9.34315 152.972C9.3923 152.264 9.27637 151.554 9.00448 150.899C8.73259 150.243 8.31218 149.66 7.77639 149.195C7.2406 148.73 6.60407 148.395 5.91698 148.218C5.22988 148.041 4.51101 148.025 3.817 148.173L3.93169 150.532L2.81594 148.511C1.72089 149.025 0.874921 149.953 0.463934 151.091C0.317977 151.49 0.229247 151.907 0.200387 152.331C0.129956 153.324 0.38535 154.314 0.927866 155.149C1.47038 155.985 2.27045 156.621 3.20684 156.961V156.961Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M7.97892 143.927C8.24064 143.205 8.67989 142.56 9.25622 142.052C9.83254 141.545 10.5274 141.19 11.2767 141.022L11.654 143.264L12.3534 140.909C13.3245 140.923 14.2659 141.246 15.0417 141.83C15.8175 142.415 16.3875 143.23 16.6695 144.16C16.9514 145.089 16.9307 146.084 16.6104 147.001C16.29 147.918 15.6866 148.709 14.8872 149.261C14.0878 149.812 13.1337 150.095 12.1629 150.069C11.192 150.043 10.2545 149.709 9.48578 149.116C8.71703 148.522 8.15678 147.7 7.88593 146.767C7.61509 145.835 7.64765 144.84 7.97892 143.927V143.927Z"
@@ -184,7 +184,7 @@ const NotFound = (): JSX.Element => {
<path
d="M8.23051 143.117C8.49223 142.395 8.93148 141.751 9.50781 141.243C10.0841 140.735 10.779 140.381 11.5283 140.212L11.9056 142.454L12.605 140.099C13.5761 140.114 14.5175 140.436 15.2933 141.021C16.0691 141.605 16.6391 142.421 16.921 143.35C17.203 144.279 17.1823 145.274 16.8619 146.191C16.5416 147.108 15.9381 147.899 15.1387 148.451C14.3393 149.003 13.3853 149.286 12.4145 149.26C11.4436 149.234 10.5061 148.9 9.73737 148.306C8.96861 147.713 8.40837 146.89 8.13752 145.958C7.86667 145.025 7.89923 144.03 8.23051 143.117V143.117Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M11.4118 168.147C12.4694 168.531 13.6312 168.512 14.6758 168.094C15.7203 167.676 16.5746 166.888 17.0757 165.881C17.5768 164.874 17.6898 163.717 17.3931 162.632C17.0963 161.547 16.4106 160.609 15.4667 159.996L14.9293 161.806L14.5482 159.538C14.5444 159.536 14.5405 159.534 14.5365 159.533C13.9708 159.327 13.3701 159.235 12.7687 159.262C12.1673 159.288 11.5771 159.433 11.0317 159.688C10.4863 159.943 9.99649 160.302 9.59021 160.747C9.18392 161.191 8.86914 161.711 8.66386 162.276C8.45859 162.842 8.36684 163.443 8.39385 164.044C8.42087 164.646 8.56612 165.236 8.82132 165.781C9.07651 166.326 9.43664 166.816 9.88112 167.222C10.3256 167.628 10.8457 167.942 11.4118 168.147V168.147Z"
@@ -193,7 +193,7 @@ const NotFound = (): JSX.Element => {
<path
d="M11.6298 167.327C12.6874 167.711 13.8492 167.692 14.8938 167.274C15.9383 166.856 16.7926 166.068 17.2937 165.061C17.7949 164.054 17.9078 162.897 17.6111 161.812C17.3143 160.727 16.6287 159.789 15.6847 159.176L15.1473 160.986L14.7662 158.718C14.7624 158.716 14.7585 158.714 14.7545 158.713C14.1889 158.508 13.5885 158.416 12.9874 158.443C12.3864 158.47 11.7965 158.615 11.2515 158.87C10.1508 159.385 9.29959 160.315 8.88523 161.458C8.47086 162.6 8.52722 163.86 9.04193 164.961C9.55663 166.061 10.4875 166.913 11.6298 167.327V167.327Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M6.64183 175.756C6.82368 176.791 7.35579 177.731 8.14892 178.42C8.94205 179.109 9.94797 179.505 10.998 179.54C12.048 179.575 13.0782 179.249 13.9159 178.615C14.7536 177.981 15.3478 177.078 15.5988 176.058C15.8499 175.037 15.7425 173.962 15.2947 173.012C14.847 172.061 14.086 171.294 13.1395 170.838C12.193 170.382 11.1185 170.265 10.0962 170.507C9.07393 170.75 8.16602 171.336 7.52475 172.168L9.56612 175.241L6.77684 173.61C6.56057 174.304 6.51427 175.04 6.64183 175.756V175.756Z"
@@ -202,7 +202,7 @@ const NotFound = (): JSX.Element => {
<path
d="M6.83052 175.149C7.01237 176.184 7.54448 177.124 8.33761 177.813C9.13074 178.502 10.1367 178.898 11.1867 178.933C12.2367 178.968 13.2669 178.642 14.1046 178.007C14.9423 177.373 15.5365 176.471 15.7875 175.45C16.0386 174.43 15.9312 173.355 15.4834 172.404C15.0357 171.454 14.2747 170.686 13.3282 170.23C12.3817 169.774 11.3072 169.658 10.2849 169.9C9.26262 170.142 8.35471 170.729 7.71343 171.561L9.75481 174.633L6.96553 173.003C6.74926 173.697 6.70296 174.433 6.83052 175.149V175.149Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M161.152 114.299C164.298 114.299 166.848 110.998 166.848 106.927C166.848 102.856 164.298 99.5555 161.152 99.5555C158.006 99.5555 155.456 102.856 155.456 106.927C155.456 110.998 158.006 114.299 161.152 114.299Z"
@@ -219,17 +219,17 @@ const NotFound = (): JSX.Element => {
<path
d="M162.492 112.623C165.638 112.623 168.189 109.323 168.189 105.252C168.189 101.18 165.638 97.8801 162.492 97.8801C159.346 97.8801 156.796 101.18 156.796 105.252C156.796 109.323 159.346 112.623 162.492 112.623Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M193.487 112.791C196.633 112.791 199.183 109.49 199.183 105.419C199.183 101.348 196.633 98.0476 193.487 98.0476C190.341 98.0476 187.79 101.348 187.79 105.419C187.79 109.49 190.341 112.791 193.487 112.791Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M178.743 133.23C184.48 133.23 189.131 130.53 189.131 127.199C189.131 123.868 184.48 121.168 178.743 121.168C173.007 121.168 168.356 123.868 168.356 127.199C168.356 130.53 173.007 133.23 178.743 133.23Z"
stroke="#3F3D56"
stroke-miterlimit="10"
strokeMiterlimit="10"
/>
<path
d="M181.257 123.748C181.259 124.169 181.101 124.576 180.814 124.884C180.679 125.032 180.514 125.15 180.331 125.232C180.147 125.313 179.949 125.355 179.749 125.356H176.398C175.985 125.342 175.595 125.164 175.312 124.863C175.03 124.562 174.878 124.161 174.89 123.748C174.888 123.421 174.984 123.101 175.165 122.829C175.906 122.725 176.654 122.674 177.403 122.676C178.659 122.671 179.911 122.815 181.133 123.104C181.215 123.309 181.257 123.527 181.257 123.748V123.748Z"

View File

@@ -1,12 +1,18 @@
@import "~antd/dist/antd.dark.css";
.ant-space-item {
margin-right: 0 !important;
}
#chart svg{
#chart svg {
width: 100%;
}
#chart{
#chart {
width: 100%;
}
}
.ant-tabs-tab {
margin: 0 0 0 32px !important;
}
.ant-tabs-nav-list > .ant-tabs-tab:first-child {
margin: 0 !important;
}

View File

@@ -0,0 +1,24 @@
import { Typography } from 'antd';
import React from 'react';
import { ColorContainer, Container } from './styles';
const Legend = ({ text, color }: LegendProps): JSX.Element => {
if (text.length === 0) {
return <></>;
}
return (
<Container>
<ColorContainer color={color}></ColorContainer>
<Typography>{text}</Typography>
</Container>
);
};
interface LegendProps {
text: string;
color: string;
}
export default Legend;

View File

@@ -0,0 +1,20 @@
import styled from 'styled-components';
export const Container = styled.div`
margin-left: 2rem;
margin-right: 2rem;
display: flex;
cursor: pointer;
`;
interface Props {
color: string;
}
export const ColorContainer = styled.div<Props>`
background-color: ${({ color }): string => color};
border-radius: 50%;
width: 20px;
height: 20px;
margin-right: 0.5rem;
`;

View File

@@ -0,0 +1,237 @@
import {
BarController,
BarElement,
CategoryScale,
Chart,
ChartOptions,
ChartType,
Decimation,
Filler,
Legend,
// LegendItem,
LinearScale,
LineController,
LineElement,
PointElement,
ScaleOptions,
SubTitle,
TimeScale,
TimeSeriesScale,
Title,
Tooltip,
} from 'chart.js';
import chartjsAdapter from 'chartjs-adapter-date-fns';
// import { colors } from 'lib/getRandomColor';
// import stringToHTML from 'lib/stringToHTML';
import React, { useCallback, useEffect, useRef } from 'react';
import { useSelector } from 'react-redux';
import { AppState } from 'store/reducers';
import AppReducer from 'types/reducer/app';
// import Legends from './Legend';
// import { LegendsContainer } from './styles';
Chart.register(
LineElement,
PointElement,
LineController,
CategoryScale,
LinearScale,
TimeScale,
TimeSeriesScale,
Decimation,
Filler,
Legend,
Title,
Tooltip,
SubTitle,
BarController,
BarElement,
);
const Graph = ({
data,
type,
title,
isStacked,
label,
xAxisType,
onClickHandler,
}: GraphProps): JSX.Element => {
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
const chartRef = useRef<HTMLCanvasElement>(null);
const currentTheme = isDarkMode ? 'dark' : 'light';
// const [tooltipVisible, setTooltipVisible] = useState<boolean>(false);
const lineChartRef = useRef<Chart>();
const getGridColor = useCallback(() => {
if (currentTheme === undefined) {
return 'rgba(231,233,237,0.1)';
}
if (currentTheme === 'dark') {
return 'rgba(231,233,237,0.1)';
}
return 'rgba(231,233,237,0.8)';
}, [currentTheme]);
const buildChart = useCallback(() => {
if (lineChartRef.current !== undefined) {
lineChartRef.current.destroy();
}
if (chartRef.current !== null) {
const options: ChartOptions = {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false,
},
plugins: {
title: {
display: title === undefined ? false : true,
text: title,
},
legend: {
// just making sure that label is present
display: !(
data.datasets.find((e) => e.label !== undefined) === undefined
),
labels: {
usePointStyle: true,
pointStyle: 'circle',
},
position: 'bottom',
// labels: {
// generateLabels: (chart: Chart): LegendItem[] => {
// return (data.datasets || []).map((e, index) => {
// return {
// text: e.label || '',
// datasetIndex: index,
// };
// });
// },
// pointStyle: 'circle',
// usePointStyle: true,
// },
},
},
layout: {
padding: 0,
},
scales: {
x: {
animate: false,
grid: {
display: true,
color: getGridColor(),
},
labels: label,
adapters: {
date: chartjsAdapter,
},
type: xAxisType,
},
y: {
display: true,
grid: {
display: true,
color: getGridColor(),
},
},
stacked: {
display: isStacked === undefined ? false : 'auto',
},
},
elements: {
line: {
tension: 0,
cubicInterpolationMode: 'monotone',
},
},
onClick: onClickHandler,
};
lineChartRef.current = new Chart(chartRef.current, {
type: type,
data: data,
options,
// plugins: [
// {
// id: 'htmlLegendPlugin',
// afterUpdate: (chart: Chart): void => {
// if (
// chart &&
// chart.options &&
// chart.options.plugins &&
// chart.options.plugins.legend &&
// chart.options.plugins.legend.labels &&
// chart.options.plugins.legend.labels.generateLabels
// ) {
// const labels = chart.options.plugins?.legend?.labels?.generateLabels(
// chart,
// );
// const id = 'htmlLegend';
// const response = document.getElementById(id);
// if (labels && response && response?.childNodes.length === 0) {
// const labelComponent = labels.map((e, index) => {
// return {
// element: Legends({
// text: e.text,
// color: colors[index] || 'white',
// }),
// dataIndex: e.datasetIndex,
// };
// });
// labelComponent.map((e) => {
// const el = stringToHTML(e.element);
// if (el) {
// el.addEventListener('click', () => {
// chart.setDatasetVisibility(
// e.dataIndex,
// !chart.isDatasetVisible(e.dataIndex),
// );
// chart.update();
// });
// response.append(el);
// }
// });
// }
// }
// },
// },
// ],
});
}
}, [chartRef, data, type, title, isStacked, label, xAxisType, getGridColor]);
useEffect(() => {
buildChart();
}, [buildChart]);
return (
<>
<canvas ref={chartRef} />
{/* <LegendsContainer id="htmlLegend" /> */}
</>
);
};
interface GraphProps {
type: ChartType;
data: Chart['data'];
title?: string;
isStacked?: boolean;
label?: string[];
xAxisType?: ScaleOptions['type'];
onClickHandler?: ChartOptions['onClick'];
}
export default Graph;

View File

@@ -0,0 +1,8 @@
import styled from 'styled-components';
export const LegendsContainer = styled.div`
display: flex;
overflow-y: scroll;
margin-right: 1rem;
margin-bottom: 1rem;
`;

View File

@@ -0,0 +1,48 @@
import { Form, Input, InputProps } from 'antd';
import React from 'react';
const InputComponent = ({
value,
type = 'text',
onChangeHandler,
placeholder,
ref,
size = 'small',
onBlurHandler,
onPressEnterHandler,
label,
labelOnTop,
addonBefore,
...props
}: InputComponentProps): JSX.Element => (
<Form.Item labelCol={{ span: labelOnTop ? 24 : 4 }} label={label}>
<Input
placeholder={placeholder}
type={type}
onChange={onChangeHandler}
value={value}
ref={ref}
size={size}
addonBefore={addonBefore}
onBlur={onBlurHandler}
onPressEnter={onPressEnterHandler}
{...props}
/>
</Form.Item>
);
interface InputComponentProps extends InputProps {
value: InputProps['value'];
type?: InputProps['type'];
onChangeHandler?: React.ChangeEventHandler<HTMLInputElement>;
placeholder?: InputProps['placeholder'];
ref?: React.LegacyRef<Input>;
size?: InputProps['size'];
onBlurHandler?: React.FocusEventHandler<HTMLInputElement>;
onPressEnterHandler?: React.KeyboardEventHandler<HTMLInputElement>;
label?: string;
labelOnTop?: boolean;
addonBefore?: React.ReactNode;
}
export default InputComponent;

View File

@@ -0,0 +1,17 @@
import { ComponentType, lazy } from 'react';
function Loadable(importPath: {
(): LoadableProps;
}): React.LazyExoticComponent<LazyComponent> {
const LazyComponent = lazy(() => importPath());
return LazyComponent;
}
type LazyComponent = ComponentType<Record<string, unknown>>;
type LoadableProps = Promise<{
default: LazyComponent;
}>;
export default Loadable;

View File

@@ -1,21 +1,13 @@
import React, { ReactElement } from "react";
import { Modal } from "antd";
import { Modal, ModalProps as Props } from 'antd';
import React, { ReactElement } from 'react';
export const CustomModal = ({
const CustomModal = ({
title,
children,
isModalVisible,
setIsModalVisible,
footer,
closable = true,
}: {
isModalVisible: boolean;
closable?: boolean;
setIsModalVisible: Function;
footer?: any;
title: string;
children: ReactElement;
}) => {
}: ModalProps): JSX.Element => {
return (
<>
<Modal
@@ -29,3 +21,13 @@ export const CustomModal = ({
</>
);
};
interface ModalProps {
isModalVisible: boolean;
closable?: boolean;
footer?: Props['footer'];
title: string;
children: ReactElement;
}
export default CustomModal;

View File

@@ -1,9 +1,8 @@
import React from "react";
import NotFoundImage from 'assets/NotFound';
import ROUTES from 'constants/routes';
import React from 'react';
import { Button, Text, TextContainer, Container } from "./styles";
import NotFoundImage from "Src/assets/NotFound";
import ROUTES from "Src/constants/routes";
import { Button, Container, Text, TextContainer } from './styles';
const NotFound = (): JSX.Element => {
return (

View File

@@ -1,5 +1,5 @@
import styled from "styled-components";
import { Link } from "react-router-dom";
import { Link } from 'react-router-dom';
import styled from 'styled-components';
export const Button = styled(Link)`
height: 100%;

View File

@@ -0,0 +1,93 @@
import { Menu, Switch as ToggleButton, Typography } from 'antd';
import ROUTES from 'constants/routes';
import history from 'lib/history';
import React, { useCallback, useState } from 'react';
import { connect, useSelector } from 'react-redux';
import { NavLink } from 'react-router-dom';
import { useLocation } from 'react-router-dom';
import { bindActionCreators } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import { ToggleDarkMode } from 'store/actions';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import AppReducer from 'types/reducer/app';
import menus from './menuItems';
import { Logo, Sider, ThemeSwitcherWrapper } from './styles';
const SideNav = ({ toggleDarkMode }: Props): JSX.Element => {
const [collapsed, setCollapsed] = useState<boolean>(false);
const { pathname } = useLocation();
const { isDarkMode } = useSelector<AppState, AppReducer>((state) => state.app);
const toggleTheme = useCallback(() => {
const preMode: mode = isDarkMode ? 'lightMode' : 'darkMode';
const postMode: mode = isDarkMode ? 'darkMode' : 'lightMode';
const id: mode = preMode;
const head = document.head;
const link = document.createElement('link');
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = !isDarkMode ? '/css/antd.dark.min.css' : '/css/antd.min.css';
link.media = 'all';
link.id = id;
head.appendChild(link);
link.onload = (): void => {
toggleDarkMode();
const prevNode = document.getElementById(postMode);
prevNode?.remove();
};
}, [toggleDarkMode, isDarkMode]);
const onCollapse = useCallback(() => {
setCollapsed((collapsed) => !collapsed);
}, []);
const onClickHandler = useCallback((to: string) => {
history.push(to);
}, []);
return (
<Sider collapsible collapsed={collapsed} onCollapse={onCollapse} width={200}>
<ThemeSwitcherWrapper>
<ToggleButton checked={isDarkMode} onChange={toggleTheme} />
</ThemeSwitcherWrapper>
<NavLink to="/">
<Logo src={'/signoz.svg'} alt="SigNoz" collapsed={collapsed} />
</NavLink>
<Menu
theme="dark"
defaultSelectedKeys={[ROUTES.APPLICATION]}
selectedKeys={[pathname]}
mode="inline"
>
{menus.map(({ to, Icon, name }) => (
<Menu.Item key={to} icon={<Icon />}>
<div onClick={(): void => onClickHandler(to)}>
<Typography>{name}</Typography>
</div>
</Menu.Item>
))}
</Menu>
</Sider>
);
};
type mode = 'darkMode' | 'lightMode';
interface DispatchProps {
toggleDarkMode: () => void;
}
const mapDispatchToProps = (
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
): DispatchProps => ({
toggleDarkMode: bindActionCreators(ToggleDarkMode, dispatch),
});
type Props = DispatchProps;
export default connect(null, mapDispatchToProps)(SideNav);

View File

@@ -0,0 +1,56 @@
import {
AlignLeftOutlined,
ApiOutlined,
BarChartOutlined,
DashboardFilled,
DeploymentUnitOutlined,
LineChartOutlined,
SettingOutlined,
} from '@ant-design/icons';
import ROUTES from 'constants/routes';
const menus: SidebarMenu[] = [
{
Icon: BarChartOutlined,
to: ROUTES.APPLICATION,
name: 'Metrics',
},
{
Icon: AlignLeftOutlined,
to: ROUTES.TRACES,
name: 'Traces',
},
{
to: ROUTES.SERVICE_MAP,
name: 'Service Map',
Icon: DeploymentUnitOutlined,
},
{
Icon: LineChartOutlined,
to: ROUTES.USAGE_EXPLORER,
name: 'Usage Explorer',
},
{
Icon: SettingOutlined,
to: ROUTES.SETTINGS,
name: 'Settings',
},
{
Icon: ApiOutlined,
to: ROUTES.INSTRUMENTATION,
name: 'Add instrumentation',
},
{
Icon: DashboardFilled,
to: ROUTES.ALL_DASHBOARD,
name: 'Dashboard',
},
];
interface SidebarMenu {
to: string;
name: string;
Icon: typeof ApiOutlined;
}
export default menus;

View File

@@ -0,0 +1,26 @@
import { Layout } from 'antd';
import styled from 'styled-components';
const { Sider: SiderComponent } = Layout;
export const ThemeSwitcherWrapper = styled.div`
display: flex;
justify-content: center;
margin-top: 24px;
margin-bottom: 16px;
`;
export const Logo = styled.img<LogoProps>`
width: 100px;
margin: 5%;
display: ${({ collapsed }): string => (!collapsed ? 'block' : 'none')};
`;
interface LogoProps {
collapsed: boolean;
}
export const Sider = styled(SiderComponent)`
.ant-typography {
color: white;
}
`;

View File

@@ -1,42 +0,0 @@
import React from 'react';
import { Spin } from 'antd';
import styled from "styled-components";
import { LoadingOutlined } from '@ant-design/icons';
const antIcon = <LoadingOutlined style={{ fontSize: 24 }} spin />;
const SpinerStyle = styled.div`
position: fixed;
z-index: 999;
height: 4em;
// width: 4em;
overflow: visible;
margin: auto;
top: 0;
left: 50%;
bottom: 0;
right: 0;
`;
export const CustomSpinner = ({
size,
tip,
}:{
size:string,
tip:string,
})=>{
return(
<>
<SpinerStyle>
<Spin size={size} tip={tip} indicator={antIcon}/>
</SpinerStyle>
</>
)
}
export const DefaultSpinner = ()=>{
return(
<>
<Spin indicator={antIcon}/>
</>
)
}

View File

@@ -0,0 +1,19 @@
import { LoadingOutlined } from '@ant-design/icons';
import { Spin, SpinProps } from 'antd';
import React from 'react';
import { SpinerStyle } from './styles';
const Spinner = ({ size, tip, height }: SpinnerProps): JSX.Element => (
<SpinerStyle height={height}>
<Spin spinning size={size} tip={tip} indicator={<LoadingOutlined spin />} />
</SpinerStyle>
);
interface SpinnerProps {
size?: SpinProps['size'];
tip?: SpinProps['tip'];
height?: React.CSSProperties['height'];
}
export default Spinner;

View File

@@ -0,0 +1,16 @@
import React from 'react';
import styled from 'styled-components';
interface Props {
height: React.CSSProperties['height'];
}
export const SpinerStyle = styled.div<Props>`
z-index: 999;
overflow: visible;
margin: auto;
display: flex;
justify-content: center;
align-items: center;
height: ${({ height = '100vh' }) => height};
`;

View File

@@ -0,0 +1,52 @@
import { Button, Dropdown, Menu, Typography } from 'antd';
import timeItems, {
timePreferance,
timePreferenceType,
} from 'container/NewWidget/RightContainer/timeItems';
import React, { useCallback } from 'react';
import { TextContainer } from './styles';
const TimePreference = ({
setSelectedTime,
selectedTime,
}: TimePreferenceDropDownProps): JSX.Element => {
const timeMenuItemOnChangeHandler = useCallback(
(event: TimeMenuItemOnChangeHandlerEvent) => {
const selectedTime = timeItems.find((e) => e.enum === event.key);
if (selectedTime !== undefined) {
setSelectedTime(selectedTime);
}
},
[setSelectedTime],
);
return (
<TextContainer noButtonMargin>
<Dropdown
overlay={
<Menu>
{timeItems.map((item) => (
<Menu.Item onClick={timeMenuItemOnChangeHandler} key={item.enum}>
<Typography>{item.name}</Typography>
</Menu.Item>
))}
</Menu>
}
>
<Button>{selectedTime.name}</Button>
</Dropdown>
</TextContainer>
);
};
interface TimeMenuItemOnChangeHandlerEvent {
key: timePreferenceType | string;
}
interface TimePreferenceDropDownProps {
setSelectedTime: React.Dispatch<React.SetStateAction<timePreferance>>;
selectedTime: timePreferance;
}
export default TimePreference;

View File

@@ -0,0 +1,14 @@
import styled from 'styled-components';
interface TextContainerProps {
noButtonMargin?: boolean;
}
export const TextContainer = styled.div<TextContainerProps>`
display: flex;
> button {
margin-left: ${({ noButtonMargin }): string => {
return noButtonMargin ? '0' : '0.5rem';
}}
`;

View File

@@ -0,0 +1,13 @@
import React from 'react';
import { Value } from './styles';
const ValueGraph = ({ value }: ValueGraphProps): JSX.Element => (
<Value>{value}</Value>
);
interface ValueGraphProps {
value: string;
}
export default ValueGraph;

View File

@@ -0,0 +1,6 @@
import { Typography } from 'antd';
import styled from 'styled-components';
export const Value = styled(Typography)`
font-size: 3rem;
`;

View File

@@ -1,7 +1,7 @@
import ROUTES from "./routes";
import ROUTES from './routes';
export const WITHOUT_SESSION_PATH = ["/redirect"];
export const WITHOUT_SESSION_PATH = ['/redirect'];
export const AUTH0_REDIRECT_PATH = "/redirect";
export const AUTH0_REDIRECT_PATH = '/redirect';
export const DEFAULT_AUTH0_APP_REDIRECTION_PATH = ROUTES.APPLICATION;

View File

@@ -1 +1 @@
export const IS_LOGGED_IN = "isLoggedIn";
export const IS_LOGGED_IN = 'isLoggedIn';

View File

@@ -1,3 +1,3 @@
export const ENVIRONMENT = {
baseURL: process?.env?.FRONTEND_API_ENDPOINT || "",
baseURL: process?.env?.FRONTEND_API_ENDPOINT || '',
};

View File

@@ -1,3 +1,3 @@
export enum LOCAL_STORAGE {
METRICS_TIME_IN_DURATION = "metricsTimeDurations",
METRICS_TIME_IN_DURATION = 'metricsTimeDurations',
}

View File

@@ -1 +1 @@
export const SKIP_ONBOARDING = "skip_onboarding";
export const SKIP_ONBOARDING = 'skip_onboarding';

View File

@@ -1,9 +1,9 @@
export enum METRICS_PAGE_QUERY_PARAM {
interval = "interval",
startTime = "startTime",
endTime = "endTime",
service = "service",
error = "error",
operation = "operation",
kind = "kind"
interval = 'interval',
startTime = 'startTime',
endTime = 'endTime',
service = 'service',
error = 'error',
operation = 'operation',
kind = 'kind',
}

View File

@@ -1,13 +1,16 @@
const ROUTES = {
SIGN_UP: "/signup",
SERVICE_METRICS: "/application/:servicename",
SERVICE_MAP: "/service-map",
TRACES: "/traces",
TRACE_GRAPH: "/traces/:id",
SETTINGS: "/settings",
INSTRUMENTATION: "/add-instrumentation",
USAGE_EXPLORER: "/usage-explorer",
APPLICATION: "/application",
SIGN_UP: '/signup',
SERVICE_METRICS: '/application/:servicename',
SERVICE_MAP: '/service-map',
TRACES: '/traces',
TRACE_GRAPH: '/traces/:id',
SETTINGS: '/settings',
INSTRUMENTATION: '/add-instrumentation',
USAGE_EXPLORER: '/usage-explorer',
APPLICATION: '/application',
ALL_DASHBOARD: '/dashboard',
DASHBOARD: '/dashboard/:dashboardId',
DASHBOARD_WIDGET: '/dashboard/:dashboardId/:widgetId',
};
export default ROUTES;

View File

@@ -0,0 +1,71 @@
import { Typography } from 'antd';
import { ChartData } from 'chart.js';
import Graph from 'components/Graph';
import ValueGraph from 'components/ValueGraph';
import { GRAPH_TYPES } from 'container/NewDashboard/ComponentsSlider';
import history from 'lib/history';
import React from 'react';
import { TitleContainer, ValueContainer } from './styles';
const GridGraphComponent = ({
GRAPH_TYPES,
data,
title,
opacity,
isStacked,
}: GridGraphComponentProps): JSX.Element | null => {
const location = history.location.pathname;
const isDashboardPage = location.split('/').length === 3;
if (GRAPH_TYPES === 'TIME_SERIES') {
return (
<Graph
{...{
data,
title,
type: 'line',
isStacked,
opacity,
xAxisType: 'time',
}}
/>
);
}
if (GRAPH_TYPES === 'VALUE') {
const value = (((data.datasets[0] || []).data || [])[0] || 0) as number;
if (data.datasets.length === 0) {
return (
<ValueContainer isDashboardPage={isDashboardPage}>
<Typography>No Data</Typography>
</ValueContainer>
);
}
return (
<>
<TitleContainer isDashboardPage={isDashboardPage}>
<Typography>{title}</Typography>
</TitleContainer>
<ValueContainer isDashboardPage={isDashboardPage}>
<ValueGraph value={value.toString()} />
</ValueContainer>
</>
);
}
return null;
};
export interface GridGraphComponentProps {
GRAPH_TYPES: GRAPH_TYPES;
data: ChartData;
title?: string;
opacity?: string;
isStacked?: boolean;
}
export default GridGraphComponent;

View File

@@ -0,0 +1,19 @@
import styled from 'styled-components';
interface Props {
isDashboardPage: boolean;
}
export const ValueContainer = styled.div<Props>`
height: ${({ isDashboardPage }): string =>
isDashboardPage ? '100%' : '55vh'};
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
`;
export const TitleContainer = styled.div<Props>`
text-align: center;
padding-top: ${({ isDashboardPage }): string =>
!isDashboardPage ? '1rem' : '0rem'};
`;

View File

@@ -0,0 +1,55 @@
import { PlusOutlined } from '@ant-design/icons';
import { Typography } from 'antd';
import React, { useCallback } from 'react';
import { connect, useSelector } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';
import { ThunkDispatch } from 'redux-thunk';
import {
ToggleAddWidget,
ToggleAddWidgetProps,
} from 'store/actions/dashboard/toggleAddWidget';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import DashboardReducer from 'types/reducer/dashboards';
import { Button, Container } from './styles';
const AddWidget = ({ toggleAddWidget }: Props): JSX.Element => {
const { isAddWidget } = useSelector<AppState, DashboardReducer>(
(state) => state.dashboards,
);
const onToggleHandler = useCallback(() => {
toggleAddWidget(true);
}, [toggleAddWidget]);
return (
<Container>
{!isAddWidget ? (
<>
<Button onClick={onToggleHandler} icon={<PlusOutlined />}>
Add Widgets
</Button>
</>
) : (
<Typography>Click a widget icon to add it here</Typography>
)}
</Container>
);
};
interface DispatchProps {
toggleAddWidget: (
props: ToggleAddWidgetProps,
) => (dispatch: Dispatch<AppActions>) => void;
}
const mapDispatchToProps = (
dispatch: ThunkDispatch<unknown, unknown, AppActions>,
): DispatchProps => ({
toggleAddWidget: bindActionCreators(ToggleAddWidget, dispatch),
});
type Props = DispatchProps;
export default connect(null, mapDispatchToProps)(AddWidget);

View File

@@ -0,0 +1,18 @@
import { Button as ButtonComponent } from 'antd';
import styled from 'styled-components';
export const Button = styled(ButtonComponent)`
&&& {
display: flex;
justify-content: center;
align-items: center;
border: none;
}
`;
export const Container = styled.div`
display: flex;
justify-content: center;
align-items: center;
height: 100%;
`;

View File

@@ -0,0 +1,40 @@
import {
DeleteOutlined,
EditFilled,
FullscreenOutlined,
} from '@ant-design/icons';
import React, { useCallback } from 'react';
import { useHistory, useLocation } from 'react-router';
import { Widgets } from 'types/api/dashboard/getAll';
import { Container } from './styles';
const Bar = ({
widget,
onViewFullScreenHandler,
onDeleteHandler,
}: BarProps): JSX.Element => {
const { push } = useHistory();
const { pathname } = useLocation();
const onEditHandler = useCallback(() => {
const widgetId = widget.id;
push(`${pathname}/new?widgetId=${widgetId}&graphType=${widget.panelTypes}`);
}, [push, pathname, widget]);
return (
<Container>
<FullscreenOutlined onClick={onViewFullScreenHandler} />
<EditFilled onClick={onEditHandler} />
<DeleteOutlined onClick={onDeleteHandler} />
</Container>
);
};
interface BarProps {
widget: Widgets;
onViewFullScreenHandler: () => void;
onDeleteHandler: () => void;
}
export default Bar;

Some files were not shown because too many files have changed in this diff Show More