Compare commits

...

165 Commits

Author SHA1 Message Date
Srikanth Chekuri
a4e0d9c7df chore: pin SigNoz version to v0.30.0 2023-09-27 23:04:02 +05:30
Srikanth Chekuri
4076cd9847 fix: alert eval for "="/"!=" combination with "at least once"/"all the times" (#3613) 2023-09-27 22:34:49 +05:30
Yunus M
e3f4fc2967 feat: fix use raw-loader instead of mdx-js/loader (#3640) 2023-09-27 14:26:51 +00:00
Palash Gupta
bccefc6a10 chore: error details stack trace height is updated (#3639)
* chore: error details stack trace height is updated

* chore: style is updated

---------

Co-authored-by: Rajat Dabade <rajat@signoz.io>
2023-09-27 17:50:10 +05:30
Palash Gupta
821471f4ab feat(query-builder): add limit, order by and having clause to formula (#3623)
* feat: query builder formula is updated

* feat: formula is updated for having and limit

* feat: orderBy is updated

* feat: formula is added

* chore: add query-service support for formula limit and order by

* feat: enable more filters is displayed when all data source is metrics

* chore: feedback is updated

* chore: feedback is updated

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
Co-authored-by: Rajat Dabade <rajat@signoz.io>
2023-09-27 17:34:47 +05:30
Ankit Anand
1e242b6d06 feat: updated infra docs (#3637)
* feat: updated infra docs

* feat: add selection for infra metrics types and render selected metrics type docs

* feat: qc updates

* feat: fix header alignment issue

---------

Co-authored-by: ankit01-oss <>
Co-authored-by: Yunus A M <myounis.ar@live.com>
2023-09-27 17:19:20 +05:30
Prashant Shahi
4ca5176836 ci(frontend-ee): 👷 add clarity project ID to env (#3635) 2023-09-27 08:24:55 +00:00
Yunus M
7f397d529b Onboarding Docs - Copy to clipboard (#3634)
* feat: enable copy-to-clipboard to onboarding docs snippets

* feat: remove commented code & <br></br> from md docs

* feat: remove react-copy-to-clipboard lib and fix type issues

* feat: markdown renderer - pre - remove any with reactnode
2023-09-27 13:20:48 +05:30
Yunus M
656f354fdc feat: ignore prettier formatting for build, coverage and md files (#3628) 2023-09-26 15:55:36 +00:00
Ankit Anand
4cc3ce224c docs: update onboarding docs (#3627)
Co-authored-by: ankit01-oss <>
2023-09-26 20:38:37 +05:30
Nityananda Gohain
a4a285c074 feat: add support for freehand json query (#3625)
* feat: freehand json search

* feat: support for freehand json query

* fix: minor updates

* fix: minor refactor
2023-09-26 20:10:39 +05:30
Yunus M
a8f8580606 feat: add account creation page events (#3619) 2023-09-26 13:21:59 +00:00
Yunus M
e24918044e feat: add clarity ms (#3620) 2023-09-26 13:06:53 +05:30
Palash Gupta
28d346eafb feat: default options is updated (#3607)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-09-26 00:23:27 +05:30
Rajat Dabade
cbd2f4c643 [Fix]: select dropdown for onboarding flow (#3618)
* fix: select dropdown for onboarding flow

* refactor: dropdown scroll issue for widget header

* refactor: dropdown scroll issue for topnav

* refactor: fix the dropdown scroll issue

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-25 19:39:10 +05:30
Palash Gupta
fcedc9e445 feat: severityText is added (#3606) 2023-09-25 12:17:26 +00:00
Yunus M
d2d3c4bb36 feat: make identity call if user is logs in for first time or if identity call was not registered (#3612) 2023-09-24 09:35:11 +00:00
Eng Zer Jun
dc4acc0730 refactor(query-service): remove redundant nil check (#3614)
From the Go specification [1]:

  "1. For a nil slice, the number of iterations is 0."
  "3. If the map is nil, the number of iterations is 0."

Therefore, an additional nil check for before the loop is unnecessary.

[1]: https://go.dev/ref/spec#For_range

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2023-09-24 14:42:17 +05:30
Srikanth Chekuri
043e5ca880 fix: skip first record only for rate metrics (#3609) 2023-09-22 15:43:21 +05:30
Rajat Dabade
5c437dd8f9 fix: the scroll issue and name issue in save view (#3604) 2023-09-21 19:49:43 +05:30
Palash Gupta
31b898b2c6 fix: active menu logic is updated (#3602) 2023-09-21 15:58:41 +05:30
Raj Kamal Singh
8bfb0b5088 QueryBuilder filters for log pipelines (#3587) 2023-09-21 05:11:48 +00:00
Yunus M
30e0924bfb feat: onboarding flow - add analytics - update webpack config (#3599) 2023-09-20 23:37:59 +05:30
Yunus M
ccada08db5 feat: onboarding flow - add analytics - update webpack config (#3597) 2023-09-20 15:20:08 +00:00
Prashant Shahi
6654dd2672 ci(frontend): 👷 update CI job for frontend EE build (#3596)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-09-20 19:42:56 +05:30
Yunus M
4b0a7cc4d3 feat: onboarding flow - add analytics (#3594) 2023-09-20 16:00:51 +05:30
Rajat Dabade
04acc49154 refactor: polished the log UI (#3591) 2023-09-20 15:31:31 +05:30
Raj Kamal Singh
3db8a25eb9 Add support in query service for querybuilder filterset based log pipelines (#3560)
* chore: use v3.Filterset as pipeline filters in logparsing pipelines integration tests

* chore: get logparsing integration tests passing with filterset based pipeline

* chore: get all other breaking tests passing

* chore: move models.logparsingpipeline to logparsingpipeline.model

* chore: implement Valuer and Scanner interfaces for v3.FilterSet
2023-09-20 12:39:34 +05:30
Yunus M
8324d010ae fix: frontend/Dockerfile to reduce vulnerabilities (#3589)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-ALPINE317-LIBWEBP-5902239

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-09-20 11:32:17 +05:30
Srikanth Chekuri
735ab8e118 fix: add missed variable substitution for promql querires (#3584) 2023-09-19 17:49:11 +05:30
Palash Gupta
b0861f4fe0 feat: old logs explorer is now deprecated (#3576)
* feat: old logs explorer is now deprecated

* chore: logs to trace is updated

* chore: min and max time is added

* chore: new explorer cta button is updated
2023-09-19 15:35:16 +05:30
Yunus M
61b6779a31 feat: integrate segment and track page views (#3586) 2023-09-19 15:09:28 +05:30
Srikanth Chekuri
416a058eab Query range caching (#2142) 2023-09-17 10:40:45 +05:30
Palash Gupta
4227faa6b5 feat: limit & order by is enabled in the metrics query builder (#3566)
* feat: limit filter is enabled in the metrics filters

* chore: orderBy is enabled for metrics data source

* chore: fix table type limit and order by

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-09-16 18:32:51 +05:30
Rajat Dabade
9d3c4598ac refactor: aggreated attributes and resources from json (#3558) 2023-09-15 18:13:25 +05:30
Prashant Shahi
6aba701cca Merge pull request #3565 from SigNoz/release/v0.29.1
Release/v0.29.1
2023-09-15 14:20:11 +05:30
Prashant Shahi
cf1b0c2f24 chore(release): 📌 pin version: SigNoz 0.29.1
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-09-15 13:33:55 +05:30
Rajat Dabade
231c2fd281 [Fix]: show dashboard according to Id (#3564)
* fix: show dashboard according to id

* chore: removed log
2023-09-15 12:56:59 +05:30
Palash Gupta
e3f17b5420 chore: tree is expanded by default (#3563) 2023-09-15 10:38:07 +05:30
Palash Gupta
56f1f71461 feat: tree is updated to show different node values instead of editor (#2696)
* feat: tree is updated to show different node values instead of editor

* chore: table view is updated

* [Refactoring]: Seperate title and menu to another component  (#3531)

* refactor: separated the title renderer

* refactor: separated styles

* refactor: seperate types

* refactor: instead of key showing value if array (#3532)

* refactor: instead of key showing value if array

* feat: added filter for array and also nodekey

* refactor: made common check for value is array

* refactor: changed the key to value for arrays

* chore: getData types is updated

* chore: getDataTypes function types is updated

* refactor: connection to querybuilder (#3535)

Co-authored-by: Palash Gupta <palashgdev@gmail.com>

* chore: operator is updated

* fix: build is fixed

* fix: build is fixed

* chore: operator is updated

* chore: operator is updated

* chore: parsing is updated

* chore: key is updated

* Refactor: Log parsing updates (#3542)

* refactor: updated nodekey

* refactor: removed pasred data

* refactor: parentIsArray check

* chore: added the support for the bool

* [Refactor]: handle nested object case (#3545)

* refactor: updated nodekey

* refactor: removed pasred data

* refactor: parentIsArray check

* refactor: handled nested array inside object case

* fix: float issue parsing

* chore: operator is updated

* chore: title is updated

* chore: title is updated

* fix: update tagRegexp

* fix: maintain single source of DataTypes

* chore: operator is updated

* fix: fixed due to merge conflicts

---------

Co-authored-by: Rajat Dabade <rajat@signoz.io>
Co-authored-by: Yunus A M <myounis.ar@live.com>
2023-09-15 10:21:42 +05:30
Ankit Nayan
72f4578152 Merge branch 'main' into develop 2023-09-14 18:35:18 +05:30
Prashant Shahi
9c8125ffc1 Merge pull request #3549 from SigNoz/release/v0.29.0
Release/v0.29.0
2023-09-14 18:05:19 +05:30
Rajat Dabade
85d7752350 [Refactor]: added tag for data type and type of logs (#3554) 2023-09-14 17:12:49 +05:30
Prashant Shahi
63ba9fb5e0 Merge branch 'develop' into release/v0.29.0 2023-09-14 13:06:17 +05:30
Ben Walding
14a59a26b2 Fix typo - data => data (#3551)
Co-authored-by: Prashant Shahi <prashant@signoz.io>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-14 12:48:16 +05:30
Prashant Shahi
178c154263 Merge branch 'develop' into release/v0.29.0 2023-09-14 12:39:44 +05:30
Prashant Shahi
122488c2c1 ci(frontend): 👷 CI job for frontend EE build (#3552)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-09-14 11:36:39 +05:30
Prashant Shahi
ad3fbd7599 chore(release): 📌 pin version: SigNoz 0.29.0
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-09-14 02:58:31 +05:30
Prashant Shahi
1ad1ca5385 chore: 📌 pin versions: SigNoz OtelCollector 0.76.7, Alertmanager 0.23.4
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-09-14 02:57:37 +05:30
Ankit Anand
2fc82ffa59 docs: updated APM docs (#3548)
* docs: updated APM docs

* feat: signoz cloud - update logs management and infra monitoring docs

---------

Co-authored-by: Yunus A M <myounis.ar@live.com>
2023-09-14 01:43:49 +05:30
Nityananda Gohain
ed809474d6 feat: json filter bool support (#3544)
* feat: json filter bool support

* fix: update json filter for bool
2023-09-13 21:00:40 +05:30
Dhawal Sanghvi
a8c4a91001 Merge pull request #3543 from SigNoz/clickhouse/reader/fix.removeUnnecessaryBraces
fix: remove unnecessary braces in clickhouse reader
2023-09-13 15:52:32 +05:30
dhawal1248
1ffb1b4a5d fix: remove unnecessary braces in clickhouse reader 2023-09-13 15:26:27 +05:30
Yunus M
9a00998930 feat: signoz cloud - show cloud onboarding docs only when the domain is signoz.cloud (#3540)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-13 15:00:14 +05:30
Dhawal Sanghvi
c60f612e0e Merge pull request #3541 from SigNoz/chore.preferDeltaTemporalityByDefault
prefer delta by default - fix indent
2023-09-13 14:45:23 +05:30
Dhawal Sanghvi
7839134532 Merge branch 'develop' into chore.preferDeltaTemporalityByDefault 2023-09-13 14:35:37 +05:30
dhawal1248
714a2ef4fd fix: fix indent 2023-09-13 14:34:07 +05:30
Dhawal Sanghvi
7f98a65022 Merge pull request #3533 from SigNoz/chore.preferDeltaTemporalityByDefault
chore: prefer delta temporality by default
2023-09-13 14:18:59 +05:30
Dhawal Sanghvi
616e3af18f Merge branch 'develop' into chore.preferDeltaTemporalityByDefault 2023-09-13 14:01:30 +05:30
Nityananda Gohain
17ae197bc3 feat: support for filtering json inside body (#3534)
* feat: support for json query on body

* feat: json filter parser updated for scalar values
2023-09-13 13:46:06 +05:30
Prashant Shahi
27cda7a437 chore(frontend): load dotenv for webpack prod and related changes (#3537)
* chore(frontend): 🔧 update dotenv and add example.env

* chore(frontend): 🙈 update .gitignore and .dockerignore

---------

Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-09-13 12:26:16 +05:30
Yunus M
54a2309d8f feat: signoz cloud - update polling logic to fetch latest services (#3538) 2023-09-13 11:15:24 +05:30
Prashant Shahi
748c78e9c3 Merge branch 'develop' into chore.preferDeltaTemporalityByDefault 2023-09-12 19:49:15 +05:30
Dhawal Sanghvi
7ae0326f61 Update pkg/query-service/README.md
Co-authored-by: Prashant Shahi <prashant@signoz.io>
2023-09-12 19:46:23 +05:30
Yunus M
c15240abab Signoz cloud onboarding v1 (#3525)
* Signoz Cloud - Onboarding Flow - Getting Started page

* Signoz Cloud - Onboarding Flow - Java lang setup flow

* Signoz Cloud - Onboarding Flow - Wireup other lang docs for APM and create empty base component for other modules

* Signoz Cloud - Onboarding Flow - remove try signoz cloud button, Update code background

* Signoz Cloud - Onboarding Flow - Wire up all docs and modules

* Signoz Cloud - Onboarding Flow - Integrate Intercom and other minor fixes

* Signoz Cloud - Onboarding Flow - Logs Management - Update Connection Status component

* Signoz Cloud - Onboarding Flow - Logs Management - Update light mode styles

* Signoz Cloud - Onboarding Flow - Logs Management - Update Logs

* Signoz Cloud - Update yarn.lock

* Signoz Cloud - Delete Progress Steps component

* Signoz Cloud - Poll for connection status, created common Header component

* Signoz Cloud - Add polling to check connection status, update components to use common Header component

* Signoz Cloud - Render onboarding only if feature flag is enabled

* Signoz Cloud - Configure Logs Management Steps

* Signoz Cloud - Update intercom snippet and set max width for onboarding flow container to 1440px

* Signoz Cloud - Use andD card component for displaying modules

* chore: first clean up

* Signoz Cloud - Use ONBOARDING and CHAT_SUPPORT FF

* Signoz Cloud - Update version check logic and fix minor css issues

* fix: feature flag is updated

* chore: docusaurus is removed

* chore: docusaurus is removed

* feat: signoz cloud - fix typecheck errors

* feat: signoz cloud - enable chat support based on FF

* feat: signoz cloud - fix type errors

* feat: signoz cloud - fix type errors

* feat: signoz cloud - update webpack config rules

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-12 19:20:14 +05:30
dhawal1248
2fe9e53766 chore: prefer delta temporality by default 2023-09-12 16:34:28 +05:30
Vishal Sharma
7209ac0007 fix: login/precheck api in non-ee variant (#3516)
* fix: login/precheck api in non-ee variant

* fix: add return statement

* fix: make skip config empty

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-09-12 12:53:46 +05:30
Rajat Dabade
96adc7f61c Save view PRD design changes. (#3480)
* refactor: search in dropdown

* refactor: name of the view to i18

* refactor: make the use of useForm from antd

* refactor: moved QuerySearchParamNames into save view module

* refactor: reset to query build when click on explorer link

* refactor: save view prd design changes

* refactor: reverted resetQuery in querybuilder

* refactor: queryParams to query.ts in querybuilder constants

* fix: redirect with saved view is updated

* refactor: removed useffect logic for updating query

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-12 11:57:33 +05:30
Vishal Sharma
7b4fd55aeb feat: add new ff for ee plan (#3524) 2023-09-12 11:39:28 +05:30
Palash Gupta
86c34bd87d fix: code scanning issues is fixed (#3522) 2023-09-11 14:02:38 +05:30
Himanshu Gupta
41f7a7993d feat: all dashboard is migrated to useQuery and action is removed (#3384)
* feat: all dashboard is migrated to useQuery and action is removed

* chore: delete functionality is updated

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-11 10:51:10 +05:30
Raj Kamal Singh
dfd94f67bd chore: return 400 http status on pipeline validation error (#3472)
* chore: add integration test for log parsing pipelines validation

* chore: add helpers for creating unauthorized, unavailable & not found api errors

* chore: return *model.APIError from logpipeline and agentConf functions

* chore: some cleanup

* chore: some more cleanup

* chore: one more round of cleanups
2023-09-10 16:48:29 +05:30
Palash Gupta
052c32ce78 fix: live logs table color for light mode is fixed (#3517) 2023-09-10 11:43:17 +05:30
Rajat Dabade
004f10e73b Enhancement for Save View PRD. (#3471)
* refactor: search in dropdown

* refactor: name of the view to i18

* refactor: make the use of useForm from antd

* refactor: moved QuerySearchParamNames into save view module

* refactor: reset to query build when click on explorer link

* refactor: reverted resetQuery in querybuilder

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-09-08 20:36:21 +05:30
Rajat Dabade
f17608fa10 fix: unvalidated dynamic method call (#3515) 2023-09-08 13:52:30 +05:30
Kanishka Chowdhury
8de8a8a86a fix(FE/Logs): fix all logs not visible on scrolling (#3512)
* fix(FE/Logs): fix all logs not visible on scrolling

* fix(FE/logs): fix scroll behaviour in live logs

* refactor(FE/logs): replaced StyledComponents with scss

---------

Co-authored-by: Rajat Dabade <rajat@signoz.io>
2023-09-08 12:11:07 +05:30
Srikanth Chekuri
0486721b35 chore: update dependencies (#3514) 2023-09-07 19:49:29 +05:30
Palash Gupta
14bbc609d8 feat: triggered alerts is migrated to useQuery (#2814)
* feat: alerts is migrated to useQuery

* chore: review comments is updated

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
Co-authored-by: Rajat Dabade <rajat@signoz.io>
2023-09-07 18:18:26 +05:30
Raj Kamal Singh
f450d71a25 fix: avoid pipeline builder panic when first op is disabled (#3500)
* fix: avoid pipeline builder panic if first op is disabled

* chore: use pipeline builder test to trigger getOperator panic

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2023-09-07 17:47:09 +05:30
Srikanth Chekuri
921fca5e67 fix: do not add redundant [] for array (#3484) 2023-09-07 15:20:14 +05:30
Rajat Dabade
1f7e70fa16 fix: unvalidated dynamic method call (#3508)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-07 11:08:55 +05:30
Palash Gupta
3ca048bc76 fix: tagRef is updated (#3502)
Co-authored-by: Rajat Dabade <rajat@signoz.io>
2023-09-07 10:55:25 +05:30
Nityananda Gohain
37e36626ab feat: initail version of QB to expr (#3412)
* feat: initail version of QB to expr

* chore: check final expression is valid or not

* feat: minor formatting changes

* Update pkg/query-service/queryBuilderToExpr/queryBuilderToExpr_test.go

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>

* fix: go.mod updated

* fix: go.mod updated

* fix: go.mod updated

* fix: unwanted changes in go.mod reverted

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-09-07 10:00:22 +05:30
Yunus M
07808a8664 chore(FE): update webpack, add sass, remove wydr (#3503) 2023-09-07 09:21:32 +05:30
Kanishka Chowdhury
16d490fbe3 chore(FE): reduce main.js chunk size (#3486)
* refactor(FE/routes): lazy load DashboardWidget route

* refactor(FE/Styled): update antd import

* chore(FE): remove majority of import * and import only necessary items

* fix(FE): fix missing papa parse import

* fix(FE): fix missing papa parse import

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-06 19:00:00 +05:30
Kanishka Chowdhury
b1cee71621 fix(FE): encode URL query params (#3501) 2023-09-06 18:45:32 +05:30
Ankit Nayan
e55a4da2bc fix: frontend/package.json & frontend/yarn.lock to reduce vulnerabilities (#3499) 2023-09-06 17:48:56 +05:30
Rajat Dabade
0fa0e64697 fix: storage of sensitive information in build artifact (#3491)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-06 17:20:43 +05:30
Ankit Nayan
c54fffb51d fix: ee/query-service/Dockerfile to reduce vulnerabilities (#3488)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-ALPINE37-MUSL-458286
- https://snyk.io/vuln/SNYK-ALPINE37-MUSL-458286

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-09-06 16:39:28 +05:30
Ankit Nayan
294b6966bf fix: pkg/query-service/Dockerfile to reduce vulnerabilities (#3492)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-ALPINE37-MUSL-458286
- https://snyk.io/vuln/SNYK-ALPINE37-MUSL-458286

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-09-06 16:38:52 +05:30
Kanishka Chowdhury
9aa72f847c style(FE/layout): Fix app scroll behaviour and sidenav footer section inconsistency (#3426) 2023-09-06 13:00:20 +05:30
Kanishka Chowdhury
32a55f3c4f fix(FE/logs): show relevant error message on deleting/adding selected/interesting fields (#3437)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-05 21:04:28 +05:30
Yevhen Shevchenko
8e6a7f13a1 fix: clear query builder staged query (#3479) 2023-09-05 20:20:26 +05:30
Srikanth Chekuri
89e8fb715c chore: bump SigNoz/prometheus (#3410) 2023-09-05 18:17:32 +05:30
Yevhen Shevchenko
21de4bbd1b chore: update package resolution (#3477) 2023-09-05 14:25:32 +05:30
Palash Gupta
d4cc7c88c3 chore: css-minimizer-webpack-plugin is updated (#3464) 2023-09-05 13:58:31 +05:30
Kanishka Chowdhury
0e9e29e650 chore(FE): upgrade babel-loader to latest (#3476) 2023-09-05 13:13:35 +05:30
Palash Gupta
176725a4b4 fix: threshold value is handled for undefined case (#3473) 2023-09-05 11:54:44 +05:30
Yevhen Shevchenko
88560e7c43 chore: add debug package resolution (#3469) 2023-09-04 21:28:25 +05:30
Yevhen Shevchenko
2538899544 chore: fix update debug dependency (#3465)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-04 19:34:01 +05:30
dependabot[bot]
ae0fc32fe1 chore(deps): bump tough-cookie from 4.1.2 to 4.1.3 in /frontend (#3363)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.1.2...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-04 19:12:30 +05:30
dependabot[bot]
859875667a chore(deps): bump semver from 5.7.1 to 5.7.2 in /frontend (#3357)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-04 18:17:49 +05:30
Yevhen Shevchenko
674dee5a1b chore: upgrade d3-color dependency (#3461)
* chore: upgrade d3-color dependency

* fix: upgrade version

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-04 18:06:51 +05:30
dependabot[bot]
0318e53fdc chore(deps): bump @adobe/css-tools from 4.2.0 to 4.3.1 in /frontend (#3458)
Bumps [@adobe/css-tools](https://github.com/adobe/css-tools) from 4.2.0 to 4.3.1.
- [Changelog](https://github.com/adobe/css-tools/blob/main/History.md)
- [Commits](https://github.com/adobe/css-tools/commits)

---
updated-dependencies:
- dependency-name: "@adobe/css-tools"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-04 14:58:36 +05:30
dependabot[bot]
b768840d36 chore(deps): bump word-wrap from 1.2.3 to 1.2.5 in /frontend (#3459)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.5.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.5)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-04 14:41:49 +05:30
Yevhen Shevchenko
ccc8be009c chore: upgrade debug dependency (#3462)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-09-04 14:32:12 +05:30
Ankit Nayan
59549c36de Merge branch 'main' into develop 2023-09-04 12:26:12 +05:30
Srikanth Chekuri
aeee8b4cb2 Merge pull request #3463 from SigNoz/release/v0.28.0
Release/v0.28.0
2023-09-04 11:51:19 +05:30
Raj Kamal Singh
03acc33888 chore: log parsing pipelines happy path integration test (#3424)
* chore: get started with logparsingpipeline happy path integration test

* chore: log pipelines happy path: assert opampclient receives expected otel config processors for log pipelines.

* chore: logparsing pipeline happy path: validate deployment status update

* chore: logparsing pipeline happy path: validate posting pipelines update

* chore: some cleanup

* chore: some more cleanup

* chore: some more cleanup

* fix: address review comments

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2023-09-02 20:01:03 +05:30
Srikanth Chekuri
b2a943769b chore: pin SigNoz version 0.28.0, alert manager 0.23.3 2023-09-01 16:01:07 +05:30
Yevhen Shevchenko
1501ed0c5d chore: update typescript css modules package (#3457) 2023-08-31 21:03:53 +05:30
Srikanth Chekuri
218eb5379e feat: opsgenie integration (#3429) 2023-08-31 20:50:55 +05:30
Nityananda Gohain
e596dd77bd fix: live tail query formatting fix (#3453)
* fix: live tail query formatting fix

* fix: minor fixes in formatter

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-08-30 20:38:46 +05:30
Rajat Dabade
1138c6e41a Save View for Explorer pages. (#3404)
* feat: save view switch and save view done

* feat: delete view completed

* refactor: moved update logic to utils

* chore: removed unwated commented logic

* refactor: shifted save view logic to utils

* refactor: separated types

* refactor: updated types for save view

* refactor: shifted delete view logic to utils

* refactor: done with share url

* refactor: separated constants

* refactor: separated types

* test: added unit test for explorerCard

* refactor: done with update view

* refactor: added test cases

* chore: updated the file name from index to ExplorerCard

* refactor: moved unit test to test folder and useCallbacks

* chore: changed the variable names

* refactor: updated code review comments

* chore: fix build pipeline

* fix: 404 for query_range because of attribute operator

* refactor: functional review commnet address

* refactor: updatd unit test

* refactor: added delete option beside save view

* refactor: row align middle

* fix: build pipeline

* refactor: updated logic and review comments changes

* refactor: fixed build pipeline

* refactor: used onSuccess and onError for mutation

* refactor: onSuccess and onError for saveView

* refactor: mapping in function with query type

* refactor: updated code review comments

* refactor: updated explorerCard utils

* refactor: removed async

* fix: update state for save view

* refactor: tab according to aggregate operator

* refactor: updated test case

* refactor: updated the loading state of the button

* fix: build pipeline

* fix: share view tab updates

* fix: click on dropdown

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
Co-authored-by: Yunus M <myounis.ar@live.com>
2023-08-30 20:24:16 +05:30
Palash Gupta
15f328eb9e fix: enable modal is fixed when time is changed (#3454) 2023-08-30 19:28:04 +05:30
Neelesh Sharma
01312ec286 fix: back button issue fixed for traces/logs explorer (#3448)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-08-29 20:22:47 +05:30
Yevhen Shevchenko
0574350e6e feat: add list loader and fix action column size (#3440)
* feat: create live logs page and custom top nav

* feat: add live logs where clause

* fix: success button color

* fix: turn back color

* fix: undefined scenario

* feat: get live data

* fix: change color, change number format

* feat: add live logs list

* feat: hide view if error, clear logs

* feat: add condition for disable initial loading

* fix: double request

* fix: render id in the where clause

* fix: render where clause and live list

* fix: last log padding

* fix: list data loading

* fix: no logs text

* fix: logs list size

* fix: small issues

* feat: add list loader and fix action column size

* fix: remove unnecessary file

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
Co-authored-by: Yunus M <myounis.ar@live.com>
2023-08-29 20:06:39 +05:30
Yevhen Shevchenko
7e297dcb75 feat: use prefetched query in live (#3450)
* feat: create live logs page and custom top nav

* feat: add live logs where clause

* fix: success button color

* fix: turn back color

* fix: undefined scenario

* feat: get live data

* fix: change color, change number format

* feat: add live logs list

* feat: hide view if error, clear logs

* feat: add condition for disable initial loading

* fix: double request

* fix: render id in the where clause

* fix: render where clause and live list

* fix: last log padding

* fix: list data loading

* fix: no logs text

* fix: logs list size

* fix: small issues

* feat: use prefetched query in live

* chore: useMemo is updated

* feat: add live logs list (#3341)

* feat: add live logs list

* feat: hide view if error, clear logs

* feat: add condition for disable initial loading

* fix: double request

* fix: render id in the where clause

* fix: render where clause and live list

* fix: last log padding

* fix: list data loading

* fix: no logs text

* fix: logs list size

* fix: small issues

* fix: render view with memo

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>

* chore: alignment is updated

* fix: action column size

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-08-29 19:39:40 +05:30
Yevhen Shevchenko
d184486978 feat: create live logs page and custom top nav (#3315)
* feat: create live logs page and custom top nav

* fix: success button color

* fix: turn back color

* feat: add live logs where clause (#3325)

* feat: add live logs where clause

* fix: undefined scenario

* feat: get live data (#3337)

* feat: get live data

* fix: change color, change number format

* chore: useMemo is updated

* feat: add live logs list (#3341)

* feat: add live logs list

* feat: hide view if error, clear logs

* feat: add condition for disable initial loading

* fix: double request

* fix: render id in the where clause

* fix: render where clause and live list

* fix: last log padding

* fix: list data loading

* fix: no logs text

* fix: logs list size

* fix: small issues

* fix: render view with memo

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>

* fix: build is fixed

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
Co-authored-by: Yunus M <myounis.ar@live.com>
2023-08-29 17:53:22 +05:30
Yunus M
337e33eb8a fix(FE): tooltip link not opening in apdex tooltip (#3441)
* Fix tooltip link not opening in apdex tooltip modal

* chore: onClick is updated from inline to one to one

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-08-28 17:54:14 +05:30
Nityananda Gohain
988dd1bcf0 fix: exists, nexists support for top level logs columns (#3434)
* fix: exists, nexists support for top level logs columns

* fix: dont check value for exists and nexists

* fix: exists, nexists updated for materialized columns

* fix: remove unnecesary variable

* fix: exists check updated in all places
2023-08-28 15:48:39 +05:30
Srikanth Chekuri
25fc7b83ec chore: update saved views endpoints (#3314) 2023-08-25 09:22:46 +05:30
Rajat Dabade
893fcfa6ee Merge pull request #3407 from SigNoz/issue-3400-ui-horizontal-scroll-logs-context 2023-08-25 07:49:47 +05:30
Palash Gupta
23f94538c8 Merge branch 'develop' into issue-3400-ui-horizontal-scroll-logs-context 2023-08-24 18:35:51 +05:30
Srikanth Chekuri
7586b50c5a fix: use query-service API to fetch triggered alerts (#3417) 2023-08-24 17:14:42 +05:30
Srikanth Chekuri
0bee0a6d90 fix: update dashboards to use placeholder params (#3408) 2023-08-24 12:14:16 +05:30
Rajat Dabade
f89f3c0b14 Merge branch 'develop' into issue-3400-ui-horizontal-scroll-logs-context 2023-08-24 11:48:32 +05:30
Vishal Sharma
598e71eb8e chore: remove ee import (#3425) 2023-08-24 11:32:06 +05:30
Srikanth Chekuri
4d14416a08 fix: update apdex query to use placeholder parameters (#3409) 2023-08-24 11:09:51 +05:30
Rajat Dabade
2657276a80 Merge branch 'develop' into issue-3400-ui-horizontal-scroll-logs-context 2023-08-24 07:53:21 +05:30
Ankit Nayan
48538e6b96 Merge branch 'main' into develop 2023-08-23 23:08:40 +05:30
Ankit Nayan
9337ff4b41 Merge pull request #3422 from SigNoz/release/v0.27.0
Release/v0.27.0
2023-08-23 23:07:58 +05:30
Yevhen Shevchenko
02cd069bb2 fix: export table panel (#3403)
* fix: export table panel

* fix: create generate link helper

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-08-23 22:14:33 +05:30
Srikanth Chekuri
6a71d311b3 chore: pin versions: SigNoz 0.27.0, SigNoz OtelCollector 0.79.6 2023-08-23 21:57:36 +05:30
Rajat Dabade
0b8367c817 Merge branch 'develop' into issue-3400-ui-horizontal-scroll-logs-context 2023-08-23 21:32:02 +05:30
Ankit Nayan
b20fc39e08 chore: do not return domain when err is observed (#3421) 2023-08-23 21:31:45 +05:30
Palash Gupta
1dd7bdb100 Merge branch 'develop' into issue-3400-ui-horizontal-scroll-logs-context 2023-08-23 17:01:15 +05:30
Ankit Nayan
591ea96285 feat: Just-in-time provisioning of SSO users (#3394)
* feat: auto provisioning of SSO users rather than needing invite link to login each user

* updating errors

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>

* fix: set IsUser: true when SSO feature is available

* fix: signoz login from IDP (#3396)

* fix: enable login from IDP with relayState set with domainName

* update comments on function

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>

* chore: added error checks to fetch domain from SAML relay state

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-08-23 16:22:24 +05:30
Nityananda Gohain
ee6b290a0c feat: get and update log fields updated to support new materialized c… (#3275)
* feat: get and update log fields updated to support new materialized columns and index

* feat: get attribute keys logic updated

* feat: logs qb changes to support new materialized columns

* feat: don't allow updating static top level fields

* feat: old logs parser updated

* feat: upgrade clickhouse

* fix: columnname format updated for materialized columns

* feat: get fields updated

* feat: minor changes

* fix: default values for distributed columns

* feat: common function for for clickhouse formatted column name

* chore: remove interesting selected fields

* fix: update clickhouse version in other place

---------

Co-authored-by: Prashant Shahi <prashant@signoz.io>
2023-08-23 15:03:24 +05:30
CKanishka
a37476a09b refactor(FE/RawLogView): move types to seperate file 2023-08-23 11:49:05 +05:30
CKanishka
d41805a3b0 refactor(FE/RawLogView): prop destructure at param level 2023-08-23 11:43:16 +05:30
Nityananda Gohain
5d6bb18679 fix: disable proxy buffering and cache (#3399)
* fix: disable proxy buffering and cache

* fix: changed for docker swarm

* fix: nginx config updated only for live tail

* fix: corrected value of buffering

---------

Co-authored-by: Prashant Shahi <prashant@signoz.io>
2023-08-23 10:27:33 +05:30
CKanishka
a393ea4d68 fix(FE/logs): enable horizontal scroll in logs context 2023-08-22 23:08:52 +05:30
dependabot[bot]
26b95f1b9f chore(deps): bump github.com/russellhaering/gosaml2 from 0.8.0 to 0.9.0 (#3406)
Bumps [github.com/russellhaering/gosaml2](https://github.com/russellhaering/gosaml2) from 0.8.0 to 0.9.0.
- [Release notes](https://github.com/russellhaering/gosaml2/releases)
- [Commits](https://github.com/russellhaering/gosaml2/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: github.com/russellhaering/gosaml2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-22 20:14:48 +05:30
Raj Kamal Singh
34be2953d3 chore: disable telemetry in CI (#3405) 2023-08-22 18:38:26 +05:30
Srikanth Chekuri
e04d5fa7e8 Align the query start and end timestamps to the nearest multiple of step (#2844) 2023-08-22 17:09:58 +05:30
Nityananda Gohain
2df5a9d72d fix: ts issue fixed with live tail (#3397) 2023-08-22 16:48:44 +05:30
Raj Kamal Singh
b6e111b835 chore: upgrade to go 1.21 (#3401) 2023-08-22 16:18:43 +05:30
Palash Gupta
6a4aa7e5f5 chore: search support is added (#3378) 2023-08-22 12:44:34 +05:30
Palash Gupta
962fc5e9ff fix: type email is added in the invite members (#3376)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-08-22 12:25:29 +05:30
Yunus M
4d5ee861ec fix: [FE-3128]: Logs Explorer: Show options based on format type selected (#3333)
* fix: [FE-3128]: Logs Explorer: Show options based on format type selected

* fix: build is fixed

---------

Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-08-22 12:12:56 +05:30
Palash Gupta
2aef4578b0 feat: default types for the query builder is updated (#3369)
Co-authored-by: Rajat Dabade <rajat@signoz.io>
2023-08-22 11:55:15 +05:30
Vishal Sharma
f8bfd1abc4 feat: add regex support to traces (#3393) 2023-08-22 10:42:53 +05:30
Nityananda Gohain
a75f4f02d6 fix: regex support updated in logs (#3392) 2023-08-21 16:08:42 +05:30
Pranay Prateek
5ae4a59060 Update Docker Download number label in README.md (#3388) 2023-08-19 12:43:43 +05:30
Palash Gupta
896836b57d fix: update request payload and color in light mode for apdex (#3381)
* fix: appdex color is updated

* fix: update payload

* chore: icon is updated

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-08-18 20:18:03 +05:30
Srikanth Chekuri
06bedc92dc Merge pull request #3379 from SigNoz/release/v0.26.1
Release/v0.26.1
2023-08-18 18:28:05 +05:30
Srikanth Chekuri
8a05b32a30 chore: resolve conflicts 2023-08-18 17:03:33 +05:30
Srikanth Chekuri
5bca66fedf chore: bump SigNoz version to 0.26.1 2023-08-18 16:51:01 +05:30
Srikanth Chekuri
6fb071cf37 fix: escape quote and backslash for ClickHouse value (#3377) 2023-08-18 15:52:59 +05:30
GitStart
9488ce8585 FE: chart metrics name suggestion not updated when text is update (#3329)
Co-authored-by: gitstart <gitstart@users.noreply.github.com>
Co-authored-by: Rubens Rafael <70234898+RubensRafael@users.noreply.github.com>
Co-authored-by: RubensRafael <rubensrafael2@live.com>
Co-authored-by: gitstart_bot <gitstart_bot@users.noreply.github.com>
Co-authored-by: Prashant Shahi <prashant@signoz.io>
2023-08-18 13:34:57 +05:30
Palash Gupta
458cff32fd feat: regex operator is added in the string type for all data source (#3362) 2023-08-18 09:18:50 +05:30
Vishal Sharma
c8bad4fc79 feat: introduce PreferRPM feature (#3197)
* feat: introduce PreferRPM feature
Completed in logs and traces but tests of metrics are not updated

* chore: pass preferRPM feature flag rather than fn

* chore: support metrics rpm

* chore: remove step interval validation
As step interval is missing in formula queries

* chore: update failing tests

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-08-18 07:32:05 +05:30
Palash Gupta
5ac105beca fix: disabled the button when both password are same (#3360) 2023-08-17 14:35:56 +05:30
Srikanth Chekuri
865409d725 Merge pull request #3354 from SigNoz/release/v0.26.0
Release/v0.26.0
2023-08-17 13:29:16 +05:30
462 changed files with 22020 additions and 4999 deletions

View File

@@ -27,9 +27,37 @@ jobs:
run: |
make build-frontend-amd64
build-frontend-ee:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Create .env file
run: |
echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > frontend/.env
echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env
echo 'CLARITY_PROJECT_ID="${{ secrets.CLARITY_PROJECT_ID }}"' >> frontend/.env
- name: Install dependencies
run: cd frontend && yarn install
- name: Run ESLint
run: cd frontend && npm run lint
- name: Run Jest
run: cd frontend && npm run jest
- name: TSC
run: yarn tsc
working-directory: ./frontend
- name: Build frontend docker image
shell: bash
run: |
make build-frontend-amd64
build-query-service:
runs-on: ubuntu-latest
steps:
- name: Setup golang
uses: actions/setup-go@v4
with:
go-version: "1.21"
- name: Checkout code
uses: actions/checkout@v3
- name: Run tests
@@ -44,6 +72,10 @@ jobs:
build-ee-query-service:
runs-on: ubuntu-latest
steps:
- name: Setup golang
uses: actions/setup-go@v4
with:
go-version: "1.21"
- name: Checkout code
uses: actions/checkout@v3
- name: Build EE query-service image

View File

@@ -123,3 +123,52 @@ jobs:
fi
- name: Build and push docker image
run: make build-push-frontend
image-build-and-push-frontend-ee:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Create .env file
run: |
echo 'INTERCOM_APP_ID="${{ secrets.INTERCOM_APP_ID }}"' > frontend/.env
echo 'SEGMENT_ID="${{ secrets.SEGMENT_ID }}"' >> frontend/.env
echo 'CLARITY_PROJECT_ID="${{ secrets.CLARITY_PROJECT_ID }}"' >> frontend/.env
- name: Install dependencies
working-directory: frontend
run: yarn install
- name: Run Prettier
working-directory: frontend
run: npm run prettify
continue-on-error: true
- name: Run ESLint
working-directory: frontend
run: npm run lint
continue-on-error: true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
with:
version: latest
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: benjlevesque/short-sha@v2.2
id: short-sha
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v5.1
- name: Set docker tag environment
run: |
if [ '${{ steps.branch-name.outputs.is_tag }}' == 'true' ]; then
tag="${{ steps.branch-name.outputs.tag }}"
tag="${tag:1}"
echo "DOCKER_TAG=${tag}-ee" >> $GITHUB_ENV
elif [ '${{ steps.branch-name.outputs.current_branch }}' == 'main' ]; then
echo "DOCKER_TAG=latest-ee" >> $GITHUB_ENV
else
echo "DOCKER_TAG=${{ steps.branch-name.outputs.current_branch }}-ee" >> $GITHUB_ENV
fi
- name: Build and push docker image
run: make build-push-frontend

2
.gitignore vendored
View File

@@ -37,7 +37,7 @@ frontend/src/constants/env.ts
**/locust-scripts/__pycache__/
**/__debug_bin
frontend/*.env
frontend/.env
pkg/query-service/signoz.db
pkg/query-service/tests/test-deploy/data/

View File

@@ -19,7 +19,7 @@ LOCAL_GOOS ?= $(shell go env GOOS)
LOCAL_GOARCH ?= $(shell go env GOARCH)
REPONAME ?= signoz
DOCKER_TAG ?= latest
DOCKER_TAG ?= $(subst v,,$(BUILD_VERSION))
FRONTEND_DOCKER_IMAGE ?= frontend
QUERY_SERVICE_DOCKER_IMAGE ?= query-service
@@ -151,3 +151,5 @@ test:
go test ./pkg/query-service/app/querier/...
go test ./pkg/query-service/converter/...
go test ./pkg/query-service/formatter/...
go test ./pkg/query-service/tests/integration/...
go test ./pkg/query-service/rules/...

View File

@@ -5,7 +5,7 @@
</p>
<p align="center">
<img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/query-service?label=Downloads"> </a>
<img alt="Downloads" src="https://img.shields.io/docker/pulls/signoz/query-service?label=Docker 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>

View File

@@ -1,8 +1,7 @@
version: "3.9"
x-clickhouse-defaults:
&clickhouse-defaults
image: clickhouse/clickhouse-server:22.8.8-alpine
x-clickhouse-defaults: &clickhouse-defaults
image: clickhouse/clickhouse-server:23.7.3-alpine
tty: true
deploy:
restart_policy:
@@ -34,8 +33,7 @@ x-clickhouse-defaults:
soft: 262144
hard: 262144
x-clickhouse-depend:
&clickhouse-depend
x-clickhouse-depend: &clickhouse-depend
depends_on:
- clickhouse
# - clickhouse-2
@@ -133,7 +131,7 @@ services:
# - ./data/clickhouse-3/:/var/lib/clickhouse/
alertmanager:
image: signoz/alertmanager:0.23.2
image: signoz/alertmanager:0.23.4
volumes:
- ./data/alertmanager:/data
command:
@@ -146,8 +144,12 @@ services:
condition: on-failure
query-service:
image: signoz/query-service:0.26.0
command: [ "-config=/root/config/prometheus.yml" ]
image: signoz/query-service:0.30.0
command:
[
"-config=/root/config/prometheus.yml",
"--prefer-delta=true"
]
# ports:
# - "6060:6060" # pprof port
# - "8080:8080" # query-service port
@@ -182,7 +184,7 @@ services:
<<: *clickhouse-depend
frontend:
image: signoz/frontend:0.26.0
image: signoz/frontend:0.30.0
deploy:
restart_policy:
condition: on-failure
@@ -195,7 +197,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/signoz-otel-collector:0.79.5
image: signoz/signoz-otel-collector:0.79.7
command:
[
"--config=/etc/otel-collector-config.yaml",
@@ -228,7 +230,7 @@ services:
<<: *clickhouse-depend
otel-collector-metrics:
image: signoz/signoz-otel-collector:0.79.5
image: signoz/signoz-otel-collector:0.79.7
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",

View File

@@ -24,8 +24,16 @@ server {
try_files $uri $uri/ /index.html;
}
location /api/alertmanager {
proxy_pass http://alertmanager:9093/api/v2;
location ~ ^/api/(v1|v3)/logs/(tail|livetail){
proxy_pass http://query-service:8080;
proxy_http_version 1.1;
# connection will be closed if no data is read for 600s between successive read operations
proxy_read_timeout 600s;
# dont buffer the data send it directly to client.
proxy_buffering off;
proxy_cache off;
}
location /api {

View File

@@ -2,7 +2,7 @@ version: "2.4"
services:
clickhouse:
image: clickhouse/clickhouse-server:22.8.8-alpine
image: clickhouse/clickhouse-server:23.7.3-alpine
container_name: signoz-clickhouse
# ports:
# - "9000:9000"
@@ -34,7 +34,7 @@ services:
alertmanager:
container_name: signoz-alertmanager
image: signoz/alertmanager:0.23.2
image: signoz/alertmanager:0.23.4
volumes:
- ./data/alertmanager:/data
depends_on:
@@ -48,7 +48,7 @@ services:
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
otel-collector:
container_name: signoz-otel-collector
image: signoz/signoz-otel-collector:0.79.5
image: signoz/signoz-otel-collector:0.79.7
command:
[
"--config=/etc/otel-collector-config.yaml",
@@ -78,7 +78,7 @@ services:
otel-collector-metrics:
container_name: signoz-otel-collector-metrics
image: signoz/signoz-otel-collector:0.79.5
image: signoz/signoz-otel-collector:0.79.7
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",

View File

@@ -22,7 +22,11 @@ services:
- ./prometheus.yml:/root/config/prometheus.yml
- ../dashboards:/root/config/dashboards
- ./data/signoz/:/var/lib/signoz/
command: [ "-config=/root/config/prometheus.yml" ]
command:
[
"-config=/root/config/prometheus.yml",
"--prefer-delta=true"
]
ports:
- "6060:6060"
- "8080:8080"

View File

@@ -1,9 +1,9 @@
version: "2.4"
x-clickhouse-defaults:
&clickhouse-defaults
x-clickhouse-defaults: &clickhouse-defaults
restart: on-failure
image: clickhouse/clickhouse-server:22.8.8-alpine
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
image: clickhouse/clickhouse-server:23.7.3-alpine
tty: true
depends_on:
- zookeeper-1
@@ -32,8 +32,7 @@ x-clickhouse-defaults:
soft: 262144
hard: 262144
x-clickhouse-depend:
&clickhouse-depend
x-clickhouse-depend: &clickhouse-depend
depends_on:
clickhouse:
condition: service_healthy
@@ -148,7 +147,7 @@ services:
# - ./user_scripts:/var/lib/clickhouse/user_scripts/
alertmanager:
image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.2}
image: signoz/alertmanager:${ALERTMANAGER_TAG:-0.23.4}
container_name: signoz-alertmanager
volumes:
- ./data/alertmanager:/data
@@ -163,9 +162,13 @@ services:
# Notes for Maintainers/Contributors who will change Line Numbers of Frontend & Query-Section. Please Update Line Numbers in `./scripts/commentLinesForSetup.sh` & `./CONTRIBUTING.md`
query-service:
image: signoz/query-service:${DOCKER_TAG:-0.26.0}
image: signoz/query-service:${DOCKER_TAG:-0.30.0}
container_name: signoz-query-service
command: [ "-config=/root/config/prometheus.yml" ]
command:
[
"-config=/root/config/prometheus.yml",
"--prefer-delta=true"
]
# ports:
# - "6060:6060" # pprof port
# - "8080:8080" # query-service port
@@ -198,7 +201,7 @@ services:
<<: *clickhouse-depend
frontend:
image: signoz/frontend:${DOCKER_TAG:-0.26.0}
image: signoz/frontend:${DOCKER_TAG:-0.30.0}
container_name: signoz-frontend
restart: on-failure
depends_on:
@@ -210,7 +213,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.79.5}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.79.7}
container_name: signoz-otel-collector
command:
[
@@ -241,7 +244,7 @@ services:
<<: *clickhouse-depend
otel-collector-metrics:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.79.5}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.79.7}
container_name: signoz-otel-collector-metrics
command:
[

View File

@@ -24,8 +24,16 @@ server {
try_files $uri $uri/ /index.html;
}
location /api/alertmanager {
proxy_pass http://alertmanager:9093/api/v2;
location ~ ^/api/(v1|v3)/logs/(tail|livetail){
proxy_pass http://query-service:8080;
proxy_http_version 1.1;
# connection will be closed if no data is read for 600s between successive read operations
proxy_read_timeout 600s;
# dont buffer the data send it directly to client.
proxy_buffering off;
proxy_cache off;
}
location /api {

View File

@@ -1,4 +1,4 @@
FROM golang:1.18-buster AS builder
FROM golang:1.21-bookworm AS builder
# LD_FLAGS is passed as argument from Makefile. It will be empty, if no argument passed
ARG LD_FLAGS
@@ -22,7 +22,7 @@ RUN cd ee/query-service \
# use a minimal alpine image
FROM alpine:3.7
FROM alpine:3.16.7
# Add Maintainer Info
LABEL maintainer="signoz"

View File

@@ -10,6 +10,7 @@ import (
"go.signoz.io/signoz/ee/query-service/license"
baseapp "go.signoz.io/signoz/pkg/query-service/app"
"go.signoz.io/signoz/pkg/query-service/app/logparsingpipeline"
"go.signoz.io/signoz/pkg/query-service/cache"
baseint "go.signoz.io/signoz/pkg/query-service/interfaces"
basemodel "go.signoz.io/signoz/pkg/query-service/model"
rules "go.signoz.io/signoz/pkg/query-service/rules"
@@ -29,6 +30,9 @@ type APIHandlerOptions struct {
FeatureFlags baseint.FeatureLookup
LicenseManager *license.Manager
LogsParsingPipelineController *logparsingpipeline.LogParsingPipelineController
Cache cache.Cache
// Querier Influx Interval
FluxInterval time.Duration
}
type APIHandler struct {
@@ -51,6 +55,8 @@ func NewAPIHandler(opts APIHandlerOptions) (*APIHandler, error) {
RuleManager: opts.RulesManager,
FeatureFlags: opts.FeatureFlags,
LogsParsingPipelineController: opts.LogsParsingPipelineController,
Cache: opts.Cache,
FluxInterval: opts.FluxInterval,
})
if err != nil {

View File

@@ -107,13 +107,13 @@ func (ah *APIHandler) registerUser(w http.ResponseWriter, r *http.Request) {
RespondError(w, model.InternalError(basemodel.ErrSignupFailed{}), nil)
}
precheckResp := &model.PrecheckResponse{
precheckResp := &basemodel.PrecheckResponse{
SSO: false,
IsUser: false,
}
if domain != nil && domain.SsoEnabled {
// so is enabled, create user and respond precheck data
// sso is enabled, create user and respond precheck data
user, apierr := baseauth.RegisterInvitedUser(ctx, req, true)
if apierr != nil {
RespondError(w, apierr, nil)

View File

@@ -137,8 +137,8 @@ func (ah *APIHandler) queryRangeMetricsV2(w http.ResponseWriter, r *http.Request
var s basemodel.Series
s.QueryName = name
s.Labels = v.Metric.Copy().Map()
for _, p := range v.Points {
s.Points = append(s.Points, basemodel.MetricPoint{Timestamp: p.T, Value: p.V})
for _, p := range v.Floats {
s.Points = append(s.Points, basemodel.MetricPoint{Timestamp: p.T, Value: p.F})
}
seriesList = append(seriesList, &s)
}

View File

@@ -35,6 +35,7 @@ import (
"go.signoz.io/signoz/pkg/query-service/app/opamp"
opAmpModel "go.signoz.io/signoz/pkg/query-service/app/opamp/model"
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
"go.signoz.io/signoz/pkg/query-service/cache"
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
"go.signoz.io/signoz/pkg/query-service/healthcheck"
basealm "go.signoz.io/signoz/pkg/query-service/integrations/alertManager"
@@ -62,6 +63,8 @@ type ServerOptions struct {
MaxIdleConns int
MaxOpenConns int
DialTimeout time.Duration
CacheConfigPath string
FluxInterval string
}
// Server runs HTTP api service
@@ -189,6 +192,21 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
telemetry.GetInstance().SetReader(reader)
var c cache.Cache
if serverOptions.CacheConfigPath != "" {
cacheOpts, err := cache.LoadFromYAMLCacheConfigFile(serverOptions.CacheConfigPath)
if err != nil {
return nil, err
}
c = cache.NewCache(cacheOpts)
}
fluxInterval, err := time.ParseDuration(serverOptions.FluxInterval)
if err != nil {
return nil, err
}
apiOpts := api.APIHandlerOptions{
DataConnector: reader,
SkipConfig: skipConfig,
@@ -202,6 +220,8 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
FeatureFlags: lm,
LicenseManager: lm,
LogsParsingPipelineController: logParsingPipelineController,
Cache: c,
FluxInterval: fluxInterval,
}
apiHandler, err := api.NewAPIHandler(apiOpts)
@@ -548,7 +568,7 @@ func (s *Server) Start() error {
go func() {
zap.S().Info("Starting OpAmp Websocket server", zap.String("addr", baseconst.OpAmpWsEndpoint))
err := opamp.InitalizeServer(baseconst.OpAmpWsEndpoint, &opAmpModel.AllAgents)
err := opamp.InitializeAndStartServer(baseconst.OpAmpWsEndpoint, &opAmpModel.AllAgents)
if err != nil {
zap.S().Info("opamp ws server failed to start", err)
s.unavailableChannel <- healthcheck.Unavailable

View File

@@ -21,7 +21,6 @@ type ModelDao interface {
DB() *sqlx.DB
// auth methods
PrecheckLogin(ctx context.Context, email, sourceUrl string) (*model.PrecheckResponse, basemodel.BaseApiError)
CanUsePassword(ctx context.Context, email string) (bool, basemodel.BaseApiError)
PrepareSsoRedirect(ctx context.Context, redirectUri, email string) (redirectURL string, apierr basemodel.BaseApiError)
GetDomainFromSsoResponse(ctx context.Context, relayState *url.URL) (*model.OrgDomain, error)

View File

@@ -5,16 +5,61 @@ import (
"fmt"
"net/url"
"strings"
"time"
"github.com/google/uuid"
"go.signoz.io/signoz/ee/query-service/constants"
"go.signoz.io/signoz/ee/query-service/model"
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
baseconst "go.signoz.io/signoz/pkg/query-service/constants"
basemodel "go.signoz.io/signoz/pkg/query-service/model"
baseauth "go.signoz.io/signoz/pkg/query-service/auth"
"go.signoz.io/signoz/pkg/query-service/utils"
"go.uber.org/zap"
)
// PrepareSsoRedirect prepares redirect page link after SSO response
func (m *modelDao) createUserForSAMLRequest(ctx context.Context, email string) (*basemodel.User, basemodel.BaseApiError) {
// get auth domain from email domain
domain, apierr := m.GetDomainByEmail(ctx, email)
if apierr != nil {
zap.S().Errorf("failed to get domain from email", apierr)
return nil, model.InternalErrorStr("failed to get domain from email")
}
hash, err := baseauth.PasswordHash(utils.GeneratePassowrd())
if err != nil {
zap.S().Errorf("failed to generate password hash when registering a user via SSO redirect", zap.Error(err))
return nil, model.InternalErrorStr("failed to generate password hash")
}
group, apiErr := m.GetGroupByName(ctx, baseconst.ViewerGroup)
if apiErr != nil {
zap.S().Debugf("GetGroupByName failed, err: %v\n", apiErr.Err)
return nil, apiErr
}
user := &basemodel.User{
Id: uuid.NewString(),
Name: "",
Email: email,
Password: hash,
CreatedAt: time.Now().Unix(),
ProfilePictureURL: "", // Currently unused
GroupId: group.Id,
OrgId: domain.OrgId,
}
user, apiErr = m.CreateUser(ctx, user, false)
if apiErr != nil {
zap.S().Debugf("CreateUser failed, err: %v\n", apiErr.Err)
return nil, apiErr
}
return user, nil
}
// PrepareSsoRedirect prepares redirect page link after SSO response
// is successfully parsed (i.e. valid email is available)
func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email string) (redirectURL string, apierr basemodel.BaseApiError) {
@@ -24,7 +69,20 @@ func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email st
return "", model.BadRequestStr("invalid user email received from the auth provider")
}
tokenStore, err := baseauth.GenerateJWTForUser(&userPayload.User)
user := &basemodel.User{}
if userPayload == nil {
newUser, apiErr := m.createUserForSAMLRequest(ctx, email)
user = newUser
if apiErr != nil {
zap.S().Errorf("failed to create user with email received from auth provider: %v", apierr.Error())
return "", apiErr
}
} else {
user = &userPayload.User
}
tokenStore, err := baseauth.GenerateJWTForUser(user)
if err != nil {
zap.S().Errorf("failed to generate token for SSO login user", err)
return "", model.InternalErrorStr("failed to generate token for the user")
@@ -33,7 +91,7 @@ func (m *modelDao) PrepareSsoRedirect(ctx context.Context, redirectUri, email st
return fmt.Sprintf("%s?jwt=%s&usr=%s&refreshjwt=%s",
redirectUri,
tokenStore.AccessJwt,
userPayload.User.Id,
user.Id,
tokenStore.RefreshJwt), nil
}
@@ -62,10 +120,10 @@ func (m *modelDao) CanUsePassword(ctx context.Context, email string) (bool, base
// PrecheckLogin is called when the login or signup page is loaded
// to check sso login is to be prompted
func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (*model.PrecheckResponse, basemodel.BaseApiError) {
func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (*basemodel.PrecheckResponse, basemodel.BaseApiError) {
// assume user is valid unless proven otherwise
resp := &model.PrecheckResponse{IsUser: true, CanSelfRegister: false}
resp := &basemodel.PrecheckResponse{IsUser: true, CanSelfRegister: false}
// check if email is a valid user
userPayload, baseApiErr := m.GetUserByEmail(ctx, email)
@@ -76,6 +134,7 @@ func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (
if userPayload == nil {
resp.IsUser = false
}
ssoAvailable := true
err := m.checkFeature(model.SSO)
if err != nil {
@@ -91,6 +150,8 @@ func (m *modelDao) PrecheckLogin(ctx context.Context, email, sourceUrl string) (
if ssoAvailable {
resp.IsUser = true
// find domain from email
orgDomain, apierr := m.GetDomainByEmail(ctx, email)
if apierr != nil {

View File

@@ -4,8 +4,8 @@ import (
"context"
"database/sql"
"encoding/json"
"net/url"
"fmt"
"net/url"
"strings"
"time"
@@ -28,29 +28,70 @@ type StoredDomain struct {
// GetDomainFromSsoResponse uses relay state received from IdP to fetch
// user domain. The domain is further used to process validity of the response.
// when sending login request to IdP we send relay state as URL (site url)
// with domainId as query parameter.
// when sending login request to IdP we send relay state as URL (site url)
// with domainId or domainName as query parameter.
func (m *modelDao) GetDomainFromSsoResponse(ctx context.Context, relayState *url.URL) (*model.OrgDomain, error) {
// derive domain id from relay state now
var domainIdStr string
var domainIdStr string
var domainNameStr string
var domain *model.OrgDomain
for k, v := range relayState.Query() {
if k == "domainId" && len(v) > 0 {
domainIdStr = strings.Replace(v[0], ":", "-", -1)
}
if k == "domainName" && len(v) > 0 {
domainNameStr = v[0]
}
}
domainId, err := uuid.Parse(domainIdStr)
if domainIdStr != "" {
domainId, err := uuid.Parse(domainIdStr)
if err != nil {
zap.S().Errorf("failed to parse domainId from relay state", err)
return nil, fmt.Errorf("failed to parse domainId from IdP response")
}
domain, err = m.GetDomain(ctx, domainId)
if (err != nil) || domain == nil {
zap.S().Errorf("failed to find domain from domainId received in IdP response", err.Error())
return nil, fmt.Errorf("invalid credentials")
}
}
if domainNameStr != "" {
domainFromDB, err := m.GetDomainByName(ctx, domainNameStr)
domain = domainFromDB
if (err != nil) || domain == nil {
zap.S().Errorf("failed to find domain from domainName received in IdP response", err.Error())
return nil, fmt.Errorf("invalid credentials")
}
}
if domain != nil {
return domain, nil
}
return nil, fmt.Errorf("failed to find domain received in IdP response")
}
// GetDomainByName returns org domain for a given domain name
func (m *modelDao) GetDomainByName(ctx context.Context, name string) (*model.OrgDomain, basemodel.BaseApiError) {
stored := StoredDomain{}
err := m.DB().Get(&stored, `SELECT * FROM org_domains WHERE name=$1 LIMIT 1`, name)
if err != nil {
zap.S().Errorf("failed to parse domain id from relay state", err)
return nil, fmt.Errorf("failed to parse response from IdP response")
if err == sql.ErrNoRows {
return nil, model.BadRequest(fmt.Errorf("invalid domain name"))
}
return nil, model.InternalError(err)
}
domain, err := m.GetDomain(ctx, domainId)
if (err != nil) || domain == nil {
zap.S().Errorf("failed to find domain received in IdP response", err.Error())
return nil, fmt.Errorf("invalid credentials")
domain := &model.OrgDomain{Id: stored.Id, Name: stored.Name, OrgId: stored.OrgId}
if err := domain.LoadConfig(stored.Data); err != nil {
return nil, model.InternalError(err)
}
return domain, nil
}
@@ -69,7 +110,7 @@ func (m *modelDao) GetDomain(ctx context.Context, id uuid.UUID) (*model.OrgDomai
domain := &model.OrgDomain{Id: stored.Id, Name: stored.Name, OrgId: stored.OrgId}
if err := domain.LoadConfig(stored.Data); err != nil {
return domain, model.InternalError(err)
return nil, model.InternalError(err)
}
return domain, nil
}
@@ -206,7 +247,7 @@ func (m *modelDao) GetDomainByEmail(ctx context.Context, email string) (*model.O
domain := &model.OrgDomain{Id: stored.Id, Name: stored.Name, OrgId: stored.OrgId}
if err := domain.LoadConfig(stored.Data); err != nil {
return domain, model.InternalError(err)
return nil, model.InternalError(err)
}
return domain, nil
}

View File

@@ -82,6 +82,7 @@ func main() {
// the url used to build link in the alert messages in slack and other systems
var ruleRepoURL string
var cacheConfigPath, fluxInterval string
var enableQueryServiceLogOTLPExport bool
var preferDelta bool
var preferSpanMetrics bool
@@ -99,10 +100,14 @@ func main() {
flag.IntVar(&maxOpenConns, "max-open-conns", 100, "(max connections for use at any time.)")
flag.DurationVar(&dialTimeout, "dial-timeout", 5*time.Second, "(the maximum time to establish a connection.)")
flag.StringVar(&ruleRepoURL, "rules.repo-url", baseconst.AlertHelpPage, "(host address used to build rule link in alert messages)")
flag.StringVar(&cacheConfigPath, "experimental.cache-config", "", "(cache config to use)")
flag.StringVar(&fluxInterval, "flux-interval", "5m", "(cache config to use)")
flag.BoolVar(&enableQueryServiceLogOTLPExport, "enable.query.service.log.otlp.export", false, "(enable query service log otlp export)")
flag.Parse()
loggerMgr := initZapLog(enableQueryServiceLogOTLPExport)
zap.ReplaceGlobals(loggerMgr)
defer loggerMgr.Sync() // flushes buffer, if any
@@ -121,6 +126,8 @@ func main() {
MaxIdleConns: maxIdleConns,
MaxOpenConns: maxOpenConns,
DialTimeout: dialTimeout,
CacheConfigPath: cacheConfigPath,
FluxInterval: fluxInterval,
}
// Read the jwt secret key

View File

@@ -4,18 +4,9 @@ import (
basemodel "go.signoz.io/signoz/pkg/query-service/model"
)
// PrecheckResponse contains login precheck response
type PrecheckResponse struct {
SSO bool `json:"sso"`
SsoUrl string `json:"ssoUrl"`
CanSelfRegister bool `json:"canSelfRegister"`
IsUser bool `json:"isUser"`
SsoError string `json:"ssoError"`
}
// GettableInvitation overrides base object and adds precheck into
// response
type GettableInvitation struct {
*basemodel.InvitationResponseObject
Precheck *PrecheckResponse `json:"precheck"`
Precheck *basemodel.PrecheckResponse `json:"precheck"`
}

View File

@@ -2,6 +2,7 @@ package model
import (
"fmt"
basemodel "go.signoz.io/signoz/pkg/query-service/model"
)
@@ -61,7 +62,6 @@ func InternalError(err error) *ApiError {
}
}
// InternalErrorStr returns a ApiError object of internal type for string input
func InternalErrorStr(s string) *ApiError {
return &ApiError{
@@ -69,6 +69,7 @@ func InternalErrorStr(s string) *ApiError {
Err: fmt.Errorf(s),
}
}
var (
ErrorNone basemodel.ErrorType = ""
ErrorTimeout basemodel.ErrorType = "timeout"

View File

@@ -9,6 +9,8 @@ const Basic = "BASIC_PLAN"
const Pro = "PRO_PLAN"
const Enterprise = "ENTERPRISE_PLAN"
const DisableUpsell = "DISABLE_UPSELL"
const Onboarding = "ONBOARDING"
const ChatSupport = "CHAT_SUPPORT"
var BasicPlan = basemodel.FeatureSet{
basemodel.Feature{
@@ -81,6 +83,13 @@ var BasicPlan = basemodel.FeatureSet{
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: basemodel.AlertChannelOpsgenie,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: basemodel.AlertChannelMsTeams,
Active: false,
@@ -161,6 +170,13 @@ var ProPlan = basemodel.FeatureSet{
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: basemodel.AlertChannelOpsgenie,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: basemodel.AlertChannelMsTeams,
Active: true,
@@ -241,6 +257,13 @@ var EnterprisePlan = basemodel.FeatureSet{
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: basemodel.AlertChannelOpsgenie,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: basemodel.AlertChannelMsTeams,
Active: true,
@@ -255,4 +278,18 @@ var EnterprisePlan = basemodel.FeatureSet{
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: Onboarding,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
basemodel.Feature{
Name: ChatSupport,
Active: true,
Usage: 0,
UsageLimit: -1,
Route: "",
},
}

View File

@@ -1,5 +1,4 @@
node_modules
.vscode
build
.env
.git

6
frontend/.prettierignore Normal file
View File

@@ -0,0 +1,6 @@
# Ignore artifacts:
build
coverage
# Ignore all MD files:
**/*.md

View File

@@ -24,7 +24,7 @@ COPY . .
RUN yarn build
FROM nginx:1.24.0-alpine
FROM nginx:1.25.2-alpine
COPY conf/default.conf /etc/nginx/conf.d/default.conf

7
frontend/example.env Normal file
View File

@@ -0,0 +1,7 @@
NODE_ENV="development"
BUNDLE_ANALYSER="true"
FRONTEND_API_ENDPOINT="http://localhost:3301/"
INTERCOM_APP_ID="intercom-app-id"
PLAYWRIGHT_TEST_BASE_URL="http://localhost:3301"
CI="1"

View File

@@ -7,7 +7,7 @@ const config: Config.InitialOptions = {
moduleFileExtensions: ['ts', 'tsx', 'js', 'json'],
modulePathIgnorePatterns: ['dist'],
moduleNameMapper: {
'\\.(css|less)$': '<rootDir>/__mocks__/cssMock.ts',
'\\.(css|less|scss)$': '<rootDir>/__mocks__/cssMock.ts',
},
globals: {
extensionsToTreatAsEsm: ['.ts'],

View File

@@ -29,27 +29,31 @@
"dependencies": {
"@ant-design/colors": "6.0.0",
"@ant-design/icons": "4.8.0",
"@grafana/data": "^8.4.3",
"@grafana/data": "^9.5.2",
"@mdx-js/loader": "2.3.0",
"@mdx-js/react": "2.3.0",
"@monaco-editor/react": "^4.3.1",
"@uiw/react-md-editor": "3.23.5",
"@xstate/react": "^3.0.0",
"ansi-to-html": "0.7.2",
"antd": "5.0.5",
"antd-table-saveas-excel": "2.2.1",
"axios": "^0.21.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.6.0",
"babel-loader": "8.1.0",
"babel-jest": "^29.6.4",
"babel-loader": "9.1.3",
"babel-plugin-named-asset-import": "^0.3.7",
"babel-preset-minify": "^0.5.1",
"babel-preset-react-app": "^10.0.0",
"babel-preset-react-app": "^10.0.1",
"chart.js": "3.9.1",
"chartjs-adapter-date-fns": "^2.0.0",
"chartjs-plugin-annotation": "^1.4.0",
"classnames": "2.3.2",
"color": "^4.2.1",
"color-alpha": "1.1.3",
"cross-env": "^7.0.3",
"css-loader": "4.3.0",
"css-minimizer-webpack-plugin": "^3.2.0",
"css-minimizer-webpack-plugin": "5.0.1",
"dayjs": "^1.10.7",
"dompurify": "3.0.0",
"dotenv": "8.2.0",
@@ -58,7 +62,7 @@
"file-loader": "6.1.1",
"fontfaceobserver": "2.3.0",
"history": "4.10.1",
"html-webpack-plugin": "5.1.0",
"html-webpack-plugin": "5.5.0",
"i18next": "^21.6.12",
"i18next-browser-languagedetector": "^6.1.3",
"i18next-http-backend": "^1.3.2",
@@ -75,21 +79,23 @@
"react-dnd-html5-backend": "16.0.1",
"react-dom": "18.2.0",
"react-drag-listview": "2.0.0",
"react-force-graph": "^1.41.0",
"react-force-graph": "^1.43.0",
"react-grid-layout": "^1.3.4",
"react-helmet-async": "1.3.0",
"react-i18next": "^11.16.1",
"react-intersection-observer": "9.4.1",
"react-markdown": "8.0.7",
"react-query": "^3.34.19",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-syntax-highlighter": "15.5.0",
"react-use": "^17.3.2",
"react-virtuoso": "4.0.3",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0",
"stream": "^0.0.2",
"style-loader": "1.3.0",
"styled-components": "^5.2.1",
"styled-components": "^5.3.11",
"terser-webpack-plugin": "^5.2.5",
"timestamp-nano": "^1.0.0",
"ts-node": "^10.2.1",
@@ -97,8 +103,8 @@
"typescript": "^4.0.5",
"uuid": "^8.3.2",
"web-vitals": "^0.2.4",
"webpack": "^5.23.0",
"webpack-dev-server": "^4.3.1",
"webpack": "5.88.2",
"webpack-dev-server": "^4.15.1",
"xstate": "^4.31.0"
},
"browserslist": {
@@ -114,13 +120,13 @@
]
},
"devDependencies": {
"@babel/core": "^7.12.3",
"@babel/plugin-proposal-class-properties": "^7.12.13",
"@babel/core": "^7.22.11",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/plugin-syntax-jsx": "^7.12.13",
"@babel/preset-env": "^7.12.17",
"@babel/preset-env": "^7.22.14",
"@babel/preset-react": "^7.12.13",
"@babel/preset-typescript": "^7.12.17",
"@commitlint/cli": "^16.2.4",
"@babel/preset-typescript": "^7.21.4",
"@commitlint/cli": "^16.3.0",
"@commitlint/config-conventional": "^16.2.4",
"@jest/globals": "^27.5.1",
"@playwright/test": "^1.22.0",
@@ -146,25 +152,25 @@
"@types/react-redux": "^7.1.11",
"@types/react-resizable": "3.0.3",
"@types/react-router-dom": "^5.1.6",
"@types/react-syntax-highlighter": "15.5.7",
"@types/styled-components": "^5.1.4",
"@types/uuid": "^8.3.1",
"@types/webpack": "^5.28.0",
"@types/webpack-dev-server": "^4.3.0",
"@typescript-eslint/eslint-plugin": "^4.28.2",
"@typescript-eslint/parser": "^4.28.2",
"@welldone-software/why-did-you-render": "6.2.1",
"@types/webpack-dev-server": "^4.7.2",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"autoprefixer": "^9.0.0",
"babel-plugin-styled-components": "^1.12.0",
"compression-webpack-plugin": "9.0.0",
"copy-webpack-plugin": "^8.1.0",
"critters-webpack-plugin": "^3.0.1",
"eslint": "^7.30.0",
"eslint": "^7.32.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^16.1.4",
"eslint-config-prettier": "^8.3.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-jest": "^26.1.2",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jest": "^26.9.0",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^4.0.0",
@@ -175,17 +181,20 @@
"eslint-plugin-sonarjs": "^0.12.0",
"husky": "^7.0.4",
"is-ci": "^3.0.1",
"jest-playwright-preset": "^1.7.0",
"jest-playwright-preset": "^1.7.2",
"jest-styled-components": "^7.0.8",
"lint-staged": "^12.3.7",
"lint-staged": "^12.5.0",
"portfinder-sync": "^0.0.2",
"prettier": "2.2.1",
"raw-loader": "4.0.2",
"react-hooks-testing-library": "0.6.0",
"react-hot-loader": "^4.13.0",
"react-resizable": "3.0.4",
"ts-jest": "^27.1.4",
"sass": "1.66.1",
"sass-loader": "13.3.2",
"ts-jest": "^27.1.5",
"ts-node": "^10.2.1",
"typescript-plugin-css-modules": "^3.4.0",
"typescript-plugin-css-modules": "5.0.1",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-cli": "^4.9.2"
},
@@ -196,6 +205,9 @@
},
"resolutions": {
"@types/react": "18.0.26",
"@types/react-dom": "18.0.10"
"@types/react-dom": "18.0.10",
"debug": "4.3.4",
"semver": "7.5.4",
"xml2js": "0.5.0"
}
}

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 103.53" style="enable-background:new 0 0 122.88 103.53" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;} .st0{fill:#1668dc;} .st1{fill:#FFFFFF;}</style><g><path class="st0" d="M5.47,0h111.93c3.01,0,5.47,2.46,5.47,5.47v92.58c0,3.01-2.46,5.47-5.47,5.47H5.47 c-3.01,0-5.47-2.46-5.47-5.47V5.47C0,2.46,2.46,0,5.47,0L5.47,0z M31.84,38.55l17.79,18.42l2.14,2.13l-2.12,2.16L31.68,80.31 l-5.07-5l15.85-16.15L26.81,43.6L31.84,38.55L31.84,38.55z M94.1,79.41H54.69v-6.84H94.1V79.41L94.1,79.41z M38.19,9.83 c3.19,0,5.78,2.59,5.78,5.78s-2.59,5.78-5.78,5.78c-3.19,0-5.78-2.59-5.78-5.78S35,9.83,38.19,9.83L38.19,9.83z M18.95,9.83 c3.19,0,5.78,2.59,5.78,5.78s-2.59,5.78-5.78,5.78c-3.19,0-5.78-2.59-5.78-5.78S15.75,9.83,18.95,9.83L18.95,9.83z M7.49,5.41 h107.91c1.15,0,2.09,0.94,2.09,2.09v18.32H5.4V7.5C5.4,6.35,6.34,5.41,7.49,5.41L7.49,5.41z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 88.17" style="enable-background:new 0 0 122.88 88.17" xml:space="preserve"><style type="text/css">.st0{fill:#0091E2;}</style><g><path class="st0" d="M121.68,33.34c-0.34-0.28-3.42-2.62-10.03-2.62c-1.71,0-3.48,0.17-5.19,0.46c-1.25-8.72-8.49-12.94-8.78-13.16 l-1.77-1.03l-1.14,1.65c-1.42,2.22-2.51,4.73-3.13,7.29c-1.2,4.96-0.46,9.63,2.05,13.62c-3.02,1.71-7.92,2.11-8.95,2.17l-80.93,0 c-2.11,0-3.82,1.71-3.82,3.82c-0.11,7.07,1.08,14.13,3.53,20.8c2.79,7.29,6.95,12.71,12.31,16.01c6.04,3.7,15.9,5.81,27.01,5.81 c5.01,0,10.03-0.46,14.99-1.37c6.9-1.25,13.51-3.65,19.6-7.12c5.02-2.91,9.52-6.61,13.34-10.94c6.44-7.24,10.26-15.33,13.05-22.51 c0.4,0,0.74,0,1.14,0c7.01,0,11.34-2.79,13.73-5.19c1.6-1.48,2.79-3.31,3.65-5.36l0.51-1.48L121.68,33.34L121.68,33.34z M71.59,39.38h10.83c0.51,0,0.97-0.4,0.97-0.97v-9.69c0-0.51-0.4-0.97-0.97-0.97l0,0l-10.83,0c-0.51,0-0.97,0.4-0.97,0.97l0,0v9.69 C70.68,38.98,71.08,39.38,71.59,39.38L71.59,39.38z M56.49,11.63h10.83c0.51,0,0.97-0.4,0.97-0.97V0.97c0-0.51-0.46-0.97-0.97-0.97 L56.49,0c-0.51,0-0.97,0.4-0.97,0.97l0,0v9.69C55.52,11.17,55.97,11.63,56.49,11.63L56.49,11.63z M56.49,25.53h10.83 c0.51,0,0.97-0.46,0.97-0.97v-9.69c0-0.51-0.46-0.97-0.97-0.97H56.49c-0.51,0-0.97,0.4-0.97,0.97l0,0v9.69 C55.52,25.08,55.97,25.53,56.49,25.53L56.49,25.53z M41.5,25.53h10.83c0.51,0,0.97-0.46,0.97-0.97v-9.69c0-0.51-0.4-0.97-0.97-0.97 l0,0H41.5c-0.51,0-0.97,0.4-0.97,0.97l0,0v9.69C40.53,25.08,40.93,25.53,41.5,25.53L41.5,25.53z M26.28,25.53h10.83 c0.51,0,0.97-0.46,0.97-0.97v-9.69c0-0.51-0.4-0.97-0.97-0.97l0,0H26.28c-0.51,0-0.97,0.4-0.97,0.97v9.69 C25.37,25.08,25.77,25.53,26.28,25.53L26.28,25.53z M56.49,39.38h10.83c0.51,0,0.97-0.4,0.97-0.97v-9.69c0-0.51-0.4-0.97-0.97-0.97 l0,0l-10.83,0c-0.51,0-0.97,0.4-0.97,0.97l0,0v9.69C55.52,38.98,55.97,39.38,56.49,39.38L56.49,39.38L56.49,39.38z M41.5,39.38 h10.83c0.51,0,0.97-0.4,0.97-0.97l0,0v-9.69c0-0.51-0.4-0.97-0.97-0.97l0,0l-10.83,0c-0.51,0-0.97,0.4-0.97,0.97l0,0v9.69 C40.53,38.98,40.93,39.38,41.5,39.38L41.5,39.38L41.5,39.38z M26.28,39.38h10.83c0.51,0,0.97-0.4,0.97-0.97l0,0v-9.69 c0-0.51-0.4-0.97-0.97-0.97l0,0l-10.83,0c-0.51,0-0.97,0.4-0.97,0.97v9.69C25.37,38.98,25.77,39.38,26.28,39.38L26.28,39.38z M11.35,39.38h10.83c0.51,0,0.97-0.4,0.97-0.97l0,0v-9.69c0-0.51-0.4-0.97-0.97-0.97l0,0l-10.83,0c-0.51,0-0.97,0.4-0.97,0.97l0,0 v9.69C10.44,38.98,10.84,39.38,11.35,39.38L11.35,39.38L11.35,39.38z"/></g></svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 109 122.88" style="enable-background:new 0 0 109 122.88" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#689F63;}</style><g><path class="st0" d="M68.43,87.08c-19.7,0-23.83-9.04-23.83-16.63c0-0.72,0.58-1.3,1.3-1.3h5.82c0.64,0,1.18,0.47,1.28,1.1 c0.88,5.93,3.49,8.92,15.41,8.92c9.49,0,13.52-2.14,13.52-7.18c0-2.9-1.15-5.05-15.89-6.49c-12.33-1.22-19.95-3.93-19.95-13.8 c0-9.08,7.66-14.49,20.5-14.49c14.42,0,21.56,5,22.46,15.76c0.03,0.37-0.1,0.73-0.35,1c-0.25,0.26-0.6,0.42-0.96,0.42H81.9 c-0.61,0-1.14-0.43-1.26-1.01c-1.41-6.23-4.81-8.23-14.07-8.23c-10.36,0-11.56,3.61-11.56,6.31c0,3.28,1.42,4.24,15.4,6.09 c13.84,1.84,20.41,4.43,20.41,14.16c0,9.81-8.18,15.43-22.45,15.43L68.43,87.08L68.43,87.08z M54.52,122.88 c-1.65,0-3.28-0.43-4.72-1.26l-15.03-8.9c-2.25-1.26-1.15-1.7-0.41-1.96c2.99-1.05,3.6-1.28,6.8-3.1c0.34-0.19,0.78-0.12,1.12,0.08 l11.55,6.85c0.42,0.23,1.01,0.23,1.4,0l45.03-25.99c0.42-0.24,0.69-0.72,0.69-1.22V35.43c0-0.52-0.27-0.98-0.7-1.24L55.23,8.22 c-0.42-0.25-0.97-0.25-1.39,0l-45,25.97c-0.44,0.25-0.71,0.73-0.71,1.23v51.96c0,0.5,0.27,0.97,0.7,1.21l12.33,7.12 c6.69,3.35,10.79-0.6,10.79-4.56V39.86c0-0.73,0.57-1.3,1.31-1.3l5.7,0c0.71,0,1.3,0.56,1.3,1.3v51.31 c0,8.93-4.87,14.05-13.33,14.05c-2.6,0-4.66,0-10.38-2.82L4.72,95.59C1.8,93.9,0,90.75,0,87.38V35.42c0-3.38,1.8-6.54,4.72-8.21 l45.07-26c2.85-1.61,6.64-1.61,9.47,0l45.02,26.01c2.91,1.68,4.72,4.82,4.72,8.21v51.96c0,3.37-1.81,6.51-4.72,8.21l-45.02,26 c-1.44,0.83-3.08,1.26-4.74,1.26L54.52,122.88L54.52,122.88z M54.52,122.88L54.52,122.88L54.52,122.88L54.52,122.88z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1 @@
<?xml version="1.0" encoding="utf-8"?><svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 122.88 98.18" style="enable-background:new 0 0 122.88 98.18" xml:space="preserve"><style type="text/css">.st0{fill-rule:evenodd;clip-rule:evenodd;} .st0{fill:#1668dc;} .st1{fill:#FFFFFF;}</style><g><path class="st0" d="M3.42,0h116.05c1.88,0,3.41,1.54,3.41,3.41v91.36c0,1.88-1.54,3.41-3.41,3.41l-116.05,0 C1.54,98.18,0,96.65,0,94.77L0,3.41C0,1.53,1.54,0,3.42,0L3.42,0L3.42,0z M25.89,8.19c2.05,0,3.72,1.67,3.72,3.72 c0,2.05-1.67,3.72-3.72,3.72c-2.05,0-3.72-1.67-3.72-3.72C22.17,9.85,23.83,8.19,25.89,8.19L25.89,8.19z M103.07,7.69l2.52,2.77 l2.52-2.77l1.97,1.79l-2.69,2.96l2.69,2.96l-1.97,1.79l-2.52-2.77l-2.52,2.77l-1.97-1.79l2.69-2.96l-2.69-2.96L103.07,7.69 L103.07,7.69z M14.52,8.19c2.05,0,3.72,1.67,3.72,3.72c0,2.05-1.67,3.72-3.72,3.72c-2.05,0-3.72-1.67-3.72-3.72 C10.79,9.85,12.46,8.19,14.52,8.19L14.52,8.19z M37.26,8.19c2.05,0,3.72,1.67,3.72,3.72c0,2.05-1.67,3.72-3.72,3.72 c-2.05,0-3.72-1.67-3.72-3.72C33.54,9.85,35.21,8.19,37.26,8.19L37.26,8.19z M14.05,22.75h93.33c1.77,0,3.22,1.49,3.22,3.22v59.2 c0,1.73-1.49,3.22-3.22,3.22l-93.33,0c-1.73,0-3.22-1.45-3.22-3.22v-59.2C10.84,24.2,12.29,22.75,14.05,22.75L14.05,22.75 L14.05,22.75z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -0,0 +1,3 @@
{
"name_of_the_view": "Name of the view"
}

View File

@@ -0,0 +1 @@
{ "fetching_log_lines": "Fetching log lines" }

View File

@@ -8,7 +8,7 @@
"label_orgname": "Organization Name",
"placeholder_orgname": "Your Company",
"prompt_keepme_posted": "Keep me updated on new SigNoz features",
"prompt_anonymise": "Anonymise my usage date. We collect data to measure product usage",
"prompt_anonymise": "Anonymise my usage data. We collect data to measure product usage",
"failed_confirm_password": "Passwords dont match. Please try again",
"unexpected_error": "Something went wrong",
"failed_to_initiate_login": "Signup completed but failed to initiate login",

View File

@@ -1,13 +1,13 @@
{
"SIGN_UP": "SigNoz | Sign Up",
"LOGIN": "SigNoz | Login",
"GET_STARTED": "SigNoz | Get Started",
"SERVICE_METRICS": "SigNoz | Service Metrics",
"SERVICE_MAP": "SigNoz | Service Map",
"TRACE": "SigNoz | Trace",
"TRACE_DETAIL": "SigNoz | Trace Detail",
"TRACES_EXPLORER": "SigNoz | Traces Explorer",
"SETTINGS": "SigNoz | Settings",
"INSTRUMENTATION": "SigNoz | Get Started",
"USAGE_EXPLORER": "SigNoz | Usage Explorer",
"APPLICATION": "SigNoz | Home",
"ALL_DASHBOARD": "SigNoz | All Dashboards",
@@ -29,6 +29,7 @@
"NOT_FOUND": "SigNoz | Page Not Found",
"LOGS": "SigNoz | Logs",
"LOGS_EXPLORER": "SigNoz | Logs Explorer",
"LIVE_LOGS": "SigNoz | Live Logs",
"HOME_PAGE": "Open source Observability Platform | SigNoz",
"PASSWORD_RESET": "SigNoz | Password Reset",
"LIST_LICENSES": "SigNoz | List of Licenses",

View File

@@ -20,6 +20,9 @@
"field_slack_recipient": "Recipient",
"field_slack_title": "Title",
"field_slack_description": "Description",
"field_opsgenie_api_key": "API Key",
"field_opsgenie_description": "Description",
"placeholder_opsgenie_description": "Description",
"field_webhook_username": "User Name (optional)",
"field_webhook_password": "Password (optional)",
"field_pager_routing_key": "Routing Key",
@@ -31,8 +34,12 @@
"field_pager_class": "Class",
"field_pager_client": "Client",
"field_pager_client_url": "Client URL",
"field_opsgenie_message": "Message",
"field_opsgenie_priority": "Priority",
"placeholder_slack_description": "Description",
"placeholder_pager_description": "Description",
"placeholder_opsgenie_message": "Message",
"placeholder_opsgenie_priority": "Priority",
"help_pager_client": "Shows up as event source in Pagerduty",
"help_pager_client_url": "Shows up as event source link in Pagerduty",
"help_pager_class": "The class/type of the event",
@@ -43,6 +50,9 @@
"help_webhook_username": "Leave empty for bearer auth or when authentication is not necessary.",
"help_webhook_password": "Specify a password or bearer token",
"help_pager_description": "Shows up as description in pagerduty",
"help_opsgenie_message": "Shows up as message in opsgenie",
"help_opsgenie_priority": "Priority of the incident",
"help_opsgenie_description": "Shows up as description in opsgenie",
"channel_creation_done": "Successfully created the channel",
"channel_creation_failed": "An unexpected error occurred while creating this channel",
"channel_edit_done": "Channels Edited Successfully",

View File

@@ -0,0 +1,3 @@
{
"name_of_the_view": "Name of the view"
}

View File

@@ -0,0 +1 @@
{ "fetching_log_lines": "Fetching log lines" }

View File

@@ -25,6 +25,7 @@
"delete_processor_description": "Logs are processed sequentially in processors. Deleting a processor may change content of data processed by other processors",
"search_pipeline_placeholder": "Filter Pipelines",
"pipeline_name_placeholder": "Name",
"pipeline_filter_placeholder": "Filter for selecting logs to be processed by this pipeline. Example: service_name = billing",
"pipeline_tags_placeholder": "Tags",
"pipeline_description_placeholder": "Enter description for your pipeline",
"processor_name_placeholder": "Name",

View File

@@ -8,7 +8,7 @@
"label_orgname": "Organization Name",
"placeholder_orgname": "Your Company",
"prompt_keepme_posted": "Keep me updated on new SigNoz features",
"prompt_anonymise": "Anonymise my usage date. We collect data to measure product usage",
"prompt_anonymise": "Anonymise my usage data. We collect data to measure product usage",
"failed_confirm_password": "Passwords dont match. Please try again",
"unexpected_error": "Something went wrong",
"failed_to_initiate_login": "Signup completed but failed to initiate login",

View File

@@ -3,11 +3,11 @@
"LOGIN": "SigNoz | Login",
"SERVICE_METRICS": "SigNoz | Service Metrics",
"SERVICE_MAP": "SigNoz | Service Map",
"GET_STARTED": "SigNoz | Get Started",
"TRACE": "SigNoz | Trace",
"TRACE_DETAIL": "SigNoz | Trace Detail",
"TRACES_EXPLORER": "SigNoz | Traces Explorer",
"SETTINGS": "SigNoz | Settings",
"INSTRUMENTATION": "SigNoz | Get Started",
"USAGE_EXPLORER": "SigNoz | Usage Explorer",
"APPLICATION": "SigNoz | Home",
"ALL_DASHBOARD": "SigNoz | All Dashboards",
@@ -29,6 +29,7 @@
"NOT_FOUND": "SigNoz | Page Not Found",
"LOGS": "SigNoz | Logs",
"LOGS_EXPLORER": "SigNoz | Logs Explorer",
"LIVE_LOGS": "SigNoz | Live Logs",
"HOME_PAGE": "Open source Observability Platform | SigNoz",
"PASSWORD_RESET": "SigNoz | Password Reset",
"LIST_LICENSES": "SigNoz | List of Licenses",

View File

@@ -1,20 +1,107 @@
import { ConfigProvider } from 'antd';
import getLocalStorageApi from 'api/browser/localstorage/get';
import setLocalStorageApi from 'api/browser/localstorage/set';
import NotFound from 'components/NotFound';
import Spinner from 'components/Spinner';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import ROUTES from 'constants/routes';
import AppLayout from 'container/AppLayout';
import { useThemeConfig } from 'hooks/useDarkMode';
import useGetFeatureFlag from 'hooks/useGetFeatureFlag';
import { NotificationProvider } from 'hooks/useNotifications';
import { ResourceProvider } from 'hooks/useResourceAttribute';
import history from 'lib/history';
import { QueryBuilderProvider } from 'providers/QueryBuilder';
import { Suspense } from 'react';
import { Suspense, useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Route, Router, Switch } from 'react-router-dom';
import { Dispatch } from 'redux';
import { AppState } from 'store/reducers';
import AppActions from 'types/actions';
import { UPDATE_FEATURE_FLAG_RESPONSE } from 'types/actions/app';
import AppReducer from 'types/reducer/app';
import { trackPageView } from 'utils/segmentAnalytics';
import PrivateRoute from './Private';
import routes from './routes';
import defaultRoutes from './routes';
function App(): JSX.Element {
const themeConfig = useThemeConfig();
const [routes, setRoutes] = useState(defaultRoutes);
const { isLoggedIn: isLoggedInState, user } = useSelector<
AppState,
AppReducer
>((state) => state.app);
const dispatch = useDispatch<Dispatch<AppActions>>();
const { hostname, pathname } = window.location;
const featureResponse = useGetFeatureFlag((allFlags) => {
const isOnboardingEnabled =
allFlags.find((flag) => flag.name === FeatureKeys.ONBOARDING)?.active ||
false;
const isChatSupportEnabled =
allFlags.find((flag) => flag.name === FeatureKeys.CHAT_SUPPORT)?.active ||
false;
dispatch({
type: UPDATE_FEATURE_FLAG_RESPONSE,
payload: {
featureFlag: allFlags,
refetch: featureResponse.refetch,
},
});
if (
!isOnboardingEnabled ||
!(hostname && hostname.endsWith('signoz.cloud'))
) {
const newRoutes = routes.filter(
(route) => route?.path !== ROUTES.GET_STARTED,
);
setRoutes(newRoutes);
}
if (isLoggedInState && isChatSupportEnabled) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.Intercom('boot', {
app_id: process.env.INTERCOM_APP_ID,
email: user?.email || '',
name: user?.name || '',
});
}
});
useEffect(() => {
const isIdentifiedUser = getLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER);
if (
isLoggedInState &&
user &&
user.userId &&
user.email &&
!isIdentifiedUser
) {
setLocalStorageApi(LOCALSTORAGE.IS_IDENTIFIED_USER, 'true');
window.analytics.identify(user?.email, {
email: user?.email,
name: user?.name,
});
window.clarity('identify', user.email, user.name);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isLoggedInState, user]);
useEffect(() => {
trackPageView(pathname);
}, [pathname]);
return (
<ConfigProvider theme={themeConfig}>

View File

@@ -44,6 +44,10 @@ export const GettingStarted = Loadable(
() => import(/* webpackChunkName: "GettingStarted" */ 'pages/GettingStarted'),
);
export const Onboarding = Loadable(
() => import(/* webpackChunkName: "Onboarding" */ 'pages/OnboardingPage'),
);
export const DashboardPage = Loadable(
() => import(/* webpackChunkName: "DashboardPage" */ 'pages/Dashboard'),
);
@@ -110,6 +114,10 @@ export const LogsExplorer = Loadable(
() => import(/* webpackChunkName: "Logs Explorer" */ 'pages/LogsExplorer'),
);
export const LiveLogs = Loadable(
() => import(/* webpackChunkName: "Live Logs" */ 'pages/LiveLogs'),
);
export const Login = Loadable(
() => import(/* webpackChunkName: "Login" */ 'pages/Login'),
);

View File

@@ -1,5 +1,4 @@
import ROUTES from 'constants/routes';
import DashboardWidget from 'pages/DashboardWidget';
import { RouteProps } from 'react-router-dom';
import {
@@ -8,18 +7,20 @@ import {
CreateAlertChannelAlerts,
CreateNewAlerts,
DashboardPage,
DashboardWidget,
EditAlertChannelsAlerts,
EditRulesPage,
ErrorDetails,
GettingStarted,
LicensePage,
ListAllALertsPage,
LiveLogs,
Login,
Logs,
LogsExplorer,
LogsIndexToFields,
MySettings,
NewDashboardPage,
Onboarding,
OrganizationSettings,
PasswordReset,
PipelinePage,
@@ -45,6 +46,13 @@ const routes: AppRoutes[] = [
isPrivate: false,
key: 'SIGN_UP',
},
{
path: ROUTES.GET_STARTED,
exact: true,
component: Onboarding,
isPrivate: true,
key: 'GET_STARTED',
},
{
component: LogsIndexToFields,
path: ROUTES.LOGS_INDEX_FIELDS,
@@ -94,13 +102,6 @@ const routes: AppRoutes[] = [
isPrivate: true,
key: 'USAGE_EXPLORER',
},
{
path: ROUTES.INSTRUMENTATION,
exact: true,
component: GettingStarted,
isPrivate: true,
key: 'INSTRUMENTATION',
},
{
path: ROUTES.ALL_DASHBOARD,
exact: true,
@@ -234,6 +235,13 @@ const routes: AppRoutes[] = [
key: 'LOGS_EXPLORER',
isPrivate: true,
},
{
path: ROUTES.LIVE_LOGS,
exact: true,
component: LiveLogs,
key: 'LIVE_LOGS',
isPrivate: true,
},
{
path: ROUTES.LOGIN,
exact: true,

View File

@@ -1,4 +1,4 @@
import { AxiosAlertManagerInstance } from 'api';
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import convertObjectIntoParams from 'lib/query/convertObjectIntoParams';
@@ -11,15 +11,15 @@ const getTriggered = async (
try {
const queryParams = convertObjectIntoParams(props);
const response = await AxiosAlertManagerInstance.get(
`/alerts?${queryParams}`,
);
const response = await axios.get(`/alerts?${queryParams}`);
const amData = JSON.parse(response.data.data);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data,
payload: amData.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);

View File

@@ -0,0 +1,37 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createOpsgenie';
const create = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post('/channels', {
name: props.name,
opsgenie_configs: [
{
api_key: props.api_key,
description: props.description,
priority: props.priority,
message: props.message,
details: {
...props.detailsArray,
},
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default create;

View File

@@ -0,0 +1,38 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/editOpsgenie';
const editOpsgenie = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.put(`/channels/${props.id}`, {
name: props.name,
opsgenie_configs: [
{
send_resolved: true,
api_key: props.api_key,
description: props.description,
priority: props.priority,
message: props.message,
details: {
...props.detailsArray,
},
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default editOpsgenie;

View File

@@ -0,0 +1,37 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/channels/createOpsgenie';
const testOpsgenie = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post('/testChannel', {
name: props.name,
opsgenie_configs: [
{
api_key: props.api_key,
description: props.description,
priority: props.priority,
message: props.message,
details: {
...props.detailsArray,
},
},
],
});
return {
statusCode: 200,
error: null,
message: 'Success',
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
export default testOpsgenie;

View File

@@ -1,24 +1,8 @@
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';
import { ApiResponse } from 'types/api';
import { Dashboard } 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;
export const getAllDashboardList = (): Promise<Dashboard[]> =>
axios
.get<ApiResponse<Dashboard[]>>('/dashboards')
.then((res) => res.data.data);

View File

@@ -1,24 +1,10 @@
import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps } from 'types/api/features/getFeaturesFlags';
import { ApiResponse } from 'types/api';
import { FeatureFlagProps } from 'types/api/features/getFeaturesFlags';
const getFeaturesFlags = async (): Promise<
SuccessResponse<PayloadProps> | ErrorResponse
> => {
try {
const response = await axios.get(`/featureFlags`);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
}
};
const getFeaturesFlags = (): Promise<FeatureFlagProps[]> =>
axios
.get<ApiResponse<FeatureFlagProps[]>>(`/featureFlags`)
.then((response) => response.data.data);
export default getFeaturesFlags;

View File

@@ -79,7 +79,6 @@ const interceptorRejected = async (
// when refresh token is expired
if (response.status === 401 && response.config.url === '/login') {
console.log('logging out ');
Logout();
}
}

View File

@@ -4,7 +4,7 @@ import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/logs/addToSelectedFields';
const AddToSelectedFields = async (
const addToSelectedFields = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
@@ -16,8 +16,8 @@ const AddToSelectedFields = async (
payload: data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
return Promise.reject(ErrorResponseHandler(error as AxiosError));
}
};
export default AddToSelectedFields;
export default addToSelectedFields;

View File

@@ -4,7 +4,7 @@ import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/logs/addToSelectedFields';
const RemoveSelectedField = async (
const removeSelectedField = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
@@ -16,8 +16,8 @@ const RemoveSelectedField = async (
payload: data.data,
};
} catch (error) {
return ErrorResponseHandler(error as AxiosError);
return Promise.reject(ErrorResponseHandler(error as AxiosError));
}
};
export default RemoveSelectedField;
export default removeSelectedField;

View File

@@ -4,11 +4,11 @@ import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import {
MetricRangePayloadV3,
MetricsRangeProps,
QueryRangePayload,
} from 'types/api/metrics/getQueryRange';
export const getMetricsQueryRange = async (
props: MetricsRangeProps,
props: QueryRangePayload,
): Promise<SuccessResponse<MetricRangePayloadV3> | ErrorResponse> => {
try {
const response = await axios.post('/query_range', props);

View File

@@ -0,0 +1,5 @@
import axios from 'api';
import { DeleteViewPayloadProps } from 'types/api/saveViews/types';
export const deleteView = (uuid: string): Promise<DeleteViewPayloadProps> =>
axios.delete(`explorer/views/${uuid}`);

View File

@@ -0,0 +1,9 @@
import axios from 'api';
import { AxiosResponse } from 'axios';
import { AllViewsProps } from 'types/api/saveViews/types';
import { DataSource } from 'types/common/queryBuilder';
export const getAllViews = (
sourcepage: DataSource,
): Promise<AxiosResponse<AllViewsProps>> =>
axios.get(`explorer/views?sourcePage=${sourcepage}`);

View File

@@ -0,0 +1,16 @@
import axios from 'api';
import { AxiosResponse } from 'axios';
import { SaveViewPayloadProps, SaveViewProps } from 'types/api/saveViews/types';
export const saveView = ({
compositeQuery,
sourcePage,
viewName,
extraData,
}: SaveViewProps): Promise<AxiosResponse<SaveViewPayloadProps>> =>
axios.post('explorer/views', {
name: viewName,
sourcePage,
compositeQuery,
extraData,
});

View File

@@ -0,0 +1,19 @@
import axios from 'api';
import {
UpdateViewPayloadProps,
UpdateViewProps,
} from 'types/api/saveViews/types';
export const updateView = ({
compositeQuery,
viewName,
extraData,
sourcePage,
viewKey,
}: UpdateViewProps): Promise<UpdateViewPayloadProps> =>
axios.put(`explorer/views/${viewKey}`, {
name: viewName,
compositeQuery,
extraData,
sourcePage,
});

View File

@@ -2,14 +2,12 @@ import axios from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import * as loginPrecheck from 'types/api/user/loginPrecheck';
import { PayloadProps } from 'types/api/user/loginPrecheck';
import { Props } from 'types/api/user/signup';
const signup = async (
props: Props,
): Promise<
SuccessResponse<null | loginPrecheck.PayloadProps> | ErrorResponse
> => {
): Promise<SuccessResponse<null | PayloadProps> | ErrorResponse> => {
try {
const response = await axios.post(`/register`, {
...props,

View File

@@ -14,7 +14,11 @@ import {
export const Logout = (): void => {
deleteLocalStorageKey(LOCALSTORAGE.AUTH_TOKEN);
deleteLocalStorageKey(LOCALSTORAGE.IS_LOGGED_IN);
deleteLocalStorageKey(LOCALSTORAGE.IS_IDENTIFIED_USER);
deleteLocalStorageKey(LOCALSTORAGE.REFRESH_AUTH_TOKEN);
deleteLocalStorageKey(LOCALSTORAGE.LOGGED_IN_USER_EMAIL);
deleteLocalStorageKey(LOCALSTORAGE.LOGGED_IN_USER_NAME);
deleteLocalStorageKey(LOCALSTORAGE.CHAT_SUPPORT);
store.dispatch({
type: LOGGED_IN,
@@ -60,5 +64,9 @@ export const Logout = (): void => {
},
});
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.Intercom('shutdown');
history.push(ROUTES.LOGIN);
};

View File

@@ -0,0 +1,244 @@
import {
DeleteOutlined,
MoreOutlined,
SaveOutlined,
ShareAltOutlined,
} from '@ant-design/icons';
import {
Button,
Card,
Col,
Dropdown,
MenuProps,
Popover,
Row,
Select,
Space,
Typography,
} from 'antd';
import axios from 'axios';
import TextToolTip from 'components/TextToolTip';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { QueryParams } from 'constants/query';
import { useGetSearchQueryParam } from 'hooks/queryBuilder/useGetSearchQueryParam';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useDeleteView } from 'hooks/saveViews/useDeleteView';
import { useGetAllViews } from 'hooks/saveViews/useGetAllViews';
import { useUpdateView } from 'hooks/saveViews/useUpdateView';
import useErrorNotification from 'hooks/useErrorNotification';
import { useNotifications } from 'hooks/useNotifications';
import { mapCompositeQueryFromQuery } from 'lib/newQueryBuilder/queryBuilderMappers/mapCompositeQueryFromQuery';
import { useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import { popupContainer } from 'utils/selectPopupContainer';
import { ExploreHeaderToolTip, SaveButtonText } from './constants';
import MenuItemGenerator from './MenuItemGenerator';
import SaveViewWithName from './SaveViewWithName';
import {
DropDownOverlay,
ExplorerCardHeadContainer,
OffSetCol,
} from './styles';
import { ExplorerCardProps } from './types';
import { deleteViewHandler } from './utils';
function ExplorerCard({
sourcepage,
children,
}: ExplorerCardProps): JSX.Element {
const [isOpen, setIsOpen] = useState<boolean>(false);
const [, setCopyUrl] = useCopyToClipboard();
const { notifications } = useNotifications();
const onCopyUrlHandler = (): void => {
setCopyUrl(window.location.href);
notifications.success({
message: 'Copied to clipboard',
});
};
const {
currentQuery,
panelType,
redirectWithQueryBuilderData,
updateAllQueriesOperators,
isStagedQueryUpdated,
} = useQueryBuilder();
const {
data: viewsData,
isLoading,
error,
isRefetching,
refetch: refetchAllView,
} = useGetAllViews(sourcepage);
useErrorNotification(error);
const handleOpenChange = (newOpen = false): void => {
setIsOpen(newOpen);
};
const viewName = useGetSearchQueryParam(QueryParams.viewName) || '';
const viewKey = useGetSearchQueryParam(QueryParams.viewKey) || '';
const isQueryUpdated = isStagedQueryUpdated(viewsData?.data?.data, viewKey);
const { mutateAsync: updateViewAsync } = useUpdateView({
compositeQuery: mapCompositeQueryFromQuery(currentQuery, panelType),
viewKey,
extraData: '',
sourcePage: sourcepage,
viewName,
});
const { mutateAsync: deleteViewAsync } = useDeleteView(viewKey);
const showErrorNotification = (err: Error): void => {
notifications.error({
message: axios.isAxiosError(err) ? err.message : SOMETHING_WENT_WRONG,
});
};
const onDeleteHandler = (): void =>
deleteViewHandler({
deleteViewAsync,
notifications,
panelType,
redirectWithQueryBuilderData,
refetchAllView,
viewId: viewKey,
viewKey,
updateAllQueriesOperators,
sourcePage: sourcepage,
});
const onUpdateQueryHandler = (): void => {
updateViewAsync(
{
compositeQuery: mapCompositeQueryFromQuery(currentQuery, panelType),
viewKey,
extraData: '',
sourcePage: sourcepage,
viewName,
},
{
onSuccess: () => {
notifications.success({
message: 'View Updated Successfully',
});
refetchAllView();
},
onError: (err) => {
showErrorNotification(err);
},
},
);
};
const moreOptionMenu: MenuProps = {
items: [
{
key: 'delete',
label: <Typography.Text strong>Delete</Typography.Text>,
onClick: onDeleteHandler,
icon: <DeleteOutlined />,
},
],
};
const saveButtonType = isQueryUpdated ? 'default' : 'primary';
const saveButtonIcon = isQueryUpdated ? null : <SaveOutlined />;
return (
<>
<ExplorerCardHeadContainer size="small">
<Row align="middle">
<Col span={6}>
<Space>
<Typography>Query Builder</Typography>
<TextToolTip
url={ExploreHeaderToolTip.url}
text={ExploreHeaderToolTip.text}
useFilledIcon={false}
/>
</Space>
</Col>
<OffSetCol span={18}>
<Space size="large">
{viewsData?.data.data && viewsData?.data.data.length && (
<Space>
<Select
getPopupContainer={popupContainer}
loading={isLoading || isRefetching}
showSearch
placeholder="Select a view"
dropdownStyle={DropDownOverlay}
dropdownMatchSelectWidth={false}
optionLabelProp="value"
value={viewName || undefined}
>
{viewsData?.data.data.map((view) => (
<Select.Option key={view.uuid} value={view.name}>
<MenuItemGenerator
viewName={view.name}
viewKey={viewKey}
createdBy={view.createdBy}
uuid={view.uuid}
refetchAllView={refetchAllView}
viewData={viewsData.data.data}
sourcePage={sourcepage}
/>
</Select.Option>
))}
</Select>
</Space>
)}
{isQueryUpdated && (
<Button
type="primary"
icon={<SaveOutlined />}
onClick={onUpdateQueryHandler}
>
Save changes
</Button>
)}
<Popover
getPopupContainer={popupContainer}
placement="bottomLeft"
trigger="click"
content={
<SaveViewWithName
sourcePage={sourcepage}
handlePopOverClose={handleOpenChange}
refetchAllView={refetchAllView}
/>
}
showArrow={false}
open={isOpen}
onOpenChange={handleOpenChange}
>
<Button type={saveButtonType} icon={saveButtonIcon}>
{isQueryUpdated
? SaveButtonText.SAVE_AS_NEW_VIEW
: SaveButtonText.SAVE_VIEW}
</Button>
</Popover>
<ShareAltOutlined onClick={onCopyUrlHandler} />
{viewKey && (
<Dropdown trigger={['click']} menu={moreOptionMenu}>
<MoreOutlined />
</Dropdown>
)}
</Space>
</OffSetCol>
</Row>
</ExplorerCardHeadContainer>
<Card>{children}</Card>
</>
);
}
export default ExplorerCard;

View File

@@ -0,0 +1,103 @@
import { DeleteOutlined } from '@ant-design/icons';
import { Col, Row, Tooltip, Typography } from 'antd';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useDeleteView } from 'hooks/saveViews/useDeleteView';
import { useHandleExplorerTabChange } from 'hooks/useHandleExplorerTabChange';
import { useNotifications } from 'hooks/useNotifications';
import { MouseEvent, useCallback } from 'react';
import { MenuItemContainer } from './styles';
import { MenuItemLabelGeneratorProps } from './types';
import {
deleteViewHandler,
getViewDetailsUsingViewKey,
trimViewName,
} from './utils';
function MenuItemGenerator({
viewName,
viewKey,
createdBy,
uuid,
viewData,
refetchAllView,
sourcePage,
}: MenuItemLabelGeneratorProps): JSX.Element {
const {
panelType,
redirectWithQueryBuilderData,
updateAllQueriesOperators,
} = useQueryBuilder();
const { handleExplorerTabChange } = useHandleExplorerTabChange();
const { notifications } = useNotifications();
const { mutateAsync: deleteViewAsync } = useDeleteView(uuid);
const onDeleteHandler = (event: MouseEvent<HTMLElement>): void => {
event.stopPropagation();
deleteViewHandler({
deleteViewAsync,
notifications,
panelType,
redirectWithQueryBuilderData,
refetchAllView,
viewId: uuid,
viewKey,
updateAllQueriesOperators,
sourcePage,
});
};
const onMenuItemSelectHandler = useCallback(
({ key }: { key: string }): void => {
const currentViewDetails = getViewDetailsUsingViewKey(key, viewData);
if (!currentViewDetails) return;
const {
query,
name,
uuid,
panelType: currentPanelType,
} = currentViewDetails;
handleExplorerTabChange(currentPanelType, {
query,
name,
uuid,
});
},
[viewData, handleExplorerTabChange],
);
const onLabelClickHandler = (): void => {
onMenuItemSelectHandler({
key: uuid,
});
};
const newViewName = trimViewName(viewName);
return (
<MenuItemContainer onClick={onLabelClickHandler}>
<Row justify="space-between">
<Col span={22}>
<Row>
<Tooltip title={viewName}>
<Typography.Text strong>{newViewName}</Typography.Text>
</Tooltip>
</Row>
<Row>
<Typography.Text type="secondary">Created by {createdBy}</Typography.Text>
</Row>
</Col>
<Col span={2}>
<Typography.Link>
<DeleteOutlined onClick={onDeleteHandler} />
</Typography.Link>
</Col>
</Row>
</MenuItemContainer>
);
}
export default MenuItemGenerator;

View File

@@ -0,0 +1,76 @@
import { Card, Form, Input, Typography } from 'antd';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';
import { useSaveView } from 'hooks/saveViews/useSaveView';
import { useNotifications } from 'hooks/useNotifications';
import { mapCompositeQueryFromQuery } from 'lib/newQueryBuilder/queryBuilderMappers/mapCompositeQueryFromQuery';
import { useTranslation } from 'react-i18next';
import { SaveButton } from './styles';
import { SaveViewFormProps, SaveViewWithNameProps } from './types';
import { saveViewHandler } from './utils';
function SaveViewWithName({
sourcePage,
handlePopOverClose,
refetchAllView,
}: SaveViewWithNameProps): JSX.Element {
const [form] = Form.useForm<SaveViewFormProps>();
const { t } = useTranslation(['explorer']);
const {
currentQuery,
panelType,
redirectWithQueryBuilderData,
} = useQueryBuilder();
const { notifications } = useNotifications();
const compositeQuery = mapCompositeQueryFromQuery(currentQuery, panelType);
const { isLoading, mutateAsync: saveViewAsync } = useSaveView({
viewName: form.getFieldValue('viewName'),
compositeQuery,
sourcePage,
extraData: '',
});
const onSaveHandler = (): void => {
saveViewHandler({
compositeQuery,
handlePopOverClose,
extraData: '',
notifications,
panelType: panelType || PANEL_TYPES.LIST,
redirectWithQueryBuilderData,
refetchAllView,
saveViewAsync,
sourcePage,
viewName: form.getFieldValue('viewName'),
form,
});
};
return (
<Card>
<Typography>{t('name_of_the_view')}</Typography>
<Form form={form} onFinish={onSaveHandler}>
<Form.Item
name={['viewName']}
required
requiredMark
rules={[
{
required: true,
message: 'Please enter view name',
},
]}
>
<Input placeholder="Enter Name" />
</Form.Item>
<SaveButton htmlType="submit" type="primary" loading={isLoading}>
Save
</SaveButton>
</Form>
</Card>
);
}
export default SaveViewWithName;

View File

@@ -0,0 +1,32 @@
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
import { ViewProps } from 'types/api/saveViews/types';
import { DataSource } from 'types/common/queryBuilder';
export const viewMockData: ViewProps[] = [
{
uuid: 'view1',
name: 'View 1',
createdBy: 'User 1',
category: 'category 1',
compositeQuery: {} as ICompositeMetricQuery,
createdAt: '2021-07-07T06:31:00.000Z',
updatedAt: '2021-07-07T06:33:00.000Z',
extraData: '',
sourcePage: DataSource.TRACES,
tags: [],
updatedBy: 'User 1',
},
{
uuid: 'view2',
name: 'View 2',
createdBy: 'User 2',
category: 'category 2',
compositeQuery: {} as ICompositeMetricQuery,
createdAt: '2021-07-07T06:30:00.000Z',
updatedAt: '2021-07-07T06:30:00.000Z',
extraData: '',
sourcePage: DataSource.TRACES,
tags: [],
updatedBy: 'User 2',
},
];

View File

@@ -0,0 +1,14 @@
import { QueryParams } from 'constants/query';
export const ExploreHeaderToolTip = {
url:
'https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=new-query-builder',
text: 'More details on how to use query builder',
};
export const SaveButtonText = {
SAVE_AS_NEW_VIEW: 'Save as new view',
SAVE_VIEW: 'Save view',
};
export type QuerySearchParamNames = QueryParams.viewName | QueryParams.viewKey;

View File

@@ -1,27 +0,0 @@
import { Card, Space, Typography } from 'antd';
import TextToolTip from 'components/TextToolTip';
function ExplorerCard({ children }: Props): JSX.Element {
return (
<Card
size="small"
title={
<Space>
<Typography>Query Builder</Typography>
<TextToolTip
url="https://signoz.io/docs/userguide/query-builder/?utm_source=product&utm_medium=new-query-builder"
text="More details on how to use query builder"
/>
</Space>
}
>
{children}
</Card>
);
}
interface Props {
children: React.ReactNode;
}
export default ExplorerCard;

View File

@@ -0,0 +1,28 @@
import { Button, Card, Col } from 'antd';
import styled, { CSSProperties } from 'styled-components';
export const ExplorerCardHeadContainer = styled(Card)`
margin: 1rem 0;
`;
export const OffSetCol = styled(Col)`
text-align: right;
`;
export const SaveButton = styled(Button)`
&&& {
margin: 1rem 0;
width: 5rem;
}
`;
export const DropDownOverlay: CSSProperties = {
maxHeight: '20rem',
overflowY: 'auto',
width: '20rem',
padding: 0,
};
export const MenuItemContainer = styled(Card)`
padding: 0;
`;

View File

@@ -0,0 +1,73 @@
import { fireEvent, render, screen } from '@testing-library/react';
import ROUTES from 'constants/routes';
import MockQueryClientProvider from 'providers/test/MockQueryClientProvider';
import { DataSource } from 'types/common/queryBuilder';
import { viewMockData } from '../__mock__/viewData';
import ExplorerCard from '../ExplorerCard';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: (): { pathname: string } => ({
pathname: `${process.env.FRONTEND_API_ENDPOINT}/${ROUTES.TRACES_EXPLORER}/`,
}),
}));
jest.mock('hooks/queryBuilder/useGetPanelTypesQueryParam', () => ({
useGetPanelTypesQueryParam: jest.fn(() => 'mockedPanelType'),
}));
jest.mock('hooks/saveViews/useGetAllViews', () => ({
useGetAllViews: jest.fn(() => ({
data: { data: { data: viewMockData } },
isLoading: false,
error: null,
isRefetching: false,
refetch: jest.fn(),
})),
}));
jest.mock('hooks/saveViews/useUpdateView', () => ({
useUpdateView: jest.fn(() => ({
mutateAsync: jest.fn(),
})),
}));
jest.mock('hooks/saveViews/useDeleteView', () => ({
useDeleteView: jest.fn(() => ({
mutateAsync: jest.fn(),
})),
}));
describe('ExplorerCard', () => {
it('renders a card with a title and a description', () => {
render(
<MockQueryClientProvider>
<ExplorerCard sourcepage={DataSource.TRACES}>child</ExplorerCard>
</MockQueryClientProvider>,
);
expect(screen.getByText('Query Builder')).toBeInTheDocument();
});
it('renders a save view button', () => {
render(
<MockQueryClientProvider>
<ExplorerCard sourcepage={DataSource.TRACES}>child</ExplorerCard>
</MockQueryClientProvider>,
);
expect(screen.getByText('Save view')).toBeInTheDocument();
});
it('should see all the view listed in dropdown', async () => {
const screen = render(
<ExplorerCard sourcepage={DataSource.TRACES}>Mock Children</ExplorerCard>,
);
const selectPlaceholder = screen.getByText('Select a view');
fireEvent.mouseDown(selectPlaceholder);
const viewNameText = await screen.getAllByText('View 1');
viewNameText.forEach((element) => {
expect(element).toBeInTheDocument();
});
});
});

View File

@@ -0,0 +1,62 @@
import { render, screen } from '@testing-library/react';
import ROUTES from 'constants/routes';
import MockQueryClientProvider from 'providers/test/MockQueryClientProvider';
import { DataSource } from 'types/common/queryBuilder';
import { viewMockData } from '../__mock__/viewData';
import MenuItemGenerator from '../MenuItemGenerator';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: (): { pathname: string } => ({
pathname: `${process.env.FRONTEND_API_ENDPOINT}${ROUTES.APPLICATION}/`,
}),
}));
jest.mock('antd/es/form/Form', () => ({
useForm: jest.fn().mockReturnValue({
onFinish: jest.fn(),
}),
}));
describe('MenuItemGenerator', () => {
it('should render MenuItemGenerator component', () => {
const screen = render(
<MockQueryClientProvider>
<MenuItemGenerator
viewName={viewMockData[0].name}
viewKey={viewMockData[0].uuid}
createdBy={viewMockData[0].createdBy}
uuid={viewMockData[0].uuid}
refetchAllView={jest.fn()}
viewData={viewMockData}
sourcePage={DataSource.TRACES}
/>
</MockQueryClientProvider>,
);
expect(screen.getByText(viewMockData[0].name)).toBeInTheDocument();
});
it('should call onMenuItemSelectHandler on click of MenuItemGenerator', () => {
render(
<MockQueryClientProvider>
<MenuItemGenerator
viewName={viewMockData[0].name}
viewKey={viewMockData[0].uuid}
createdBy={viewMockData[0].createdBy}
uuid={viewMockData[0].uuid}
refetchAllView={jest.fn()}
viewData={viewMockData}
sourcePage={DataSource.TRACES}
/>
</MockQueryClientProvider>,
);
const spanElement = screen.getByRole('img', {
name: 'delete',
});
expect(spanElement).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,63 @@
import { fireEvent, render } from '@testing-library/react';
import ROUTES from 'constants/routes';
import { QueryClient, QueryClientProvider } from 'react-query';
import { DataSource } from 'types/common/queryBuilder';
import SaveViewWithName from '../SaveViewWithName';
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useLocation: (): { pathname: string } => ({
pathname: `${process.env.FRONTEND_API_ENDPOINT}${ROUTES.APPLICATION}/`,
}),
}));
const queryClient = new QueryClient({
defaultOptions: {
queries: {
refetchOnWindowFocus: false,
},
},
});
jest.mock('hooks/queryBuilder/useGetPanelTypesQueryParam', () => ({
useGetPanelTypesQueryParam: jest.fn(() => 'mockedPanelType'),
}));
jest.mock('hooks/saveViews/useSaveView', () => ({
useSaveView: jest.fn(() => ({
mutateAsync: jest.fn(),
})),
}));
describe('SaveViewWithName', () => {
it('should render SaveViewWithName component', () => {
const screen = render(
<QueryClientProvider client={queryClient}>
<SaveViewWithName
sourcePage={DataSource.TRACES}
handlePopOverClose={jest.fn()}
refetchAllView={jest.fn()}
/>
</QueryClientProvider>,
);
expect(screen.getByText('Save')).toBeInTheDocument();
});
it('should call saveViewAsync on click of Save button', () => {
const screen = render(
<QueryClientProvider client={queryClient}>
<SaveViewWithName
sourcePage={DataSource.TRACES}
handlePopOverClose={jest.fn()}
refetchAllView={jest.fn()}
/>
</QueryClientProvider>,
);
fireEvent.click(screen.getByText('Save'));
expect(screen.getByText('Save')).toBeInTheDocument();
});
});

View File

@@ -0,0 +1,84 @@
import { FormInstance } from 'antd';
import { NotificationInstance } from 'antd/es/notification/interface';
import { AxiosResponse } from 'axios';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { UseMutateAsyncFunction } from 'react-query';
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
import { Query } from 'types/api/queryBuilder/queryBuilderData';
import {
DeleteViewPayloadProps,
SaveViewPayloadProps,
SaveViewProps,
ViewProps,
} from 'types/api/saveViews/types';
import { DataSource, QueryBuilderContextType } from 'types/common/queryBuilder';
export interface ExplorerCardProps {
sourcepage: DataSource;
children: React.ReactNode;
}
export type GetViewDetailsUsingViewKey = (
viewKey: string,
data: ViewProps[] | undefined,
) =>
| { query: Query; name: string; uuid: string; panelType: PANEL_TYPES }
| undefined;
export interface IsQueryUpdatedInViewProps {
viewKey: string;
data: ViewProps[] | undefined;
stagedQuery: Query | null;
currentPanelType: PANEL_TYPES | null;
}
export interface SaveViewWithNameProps {
sourcePage: ExplorerCardProps['sourcepage'];
handlePopOverClose: VoidFunction;
refetchAllView: VoidFunction;
}
export interface SaveViewFormProps {
viewName: string;
}
export interface MenuItemLabelGeneratorProps {
viewName: string;
viewKey: string;
createdBy: string;
uuid: string;
viewData: ViewProps[];
refetchAllView: VoidFunction;
sourcePage: ExplorerCardProps['sourcepage'];
}
export interface SaveViewHandlerProps {
viewName: string;
compositeQuery: ICompositeMetricQuery;
sourcePage: ExplorerCardProps['sourcepage'];
extraData: string;
panelType: PANEL_TYPES | null;
notifications: NotificationInstance;
refetchAllView: SaveViewWithNameProps['refetchAllView'];
saveViewAsync: UseMutateAsyncFunction<
AxiosResponse<SaveViewPayloadProps>,
Error,
SaveViewProps,
SaveViewPayloadProps
>;
handlePopOverClose: SaveViewWithNameProps['handlePopOverClose'];
redirectWithQueryBuilderData: QueryBuilderContextType['redirectWithQueryBuilderData'];
form: FormInstance<SaveViewFormProps>;
}
export interface DeleteViewHandlerProps {
deleteViewAsync: UseMutateAsyncFunction<DeleteViewPayloadProps, Error, string>;
refetchAllView: MenuItemLabelGeneratorProps['refetchAllView'];
redirectWithQueryBuilderData: QueryBuilderContextType['redirectWithQueryBuilderData'];
notifications: NotificationInstance;
panelType: PANEL_TYPES | null;
viewKey: string;
viewId: string;
updateAllQueriesOperators: QueryBuilderContextType['updateAllQueriesOperators'];
sourcePage: ExplorerCardProps['sourcepage'];
}

View File

@@ -0,0 +1,183 @@
import { NotificationInstance } from 'antd/es/notification/interface';
import axios from 'axios';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { QueryParams } from 'constants/query';
import { initialQueriesMap, PANEL_TYPES } from 'constants/queryBuilder';
import { mapQueryDataFromApi } from 'lib/newQueryBuilder/queryBuilderMappers/mapQueryDataFromApi';
import isEqual from 'lodash-es/isEqual';
import {
DeleteViewHandlerProps,
GetViewDetailsUsingViewKey,
IsQueryUpdatedInViewProps,
SaveViewHandlerProps,
} from './types';
const showErrorNotification = (
notifications: NotificationInstance,
err: Error,
): void => {
notifications.error({
message: axios.isAxiosError(err) ? err.message : SOMETHING_WENT_WRONG,
});
};
export const getViewDetailsUsingViewKey: GetViewDetailsUsingViewKey = (
viewKey,
data,
) => {
const selectedView = data?.find((view) => view.uuid === viewKey);
if (selectedView) {
const { compositeQuery, name, uuid } = selectedView;
const query = mapQueryDataFromApi(compositeQuery);
return { query, name, uuid, panelType: compositeQuery.panelType };
}
return undefined;
};
export const isQueryUpdatedInView = ({
viewKey,
data,
stagedQuery,
currentPanelType,
}: IsQueryUpdatedInViewProps): boolean => {
const currentViewDetails = getViewDetailsUsingViewKey(viewKey, data);
if (!currentViewDetails) {
return false;
}
const { query, panelType } = currentViewDetails;
// Omitting id from aggregateAttribute and groupBy
const updatedCurrentQuery = {
...stagedQuery,
builder: {
...stagedQuery?.builder,
queryData: stagedQuery?.builder.queryData.map((queryData) => {
const { id, ...rest } = queryData.aggregateAttribute;
const newAggregateAttribute = rest;
const newGroupByAttributes = queryData.groupBy.map((groupByAttribute) => {
const { id, ...rest } = groupByAttribute;
return rest;
});
const newItems = queryData.filters.items.map((item) => {
const { id, ...newItem } = item;
if (item.key) {
const { id, ...rest } = item.key;
return {
...newItem,
key: rest,
};
}
return newItem;
});
return {
...queryData,
aggregateAttribute: newAggregateAttribute,
groupBy: newGroupByAttributes,
filters: {
...queryData.filters,
items: newItems,
},
limit: queryData.limit ? queryData.limit : 0,
offset: queryData.offset ? queryData.offset : 0,
pageSize: queryData.pageSize ? queryData.pageSize : 0,
};
}),
},
};
return (
panelType !== currentPanelType ||
!isEqual(query.builder, updatedCurrentQuery?.builder) ||
!isEqual(query.clickhouse_sql, updatedCurrentQuery?.clickhouse_sql) ||
!isEqual(query.promql, updatedCurrentQuery?.promql)
);
};
export const saveViewHandler = ({
saveViewAsync,
refetchAllView,
notifications,
handlePopOverClose,
viewName,
compositeQuery,
sourcePage,
extraData,
redirectWithQueryBuilderData,
panelType,
form,
}: SaveViewHandlerProps): void => {
saveViewAsync(
{
viewName,
compositeQuery,
sourcePage,
extraData,
},
{
onSuccess: (data) => {
refetchAllView();
redirectWithQueryBuilderData(mapQueryDataFromApi(compositeQuery), {
[QueryParams.panelTypes]: panelType,
[QueryParams.viewName]: viewName,
[QueryParams.viewKey]: data.data.data,
});
notifications.success({
message: 'View Saved Successfully',
});
},
onError: (err) => {
showErrorNotification(notifications, err);
},
onSettled: () => {
handlePopOverClose();
form.resetFields();
},
},
);
};
export const deleteViewHandler = ({
deleteViewAsync,
refetchAllView,
redirectWithQueryBuilderData,
notifications,
panelType,
viewKey,
viewId,
updateAllQueriesOperators,
sourcePage,
}: DeleteViewHandlerProps): void => {
deleteViewAsync(viewKey, {
onSuccess: () => {
if (viewId === viewKey) {
redirectWithQueryBuilderData(
updateAllQueriesOperators(
initialQueriesMap.traces,
panelType || PANEL_TYPES.LIST,
sourcePage,
),
{
[QueryParams.viewName]: '',
[QueryParams.panelTypes]: panelType,
[QueryParams.viewKey]: '',
},
);
}
notifications.success({
message: 'View Deleted Successfully',
});
refetchAllView();
},
onError: (err) => {
showErrorNotification(notifications, err);
},
});
};
export const trimViewName = (viewName: string): string => {
if (viewName.length > 20) {
return `${viewName.substring(0, 20)}...`;
}
return viewName;
};

View File

@@ -1,5 +1,5 @@
import { Chart, ChartTypeRegistry, Plugin } from 'chart.js';
import * as ChartHelpers from 'chart.js/helpers';
import { getRelativePosition } from 'chart.js/helpers';
// utils
import { ChartEventHandler, mergeDefaultOptions } from './utils';
@@ -45,7 +45,7 @@ function createMousedownHandler(
return (ev): void => {
const { left, right } = chart.chartArea;
let { x: startDragPositionX } = ChartHelpers.getRelativePosition(ev, chart);
let { x: startDragPositionX } = getRelativePosition(ev, chart);
if (left > startDragPositionX) {
startDragPositionX = left;
@@ -74,7 +74,7 @@ function createMousemoveHandler(
const { left, right } = chart.chartArea;
let { x: dragPositionX } = ChartHelpers.getRelativePosition(ev, chart);
let { x: dragPositionX } = getRelativePosition(ev, chart);
if (left > dragPositionX) {
dragPositionX = left;
@@ -99,7 +99,7 @@ function createMouseupHandler(
return (ev): void => {
const { left, right } = chart.chartArea;
let { x: endRelativePostionX } = ChartHelpers.getRelativePosition(ev, chart);
let { x: endRelativePostionX } = getRelativePosition(ev, chart);
if (left > endRelativePostionX) {
endRelativePostionX = left;

View File

@@ -1,5 +1,5 @@
import { Chart, ChartEvent, ChartTypeRegistry, Plugin } from 'chart.js';
import * as ChartHelpers from 'chart.js/helpers';
import { getRelativePosition } from 'chart.js/helpers';
// utils
import { ChartEventHandler, mergeDefaultOptions } from './utils';
@@ -42,7 +42,7 @@ function createMousemoveHandler(
return (ev: ChartEvent | MouseEvent): void => {
const { left, right, top, bottom } = chart.chartArea;
let { x, y } = ChartHelpers.getRelativePosition(ev, chart);
let { x, y } = getRelativePosition(ev, chart);
if (left > x) {
x = left;

View File

@@ -21,8 +21,6 @@ import {
useMemo,
useState,
} from 'react';
// interfaces
import { ILog } from 'types/api/logs/log';
// styles
import {
@@ -31,19 +29,17 @@ import {
RawLogContent,
RawLogViewContainer,
} from './styles';
import { RawLogViewProps } from './types';
const convert = new Convert();
interface RawLogViewProps {
isActiveLog?: boolean;
isReadOnly?: boolean;
data: ILog;
linesPerRow: number;
}
function RawLogView(props: RawLogViewProps): JSX.Element {
const { isActiveLog = false, isReadOnly = false, data, linesPerRow } = props;
function RawLogView({
isActiveLog,
isReadOnly,
data,
linesPerRow,
isTextOverflowEllipsisDisabled,
}: RawLogViewProps): JSX.Element {
const { isHighlighted, isLogsExplorerPage, onLogCopy } = useCopyLogLink(
data.id,
);
@@ -64,12 +60,14 @@ function RawLogView(props: RawLogViewProps): JSX.Element {
const isDarkMode = useIsDarkMode();
const isReadOnlyLog = !isLogsExplorerPage || isReadOnly;
const severityText = data.severity_text ? `${data.severity_text} |` : '';
const text = useMemo(
() =>
typeof data.timestamp === 'string'
? `${dayjs(data.timestamp).format()} | ${data.body}`
: `${dayjs(data.timestamp / 1e6).format()} | ${data.body}`,
[data.timestamp, data.body],
? `${dayjs(data.timestamp).format()} | ${severityText} ${data.body}`
: `${dayjs(data.timestamp / 1e6).format()} | ${severityText} ${data.body}`,
[data.timestamp, data.body, severityText],
);
const handleClickExpand = useCallback(() => {
@@ -118,11 +116,6 @@ function RawLogView(props: RawLogViewProps): JSX.Element {
[text],
);
const mouseActions = useMemo(
() => ({ onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave }),
[handleMouseEnter, handleMouseLeave],
);
return (
<RawLogViewContainer
onClick={handleClickExpand}
@@ -131,8 +124,8 @@ function RawLogView(props: RawLogViewProps): JSX.Element {
$isDarkMode={isDarkMode}
$isReadOnly={isReadOnly}
$isActiveLog={isHighlighted}
// eslint-disable-next-line react/jsx-props-no-spreading
{...mouseActions}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{!isReadOnly && (
<ExpandIconWrapper flex="30px">
@@ -143,6 +136,7 @@ function RawLogView(props: RawLogViewProps): JSX.Element {
<RawLogContent
$isReadOnly={isReadOnly}
$isActiveLog={isActiveLog}
$isTextOverflowEllipsisDisabled={isTextOverflowEllipsisDisabled}
linesPerRow={linesPerRow}
dangerouslySetInnerHTML={html}
/>
@@ -181,6 +175,7 @@ function RawLogView(props: RawLogViewProps): JSX.Element {
RawLogView.defaultProps = {
isActiveLog: false,
isReadOnly: false,
isTextOverflowEllipsisDisabled: false,
};
export default RawLogView;

View File

@@ -3,10 +3,12 @@ import { Col, Row, Space } from 'antd';
import styled from 'styled-components';
import { getActiveLogBackground, getDefaultLogBackground } from 'utils/logs';
import { RawLogContentProps } from './types';
export const RawLogViewContainer = styled(Row)<{
$isDarkMode: boolean;
$isReadOnly: boolean;
$isActiveLog: boolean;
$isReadOnly?: boolean;
$isActiveLog?: boolean;
}>`
position: relative;
width: 100%;
@@ -31,32 +33,29 @@ export const ExpandIconWrapper = styled(Col)`
font-size: 12px;
`;
interface RawLogContentProps {
linesPerRow: number;
$isReadOnly: boolean;
$isActiveLog: boolean;
}
export const RawLogContent = styled.div<RawLogContentProps>`
margin-bottom: 0;
font-family: Fira Code, monospace;
font-weight: 300;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: ${(props): number => props.linesPerRow};
line-clamp: ${(props): number => props.linesPerRow};
-webkit-box-orient: vertical;
${({ $isTextOverflowEllipsisDisabled, linesPerRow }): string =>
$isTextOverflowEllipsisDisabled
? 'white-space: nowrap'
: `overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: ${linesPerRow};
line-clamp: ${linesPerRow};
-webkit-box-orient: vertical;`};
font-size: 1rem;
line-height: 2rem;
cursor: ${(props): string =>
props.$isActiveLog || props.$isReadOnly ? 'initial' : 'pointer'};
cursor: ${({ $isActiveLog, $isReadOnly }): string =>
$isActiveLog || $isReadOnly ? 'initial' : 'pointer'};
${(props): string =>
props.$isReadOnly && !props.$isActiveLog ? 'padding: 0 1.5rem;' : ''}
${({ $isActiveLog, $isReadOnly }): string =>
$isReadOnly && $isActiveLog ? 'padding: 0 1.5rem;' : ''}
`;
export const ActionButtonsWrapper = styled(Space)`

View File

@@ -0,0 +1,16 @@
import { ILog } from 'types/api/logs/log';
export interface RawLogViewProps {
isActiveLog?: boolean;
isReadOnly?: boolean;
isTextOverflowEllipsisDisabled?: boolean;
data: ILog;
linesPerRow: number;
}
export interface RawLogContentProps {
linesPerRow: number;
$isReadOnly?: boolean;
$isActiveLog?: boolean;
$isTextOverflowEllipsisDisabled?: boolean;
}

View File

@@ -0,0 +1,34 @@
.code-snippet-container {
position: relative;
background-color: rgb(43, 43, 43);
}
.code-copy-btn {
position: absolute;
top: 8px;
right: 8px;
display: flex;
justify-content: flex-end;
align-items: center;
button {
cursor: pointer;
background-color: rgba($color: #1d1d1d, $alpha: 0.7);
color: white;
border: none;
padding: 8px;
border-radius: 3px;
transition: all 0.1s;
&:hover {
background-color: rgba($color: #1d1d1d, $alpha: 1);
}
}
&.copied {
button {
background-color: rgba($color: #52c41a, $alpha: 1);
}
}
}

View File

@@ -0,0 +1,32 @@
import './CodeCopyBtn.scss';
import { CheckOutlined, CopyOutlined } from '@ant-design/icons';
import cx from 'classnames';
import { useState } from 'react';
export default function CodeCopyBtn({
children,
}: {
children: React.ReactNode;
}): JSX.Element {
const [isSnippetCopied, setIsSnippetCopied] = useState(false);
const handleClick = (): void => {
if (children && Array.isArray(children)) {
setIsSnippetCopied(true);
navigator.clipboard.writeText(children[0].props.children[0]).finally(() => {
setTimeout(() => {
setIsSnippetCopied(false);
}, 1000);
});
}
};
return (
<div className={cx('code-copy-btn', isSnippetCopied ? 'copied' : '')}>
<button type="button" onClick={handleClick}>
{!isSnippetCopied ? <CopyOutlined /> : <CheckOutlined />}
</button>
</div>
);
}

View File

@@ -0,0 +1,43 @@
/* eslint-disable react/jsx-props-no-spreading */
import { CodeProps } from 'react-markdown/lib/ast-to-react';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { a11yDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import CodeCopyBtn from './CodeCopyBtn/CodeCopyBtn';
function Pre({ children }: { children: React.ReactNode }): JSX.Element {
return (
<pre className="code-snippet-container">
<CodeCopyBtn>{children}</CodeCopyBtn>
{children}
</pre>
);
}
function Code({
node,
inline,
className = 'blog-code',
children,
...props
}: CodeProps): JSX.Element {
const match = /language-(\w+)/.exec(className || '');
return !inline && match ? (
<SyntaxHighlighter
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
style={a11yDark}
language={match[1]}
PreTag="div"
{...props}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className={className} {...props}>
{children}
</code>
);
}
export { Code, Pre };

View File

@@ -1,4 +1,17 @@
import * as AntD from 'antd';
import {
Button,
ButtonProps,
Col,
ColProps,
Divider,
DividerProps,
Row,
RowProps,
Space,
SpaceProps,
TabsProps,
Typography,
} from 'antd';
import { TextProps } from 'antd/lib/typography/Text';
import { TitleProps } from 'antd/lib/typography/Title';
import { HTMLAttributes } from 'react';
@@ -9,43 +22,43 @@ import { IStyledClass } from './types';
const styledClass = (props: IStyledClass): FlattenSimpleInterpolation | null =>
props.styledclass || null;
type TStyledCol = AntD.ColProps & IStyledClass;
const StyledCol = styled(AntD.Col)<TStyledCol>`
type TStyledCol = ColProps & IStyledClass;
const StyledCol = styled(Col)<TStyledCol>`
${styledClass}
`;
type TStyledRow = AntD.RowProps & IStyledClass;
const StyledRow = styled(AntD.Row)<TStyledRow>`
type TStyledRow = RowProps & IStyledClass;
const StyledRow = styled(Row)<TStyledRow>`
${styledClass}
`;
type TStyledDivider = AntD.DividerProps & IStyledClass;
const StyledDivider = styled(AntD.Divider)<TStyledDivider>`
type TStyledDivider = DividerProps & IStyledClass;
const StyledDivider = styled(Divider)<TStyledDivider>`
${styledClass}
`;
type TStyledSpace = AntD.SpaceProps & IStyledClass;
const StyledSpace = styled(AntD.Space)<TStyledSpace>`
type TStyledSpace = SpaceProps & IStyledClass;
const StyledSpace = styled(Space)<TStyledSpace>`
${styledClass}
`;
type TStyledTabs = AntD.TabsProps & IStyledClass;
const StyledTabs = styled(AntD.Divider)<TStyledTabs>`
type TStyledTabs = TabsProps & IStyledClass;
const StyledTabs = styled(Divider)<TStyledTabs>`
${styledClass}
`;
type TStyledButton = AntD.ButtonProps & IStyledClass;
const StyledButton = styled(AntD.Button)<TStyledButton>`
type TStyledButton = ButtonProps & IStyledClass;
const StyledButton = styled(Button)<TStyledButton>`
${styledClass}
`;
const { Text } = AntD.Typography;
const { Text } = Typography;
type TStyledTypographyText = TextProps & IStyledClass;
const StyledTypographyText = styled(Text)<TStyledTypographyText>`
${styledClass}
`;
const { Title } = AntD.Typography;
const { Title } = Typography;
type TStyledTypographyTitle = TitleProps & IStyledClass;
const StyledTypographyTitle = styled(Title)<TStyledTypographyTitle>`
${styledClass}

View File

@@ -7,6 +7,7 @@ import { Tooltip } from 'antd';
import { themeColors } from 'constants/theme';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useMemo } from 'react';
import { popupContainer } from 'utils/selectPopupContainer';
import { style } from './styles';
@@ -18,12 +19,24 @@ function TextToolTip({
}: TextToolTipProps): JSX.Element {
const isDarkMode = useIsDarkMode();
const onClickHandler = (
event: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
): void => {
event.stopPropagation();
};
const overlay = useMemo(
() => (
<div>
{`${text} `}
{url && (
<a href={url} rel="noopener noreferrer" target="_blank">
<a
// Stopping event propagation on click so that parent click listener are not triggered
onClick={onClickHandler}
href={url}
rel="noopener noreferrer"
target="_blank"
>
{urlText || 'here'}
</a>
)}
@@ -43,13 +56,13 @@ function TextToolTip({
const iconOutlinedStyle = useMemo(
() => ({
...style,
color: isDarkMode ? themeColors.navyBlue : blue[0],
color: isDarkMode ? themeColors.navyBlue : blue[6],
}),
[isDarkMode],
);
return (
<Tooltip overlay={overlay}>
<Tooltip getTooltipContainer={popupContainer} overlay={overlay}>
{useFilledIcon ? (
<QuestionCircleFilled style={iconStyle} />
) : (

View File

@@ -0,0 +1,4 @@
export const CARD_BODY_STYLE = {
padding: '0',
height: '100%',
};

View File

@@ -6,6 +6,7 @@ export enum FeatureKeys {
ALERT_CHANNEL_SLACK = 'ALERT_CHANNEL_SLACK',
ALERT_CHANNEL_WEBHOOK = 'ALERT_CHANNEL_WEBHOOK',
ALERT_CHANNEL_PAGERDUTY = 'ALERT_CHANNEL_PAGERDUTY',
ALERT_CHANNEL_OPSGENIE = 'ALERT_CHANNEL_OPSGENIE',
ALERT_CHANNEL_MSTEAMS = 'ALERT_CHANNEL_MSTEAMS',
DurationSort = 'DurationSort',
TimestampSort = 'TimestampSort',
@@ -16,4 +17,6 @@ export enum FeatureKeys {
DISABLE_UPSELL = 'DISABLE_UPSELL',
USE_SPAN_METRICS = 'USE_SPAN_METRICS',
OSS = 'OSS',
ONBOARDING = 'ONBOARDING',
CHAT_SUPPORT = 'CHAT_SUPPORT',
}

View File

@@ -0,0 +1,5 @@
export const LIVE_TAIL_HEARTBEAT_TIMEOUT = 600000;
export const LIVE_TAIL_GRAPH_INTERVAL = 60000;
export const MAX_LOGS_LIST_SIZE = 1000;

View File

@@ -11,4 +11,8 @@ export enum LOCALSTORAGE {
GRAPH_VISIBILITY_STATES = 'GRAPH_VISIBILITY_STATES',
TRACES_LIST_COLUMNS = 'TRACES_LIST_COLUMNS',
LOGS_LIST_COLUMNS = 'LOGS_LIST_COLUMNS',
LOGGED_IN_USER_NAME = 'LOGGED_IN_USER_NAME',
LOGGED_IN_USER_EMAIL = 'LOGGED_IN_USER_EMAIL',
CHAT_SUPPORT = 'CHAT_SUPPORT',
IS_IDENTIFIED_USER = 'IS_IDENTIFIED_USER',
}

View File

@@ -0,0 +1,5 @@
export enum OptionFormatTypes {
RAW = 'raw',
LIST = 'list',
TABLE = 'table',
}

View File

@@ -12,3 +12,8 @@ export const PANEL_TYPES_COMPONENT_MAP = {
[PANEL_TYPES.LIST]: null,
[PANEL_TYPES.EMPTY_WIDGET]: null,
} as const;
export const AVAILABLE_EXPORT_PANEL_TYPES = [
PANEL_TYPES.TIME_SERIES,
PANEL_TYPES.TABLE,
];

View File

@@ -18,4 +18,12 @@ export enum QueryParams {
q = 'q',
activeLogId = 'activeLogId',
timeRange = 'timeRange',
compositeQuery = 'compositeQuery',
panelTypes = 'panelTypes',
pageSize = 'pageSize',
viewMode = 'viewMode',
selectedFields = 'selectedFields',
linesPerRow = 'linesPerRow',
viewName = 'viewName',
viewKey = 'viewKey',
}

View File

@@ -4,6 +4,7 @@ import { createNewBuilderItemName } from 'lib/newQueryBuilder/createNewBuilderIt
import {
AutocompleteType,
BaseAutocompleteData,
DataTypes,
LocalDataType,
} from 'types/api/queryBuilder/queryAutocompleteResponse';
import {
@@ -46,12 +47,13 @@ export const selectValueDivider = '__';
export const baseAutoCompleteIdKeysOrder: (keyof Omit<
BaseAutocompleteData,
'id'
'id' | 'isJSON'
>)[] = ['key', 'dataType', 'type', 'isColumn'];
export const autocompleteType: Record<AutocompleteType, AutocompleteType> = {
resource: 'resource',
tag: 'tag',
'': '',
};
export const formulasNames: string[] = Array.from(
@@ -72,7 +74,7 @@ export const mapOfOperators = {
traces: tracesAggregateOperatorOptions,
};
export const mapOfFilters: Record<DataSource, QueryAdditionalFilter[]> = {
export const mapOfQueryFilters: Record<DataSource, QueryAdditionalFilter[]> = {
metrics: [
// eslint-disable-next-line sonarjs/no-duplicate-string
{ text: 'Aggregation interval', field: 'stepInterval' },
@@ -92,6 +94,24 @@ export const mapOfFilters: Record<DataSource, QueryAdditionalFilter[]> = {
],
};
const commonFormulaFilters: QueryAdditionalFilter[] = [
{
text: 'Having',
field: 'having',
},
{ text: 'Order by', field: 'orderBy' },
{ text: 'Limit', field: 'limit' },
];
export const mapOfFormulaToFilters: Record<
DataSource,
QueryAdditionalFilter[]
> = {
metrics: commonFormulaFilters,
logs: commonFormulaFilters,
traces: commonFormulaFilters,
};
export const REDUCE_TO_VALUES: SelectOption<ReduceOperators, string>[] = [
{ value: 'last', label: 'Latest of values in timeframe' },
{ value: 'sum', label: 'Sum of values in timeframe' },
@@ -111,10 +131,11 @@ export const initialAutocompleteData: BaseAutocompleteData = {
{ dataType: null, key: '', isColumn: null, type: null },
baseAutoCompleteIdKeysOrder,
),
dataType: null,
dataType: DataTypes.EMPTY,
key: '',
isColumn: null,
type: null,
isColumn: false,
type: '',
isJSON: false,
};
export const initialFilters: TagFilter = {
@@ -260,6 +281,8 @@ export const OPERATORS = {
NIN: 'NOT_IN',
LIKE: 'LIKE',
NLIKE: 'NOT_LIKE',
REGEX: 'REGEX',
NREGEX: 'NOT_REGEX',
'=': '=',
'!=': '!=',
EXISTS: 'EXISTS',
@@ -270,6 +293,8 @@ export const OPERATORS = {
'>': '>',
'<=': '<=',
'<': '<',
HAS: 'HAS',
NHAS: 'NHAS',
};
export const QUERY_BUILDER_OPERATORS_BY_TYPES = {
@@ -284,6 +309,8 @@ export const QUERY_BUILDER_OPERATORS_BY_TYPES = {
OPERATORS.NOT_CONTAINS,
OPERATORS.EXISTS,
OPERATORS.NOT_EXISTS,
OPERATORS.REGEX,
OPERATORS.NREGEX,
],
int64: [
OPERATORS['='],

View File

@@ -1,16 +0,0 @@
type QueryParamNames =
| 'compositeQuery'
| 'panelTypes'
| 'pageSize'
| 'viewMode'
| 'selectedFields'
| 'linesPerRow';
export const queryParamNamesMap: Record<QueryParamNames, QueryParamNames> = {
compositeQuery: 'compositeQuery',
panelTypes: 'panelTypes',
pageSize: 'pageSize',
viewMode: 'viewMode',
selectedFields: 'selectedFields',
linesPerRow: 'linesPerRow',
};

View File

@@ -2,4 +2,6 @@ export const REACT_QUERY_KEY = {
GET_ALL_LICENCES: 'GET_ALL_LICENCES',
GET_QUERY_RANGE: 'GET_QUERY_RANGE',
GET_ALL_DASHBOARDS: 'GET_ALL_DASHBOARDS',
GET_TRIGGERED_ALERTS: 'GET_TRIGGERED_ALERTS',
GET_FEATURES_FLAGS: 'GET_FEATURES_FLAGS',
};

View File

@@ -7,7 +7,7 @@ const ROUTES = {
TRACE_DETAIL: '/trace/:id',
TRACES_EXPLORER: '/traces-explorer',
SETTINGS: '/settings',
INSTRUMENTATION: '/get-started',
GET_STARTED: '/get-started',
USAGE_EXPLORER: '/usage-explorer',
APPLICATION: '/services',
ALL_DASHBOARD: '/dashboard',
@@ -29,6 +29,7 @@ const ROUTES = {
NOT_FOUND: '/not-found',
LOGS: '/logs',
LOGS_EXPLORER: '/logs-explorer',
LIVE_LOGS: '/logs-explorer/live',
HOME_PAGE: '/',
PASSWORD_RESET: '/password-reset',
LIST_LICENSES: '/licenses',

View File

@@ -52,6 +52,8 @@ const themeColors = {
gamboge: '#D89614',
bckgGrey: '#1d1d1d',
lightBlue: '#177ddc',
buttonSuccessRgb: '73, 170, 25',
red: '#E84749',
};
export { themeColors };

View File

@@ -1,7 +1,7 @@
import getDynamicConfigs from 'api/dynamicConfigs/getDynamicConfigs';
import getFeaturesFlags from 'api/features/getFeatureFlags';
import getUserLatestVersion from 'api/user/getLatestVersion';
import getUserVersion from 'api/user/getVersion';
import ROUTES from 'constants/routes';
import Header from 'container/Header';
import SideNav from 'container/SideNav';
import TopNav from 'container/TopNav';
@@ -19,26 +19,25 @@ import {
UPDATE_CONFIGS,
UPDATE_CURRENT_ERROR,
UPDATE_CURRENT_VERSION,
UPDATE_FEATURE_FLAG_RESPONSE,
UPDATE_LATEST_VERSION,
UPDATE_LATEST_VERSION_ERROR,
} from 'types/actions/app';
import AppReducer from 'types/reducer/app';
import { ChildrenContainer, Layout } from './styles';
import { ChildrenContainer, Layout, LayoutContent } from './styles';
import { getRouteKey } from './utils';
function AppLayout(props: AppLayoutProps): JSX.Element {
const { isLoggedIn, user } = useSelector<AppState, AppReducer>(
(state) => state.app,
);
const { pathname } = useLocation();
const { t } = useTranslation(['titles']);
const [
getUserVersionResponse,
getUserLatestVersionResponse,
getFeaturesResponse,
getDynamicConfigsResponse,
] = useQueries([
{
@@ -51,10 +50,6 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
queryKey: ['getUserLatestVersion', user?.accessJwt],
enabled: isLoggedIn,
},
{
queryFn: getFeaturesFlags,
queryKey: ['getFeatureFlags', user?.accessJwt],
},
{
queryFn: getDynamicConfigs,
queryKey: ['getDynamicConfigs', user?.accessJwt],
@@ -62,10 +57,6 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
]);
useEffect(() => {
if (getFeaturesResponse.status === 'idle') {
getFeaturesResponse.refetch();
}
if (getUserLatestVersionResponse.status === 'idle' && isLoggedIn) {
getUserLatestVersionResponse.refetch();
}
@@ -73,14 +64,10 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
if (getUserVersionResponse.status === 'idle' && isLoggedIn) {
getUserVersionResponse.refetch();
}
if (getFeaturesResponse.status === 'idle') {
getFeaturesResponse.refetch();
}
if (getDynamicConfigsResponse.status === 'idle') {
getDynamicConfigsResponse.refetch();
}
}, [
getFeaturesResponse,
getUserLatestVersionResponse,
getUserVersionResponse,
isLoggedIn,
@@ -194,42 +181,17 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
getUserLatestVersionResponse.isFetched,
getUserVersionResponse.isFetched,
getUserLatestVersionResponse.isSuccess,
getFeaturesResponse.isFetched,
getFeaturesResponse.isSuccess,
getFeaturesResponse.data,
getDynamicConfigsResponse.data,
getDynamicConfigsResponse.isFetched,
getDynamicConfigsResponse.isSuccess,
notifications,
]);
useEffect(() => {
if (
getFeaturesResponse.isFetched &&
getFeaturesResponse.isSuccess &&
getFeaturesResponse.data &&
getFeaturesResponse.data.payload
) {
dispatch({
type: UPDATE_FEATURE_FLAG_RESPONSE,
payload: {
featureFlag: getFeaturesResponse.data.payload,
refetch: getFeaturesResponse.refetch,
},
});
}
}, [
dispatch,
getFeaturesResponse.data,
getFeaturesResponse.isFetched,
getFeaturesResponse.isSuccess,
getFeaturesResponse.refetch,
]);
const isToDisplayLayout = isLoggedIn;
const routeKey = useMemo(() => getRouteKey(pathname), [pathname]);
const pageTitle = t(routeKey);
const renderFullScreen = pathname === ROUTES.GET_STARTED;
return (
<Layout>
@@ -239,13 +201,13 @@ function AppLayout(props: AppLayoutProps): JSX.Element {
{isToDisplayLayout && <Header />}
<Layout>
{isToDisplayLayout && <SideNav />}
<Layout.Content>
{isToDisplayLayout && !renderFullScreen && <SideNav />}
<LayoutContent>
<ChildrenContainer>
{isToDisplayLayout && <TopNav />}
{isToDisplayLayout && !renderFullScreen && <TopNav />}
{children}
</ChildrenContainer>
</Layout.Content>
</LayoutContent>
</Layout>
</Layout>
);

View File

@@ -7,9 +7,14 @@ export const Layout = styled(LayoutComponent)`
position: relative;
min-height: calc(100vh - 4rem);
overflow: hidden;
height: 100%;
}
`;
export const LayoutContent = styled(LayoutComponent.Content)`
overflow-y: auto;
`;
export const ChildrenContainer = styled.div`
margin: 0 1rem;
display: flex;

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