Compare commits

...

218 Commits

Author SHA1 Message Date
Yunus M
f13b083277 feat: api / ingestion keys - initial commit 2024-02-03 02:44:29 +05:30
Vikrant Gupta
efc7aff7a2 fix: loading states for list log view (#4486) 2024-02-02 17:25:07 +05:30
Vikrant Gupta
f04937bbd1 feat: support custom times unique to pages new design changes (#4485) 2024-02-02 17:05:46 +05:30
Vikrant Gupta
fce66a2c5c fix: logs explorer issues (#4483)
* fix: logs explorer issues

* fix: jest test cases
2024-02-02 16:58:58 +05:30
Yunus M
3b4fb3eb80 UI feedback updates (#4482)
* feat: handle loading and fix ui issues

* feat: ui updates
2024-02-02 14:52:28 +05:30
Yunus M
e3ddd0470e feat: handle loading states and incorporate ui feedback (#4479) 2024-02-02 11:14:55 +05:30
Vikrant Gupta
e88b6e400d fix: update TODO and remove extra braces 2024-01-31 22:35:12 +05:30
Vikrant Gupta
857a1e9356 fix: jest config issues 2024-01-31 19:32:30 +05:30
Yunus M
5c0096623c chore: fix tsc issues 2024-01-31 16:34:14 +05:30
Rajat Dabade
32380d5688 [Feat]: View in Traces (#4450)
* refactor: datetime selector beside run query removed add to dashboard

* refactor: added tab for traces view details page

* refactor: done with the save view in traces

* fix: the gittery effect when navigatigating from views

* refactor: view tab view title light mode support

* refactor: removed console

* fix: gittery effect when switch view from views tabs

* refactor: separate traces routes

* refactor: remove query params
2024-01-31 16:16:53 +05:30
Vikrant Gupta
55a0cbc3f1 fix: switching between logs display tabs (#4457) 2024-01-31 16:16:53 +05:30
Rajat Dabade
d319ce99d6 [Refactor]: Tab Switch deplay issue and UI improvement for Clickhouse (#4409) 2024-01-31 16:16:49 +05:30
Vikrant Gupta
dc74592347 feat: added loading and error states for logs design (#4452)
* feat: added loading and error states for logs design

* feat: added error states for table view and time series view

* feat: handle error and loading states

* feat: loading states
2024-01-31 16:16:13 +05:30
Yunus M
5ef07a229d feat: update ui (#4449) 2024-01-31 16:16:13 +05:30
Vikrant Gupta
17b4e69f8b feat: [GH-4436]: date range enhancements (#4448)
* feat: [GH-4436]: when selecting custom time range it should be from start of day to end of date

* fix: custom time width and refresh text visibility issues (#4428)

---------

Co-authored-by: Yunus M <myounis.ar@live.com>
2024-01-31 16:16:12 +05:30
Rajat Dabade
aecd10ef24 refactor: New design for Save views. (#4435) 2024-01-31 16:16:12 +05:30
Vikrant Gupta
7f0574061f fix: logs UI improvements (#4426)
* fix: remove fixed times from the date time picker v2

* fix: added old logs explorer CTA in new designs

* feat: handle active logs indicator update

* fix: address review comments

* fix: old logs explorer page

* fix: remove info text and add relative time buttons

* fix: update logs explorer tab designs

* fix: update logs explorer tab designs

* fix: update logs explorer tab designs
2024-01-31 16:16:12 +05:30
Vikrant Gupta
71266836f8 feat: add raw view attributes in the logs list view (#4422)
* feat: add raw view attributes in the logs list view

* feat: add raw view attributes in the logs list view

* fix: raw attributes
2024-01-31 16:16:12 +05:30
Yunus M
4d4cd72ab2 feat: update styles for logs detail view (#4407)
* feat: update styles for logs detail view

* feat: update styles for logs detail view
2024-01-31 16:16:12 +05:30
Rajat Dabade
b3f1fdefe6 feat: save view for new design (#4392)
* feat: save view for new design

* refactor: done with save view
2024-01-31 16:16:12 +05:30
Rajat Dabade
5fea20f4e7 [Refactor]: New design for Log details page (#4362)
New design for Log details page 

Co-authored-by: Vikrant Gupta <vikrant.thomso@gmail.com>
Co-authored-by: Yunus M <myounis.ar@live.com>
2024-01-31 16:16:12 +05:30
Yunus M
195035f035 Settings theme change (#4368)
* feat: settings theme change
2024-01-31 16:16:08 +05:30
Vikrant Gupta
5c283a3013 chore: styles improvement across new design (#4389)
* fix: improve date time styles

* feat: table view changes according to new design

* fix: button visibility in clickhouse and promQL headers (#4390)

* feat: change the tabs to new design buttons for query builder
2024-01-31 16:15:24 +05:30
Vikrant Gupta
b81d3598bc feat: handle new typing changes for date time picker v2 (#4386)
Co-authored-by: Yunus M <myounis.ar@live.com>
2024-01-31 16:15:20 +05:30
Vikrant Gupta
01f1bee3cd fix: virtuoso scroll refresh issue 2024-01-31 16:12:17 +05:30
Vikrant Gupta
077d23e7b4 feat: handle light theme 2024-01-31 16:12:17 +05:30
Vikrant Gupta
212a36a233 feat: handle light theme 2024-01-31 16:12:17 +05:30
Vikrant Gupta
d296ea9574 feat: handle qb design changes across the application 2024-01-31 16:12:17 +05:30
Vikrant Gupta
065bc3d55d fix: remove dangling border after element removal 2024-01-31 16:12:17 +05:30
Vikrant Gupta
e60f430d66 feat: integrate date time selector across app 2024-01-31 16:12:17 +05:30
Vikrant Gupta
fca51d3d06 feat: date time custom time modal to render inside the new popover (#4366)
* feat: single calender for range picker

* fix: edgecases
2024-01-31 16:12:12 +05:30
Vikrant Gupta
630bf74e4f feat: handle light theme for logs explorer design changes (#4363)
* feat: handle light theme for list tables and dateTime selection

* feat: handle light theme for popover

* fix: address review comments
2024-01-31 16:11:50 +05:30
Vikrant Gupta
109e4e0bed fix: type errors (#4360) 2024-01-31 16:11:50 +05:30
Vikrant Gupta
7b5bb46b84 fix: eslint error 2024-01-31 16:11:50 +05:30
Vikrant Gupta
bc5e409c73 feat: new table view for logs explorer list section (#4353)
* feat: table view changes for logs list

* feat: code refactor to support log line actions

* feat: code refactor to support log line actions

* fix: the positioning of the btns

* feat: fix the table onclick

* fix: header issue

* fix: on hover

* fix: type issue
2024-01-31 16:11:50 +05:30
Yunus M
ccc7cb5b42 fix: lint errors 2024-01-31 16:11:50 +05:30
Yunus M
9423531db1 Query builder design update (#4359)
* feat: QB design update

* fix: add functionality and light mode styles

* fix: ts issues

* fix: update all css color variables to correct names
2024-01-31 16:11:50 +05:30
Vikrant Gupta
3ec56c12dd feat: logs list view changes (#4348)
* feat: logs list view changes

* fix: list view and toolbar styles

* feat: side btns

* feat: added auto refresh handler

* feat: handle popover close for btn click date time

* feat: extract the common log actions btn component

* feat: update the button for log line actions

* fix: event propagation from context button

* feat: use styles from ui-library
2024-01-31 16:11:47 +05:30
Vikrant Gupta
27b4b98ed0 feat: added new toolbar for logs explorer (#4336) 2024-01-31 16:11:15 +05:30
Yunus M
4eb3a4c570 feat: update styles 2024-01-31 16:11:11 +05:30
Yunus M
cb2aec9139 feat: logs explorer - new design 2024-01-31 16:10:44 +05:30
Yunus M
5c60a862e5 fix: update only showTotal property by spreading pagination object (#4467)
* fix: update only showTotal property by spreading pagination object
2024-01-31 15:59:40 +05:30
Yunus M
78c9330666 fix: set light bg for full screen in dashboard (#4465) 2024-01-31 14:25:27 +05:30
Vikrant Gupta
01fc7a7fd4 fix: [GH-4451]: custom time range modal closed on focussing closed date (#4456)
* fix: [GH-4451]: custom time range modal closed on focussing closed date

* fix: jest test
2024-01-30 18:50:02 +05:30
Yunus M
0200fb3a21 fix: close delete modal on delete success (#4459) 2024-01-30 16:47:58 +05:30
Yunus M
e977963763 feat: show total items count in table (#4453) 2024-01-29 18:21:51 +05:30
Yunus M
824d9aaf85 feat: users should choose either to broadcast all or enter specific channels to alert (#4441)
* feat: users should choose either to broadcast all or enter specific channels to alert

* fix: remove console logs
2024-01-29 11:12:41 +05:30
Srikanth Chekuri
4db3e5e542 chore: include status (#4447) 2024-01-29 00:42:19 +05:30
Yunus M
a8b293a510 fix: variable selection flow - dependent variable option not updated … (#4438)
* fix: variable selection flow - dependent variable option not updated on change

* fix: dropdown width and parent element update

* fix: add key to variable item inputs
2024-01-27 12:59:28 +05:30
Srikanth Chekuri
4a4f48cec8 chore: support p9{9,5,0},75,50 for space aggregation (#4382) 2024-01-26 17:07:23 +05:30
Vikrant Gupta
7e5cf65ea3 fix: [GH-4434]: dashboard variables performance issues (#4437) 2024-01-25 23:12:19 +05:30
Keshav Gupta
bb7417ffbd fix:edit the nameon sign up page if name is blank (#4216)
Co-authored-by: keshav <keshav.gupta@jarvis.consulting>
2024-01-25 19:42:14 +05:30
Raj Kamal Singh
085cf34a49 fix: Logs UI: querybuildersearch: avoid emptying out query on sourceKeys update if tags are yet to be populated (#4355)
* fix: querybuildersearch: do not call query onChange from sourceKeys useEffect if tags is empty

* chore: add comment explaining change
2024-01-25 12:35:36 +05:30
Srikanth Chekuri
be27a92fc9 chore: add functions support (#4381) 2024-01-25 01:14:45 +05:30
Vikrant Gupta
253137a6b8 fix: center align the dashboard delete modal (#4429) 2024-01-25 01:05:47 +05:30
Prashanth Banda
fce7ab7d24 fix(frontend,serviceMap): dynamically truncate service map node label (#4365) 2024-01-25 00:47:09 +05:30
Yunus M
5b0e3d375a fix: custom time width and refresh text visibility issues (#4428) 2024-01-24 16:09:32 +05:30
Rajat Dabade
9e05cb48fe refactor: fill span for full view and dashboard view (#4424)
* refactor: fill span for full view and dashboard view

* refactor: fill span works in full view and dashboard
2024-01-24 15:37:34 +05:30
Yunus M
6d67ca72a0 fix: update search logic in dashboard to search for title, description, tags (#4427) 2024-01-24 14:18:15 +05:30
Vikrant Gupta
0626081eee feat: added log attributes in the raw view old designs (#4423)
* feat: added log attributes in the raw view old designs

* feat: support it in old explorer page
2024-01-24 11:32:48 +05:30
Rajat Dabade
199d52b39f refactor: added null check while searching for dashboard (#4421)
* refactor: added null check while searching for dashboard

* refactor: flitering null value out

* chore: removed extra space

* refactor: remove unnecessary null check
2024-01-23 16:36:25 +05:30
Ankit Nayan
204cad8448 merging main 2024-01-22 23:45:18 +05:30
Yunus M
8c6096d60e fix: reset env on data source select, set logo center aligned (#4417) 2024-01-22 21:47:55 +05:30
Prashant Shahi
9de9fb5863 Merge pull request #4413 from SigNoz/release/v0.37.1
Release/v0.37.1
2024-01-22 19:54:11 +05:30
Prashant Shahi
64d854ffa2 chore(signoz): 📌 pin versions: SigNoz 0.37.1
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2024-01-22 19:55:04 +05:45
Prashant Shahi
6b073280a4 Merge branch 'main' into release/v0.37.1 2024-01-22 19:54:38 +05:45
Vikrant Gupta
79e6699b37 fix: logs page crash when special chars present in the value of query (#4408) 2024-01-22 19:06:33 +05:30
Rajat Dabade
d563778479 [Fix]: Resolve glitch in graph due to variable and time stamp change (#4406)
* refactor: resolve glitch in variable and time stamp change

* refactor: removed unwanted code

* refactor: updated code
2024-01-22 16:36:03 +05:30
Vikrant Gupta
255b3dd3b0 fix: back btn navigation on first load (#4405)
* fix: back btn navigation on first load

* fix: remove console logs

* chore: refactor the logic to a function and added code comments
2024-01-22 14:47:25 +05:30
Vikrant Gupta
00e97fa401 fix: trial banner moving to left screen and breaking trace detail page (#4403)
* fix: trial banner moving to left screen and breaking trace detail page

* fix: trial banner moving to left screen and breaking trace detail page
2024-01-22 13:12:02 +05:30
Prashant Shahi
9755ba6b47 Merge pull request #4400 from SigNoz/release/v0.37.0
Release/v0.37.0
2024-01-20 02:03:04 +05:30
Nityananda Gohain
f3fdd2dd6c chore: add tenantId and orgName in usage (#4399)
* feat: add tenantId and orgName in usage

* fix: update regex

* fix: if else logic updated
2024-01-20 01:24:09 +05:30
Prashant Shahi
d4248fe933 chore(signoz): 📌 pin versions: SigNoz 0.37.0, SigNoz OtelCollector 0.88.8
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2024-01-20 00:19:42 +05:45
Vishal Sharma
a8d70206ab chore: update onboarding events (#4387)
* chore: update onboarding events

* chore: update retry count
2024-01-19 17:32:52 +05:30
Yunus M
7b344f7a75 Revert "fix: update time stamp on the first load in URL to help with back navigation" (#4398) 2024-01-19 17:01:52 +05:30
Vikrant Gupta
f0669a6dc1 fix: update time stamp on the first load in URL to help with back navigation (#4397)
* fix: update time stamp on the first load in URL to help with back navigation
2024-01-19 13:52:14 +05:30
Rajat Dabade
4a7d972c85 refactor: conditional based apdex on metrics and trace query range (#4395)
* refactor: conditional based apdex on metrics and trace query range

* chore: add invalid float conversion

* Revert "refactor: conditional based apdex on metrics and trace query range"

This reverts commit ca44a7aedd.

* refactor: added servicename to the query params

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2024-01-19 13:50:51 +05:30
Rajat Dabade
51c1f88593 Revert "[Feat]: added iscolumn in option rendering" (#4396) 2024-01-19 12:05:44 +05:30
Yunus M
c1b9049176 fix: allow workspace blocked users to extend trial (#4393)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2024-01-19 11:11:29 +05:30
Rajat Dabade
46559014f7 [feat]: persistence of graph toggle on variable change (#4316)
* feat: persistence of graph toggle on variable change

* fix: reverted the previous changes

* chore: full view global time selector to right
2024-01-18 23:22:30 +05:30
Srikanth Chekuri
0c1a500142 chore: update onboarding docs to send logs from the end with a note for about beginning (#4374) 2024-01-18 20:02:25 +05:30
Vikrant Gupta
26d6a869c6 fix: button visibility in clickhouse and promQL headers (#4390) 2024-01-18 16:44:52 +05:30
Vikrant Gupta
f99da73098 fix: [GH-4383]: handle special characters in the services name (#4388)
* fix: [GH-4383]: handle special characters in the services name
2024-01-18 15:01:32 +05:30
Yunus M
4a1c48b72b fix: autosave layout to layout change (#4385)
* fix: autosave layout to layout change

* fix: autosave layout to layout change

* refactor: no update api call on opening dashboard

* refactor: removed extra put api call

* refactor: if condition changed

---------

Co-authored-by: Rajat-Dabade <rajat@signoz.io>
2024-01-18 15:01:10 +05:30
Rajat Dabade
1163c16506 [Feat]: added iscolumn in option rendering (#4334)
* feat: added iscolumn in option rendering

* chore: build failure

* fix: build failure
2024-01-18 14:14:10 +05:30
Vikrant Gupta
bb558dde8e Merge pull request #4380 from SigNoz/GH-4325
feat: [GH-4325]: update the URL time query params when zoom in and zoom out of charts
2024-01-17 18:15:47 +05:30
Vikrant Gupta
e89c000252 Merge branch 'develop' into GH-4325 2024-01-17 18:09:03 +05:30
Rajat Dabade
4e8e7745c1 [FE]: spaces in legend formatting (#4349)
* refactor: spaces in legend formatting

* refactor: spaces in legend formatting

* chore: string to const string

* refactor: replace string by const
2024-01-17 15:17:51 +05:30
Vikrant Gupta
512fcda33d fix: address review comments 2024-01-17 14:04:38 +05:30
Vikrant Gupta
6f43b085b0 Merge branch 'develop' into GH-4325 2024-01-17 13:57:25 +05:30
Vikrant Gupta
54038b8ddf feat: handle back btn changes 2024-01-17 13:57:05 +05:30
Yunus M
00c9ef50de fix: set max 6 months for user entered time (#4384)
* fix: set max 6 months for user entered time

* fix: set max 6 months for user entered time
2024-01-17 13:01:55 +05:30
Vikrant Gupta
52750e5248 Merge branch 'develop' into GH-4325 2024-01-16 17:40:28 +05:30
Vikrant Gupta
cbce1b1847 feat: [GH-4325]: update the URL time query params when zoom in and zoom out of charts 2024-01-16 17:35:07 +05:30
Srikanth Chekuri
abaf6126e5 chore: add /v4/query_range endpoint (#4361) 2024-01-16 16:56:20 +05:30
Yunus M
739b1bf387 feat: custom date time value (#4367)
* feat: custom date time value

* fix: update custom date picker

* fix: old placeholder value flicker

* fix: html semantics and move styles to css

* fix: remove console logs

---------

Co-authored-by: Vikrant Gupta <vikrant.thomso@gmail.com>
2024-01-16 01:13:52 +05:30
Vikrant Gupta
cbf150ef7b fix: update correct format in URL in case of custom date time (#4371) 2024-01-15 18:46:18 +05:30
Rajat Dabade
c28f367f46 refactor: updated height for date selector (#4331) 2024-01-11 16:22:20 +05:30
Yunus M
1e679a0d64 fix: empty string search doesn't return all exceptions (#4346)
* fix: empty string search doesn't return all exceptions

* fix: add type
2024-01-10 14:07:23 +05:30
Rajat Dabade
6f5f361a7e fix: soft min and soft max undefined issue (#4351) 2024-01-10 13:12:31 +05:30
Raj Kamal Singh
d65d75ef69 Fix: FE: pipelines: should be able to exit edit mode without making a change (#4335)
* fix: show cancel button on entering edit mode before any changes have been made

* chore: align pipeline page save/cancel buttons to the right
2024-01-10 11:26:25 +05:30
Srikanth Chekuri
722a38491e chore: add signozspanmetrics delta temporality pipeline (#3776) 2024-01-10 01:16:24 +05:30
Srikanth Chekuri
361efd3b52 chore: add querier v2 (#4170) 2024-01-09 22:19:03 +05:30
Rajat Dabade
7b46f86f7f [Refactor]: resolve the wrong payload in timeseries log explorer issue (#4345)
Co-authored-by: Vikrant Gupta <54737045+Vikrant2520@users.noreply.github.com>
2024-01-09 17:47:23 +05:30
Rajat Dabade
5b39dc36d6 [Feat]: soft min and soft max in uplot chart (#4287)
* feat: soft min and soft max in uplot chart

* fix: build pipeline

* fix: tsc

* refactor: added test case

* refactor: updated logic and added unit test

* refactor: updated logic

* chore: removed placeholder

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
Co-authored-by: Yunus M <myounis.ar@live.com>
2024-01-09 14:19:23 +05:30
Keshav Gupta
5fe7948be9 feat: preserve the sorting searching and pagination in dashboard page (#4319)
* feat: preserved the sorting searching and pagination

* fix: filter in dashboard data
2024-01-09 13:26:44 +05:30
Yunus M
a47a90b0f3 fix: validate password on paste, change (#4344)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2024-01-09 12:55:24 +05:30
Srikanth Chekuri
be6bca3717 chore: add prepare query for cumulative/unspecified table (#4169) 2024-01-08 20:04:21 +05:30
Srikanth Chekuri
92717774a2 fix: throw error when response for value panel returns more than one series (#4332) 2024-01-08 18:11:22 +05:30
Srikanth Chekuri
e7fabca38e chore: fix the query range cache gaps (#4283) 2024-01-08 18:00:42 +05:30
Srikanth Chekuri
525dea343c chore: add prepare query for delta/unspecified table (#4168) 2024-01-08 01:33:04 +05:30
Yunus M
7d960b79dd feat: update sidebar and base theme styles (#4272)
* feat: update sidebar and base theme styles

* feat: update sidebar items and styles

* feat: wire up logs navigation and update user settings page

* feat: update styles to handle light mode, add full view header

* feat: update onboarding header and styles

* feat: remove unused routes

* feat: handle sidebar collapse

* feat: show pointer on logo hover

* feat: fix logs module navigations

* feat: update logo click route

* feat: update entity name color to primary in application and dashboard tables

* feat: update sidebar item styles

* feat: update collapse icon and styles

* fix: name not updated in menu on change

* fix: show invite members nav item

* fix: open invite members modal on invite team member nav item click
2024-01-05 11:15:31 +05:30
Yunus M
bdd7778e58 update readme.md (#3814)
* chore: update read.me - fe maintainers

* chore: update code owner for frontend codebase
2024-01-02 17:42:36 +05:30
Srikanth Chekuri
105216de3e chore: add prepare query for delta/unspecified timeseries (#4167)
* chore: update BuilderQuery struct and add PrepareTimeseriesFilterQuery

* chore: add prepare query for cumulative/unspecified timeseries

* chore: add prepare query for delta/unspecified timeseries

* chore: update group by to work with 23.11+

* chore: fix test

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2023-12-30 22:53:09 +05:30
Ankit Nayan
3072b7eb01 merging main 2023-12-29 22:29:15 +05:30
Raj Kamal Singh
fd9a502012 fix: opamp server: do not panic if config generation fails (#4307) 2023-12-29 21:55:38 +05:30
Prashant Shahi
cf6dc827cc Merge pull request #4306 from SigNoz/release/v0.36.2
Release/v0.36.2
2023-12-29 19:21:12 +05:30
Prashant Shahi
6530873994 Merge branch 'main' into release/v0.36.2 2023-12-29 19:12:41 +05:30
Prashant Shahi
c9c0bd38be chore(signoz): 📌 pin versions: SigNoz 0.36.2
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-12-29 19:24:12 +05:45
Prashant Shahi
9ac22fcb10 Merge branch 'develop' into release/v0.36.1 2023-12-29 19:06:53 +05:45
Raj Kamal Singh
86ff865842 Fix: logs pipelines: ignore coalesce op when generating nil check for add value expressions (#4305)
* chore: panic if agent config recommendation can't be generated

* chore: add case with coalesce op in field nil check generation tests

* fix: ignore expr ast member nodes that contain coalesce op in them
2023-12-29 18:21:01 +05:30
Rajat Dabade
e792c48f6d [Refactor]: css fixes (#4248) 2023-12-29 16:05:46 +05:30
Rajat Dabade
8ee92516ca [Refactor]: updated css for height of Panel in LeftContainer (#4030)
* refactor: updated css

* refactor: updated the css

* refactor: removed overflow hidden
2023-12-29 15:52:35 +05:30
Prashant Shahi
79c05d8fa8 Merge pull request #4304 from SigNoz/release/v0.36.1
Release/v0.36.1
2023-12-29 15:39:38 +05:30
Prashant Shahi
019bc8c1df chore(signoz): 📌 pin versions: SigNoz 0.36.1, SigNoz OtelCollector 0.88.6
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-12-29 15:44:27 +05:45
Yunus M
d688399b91 fix: overflow issue in service page graphs (#4300) 2023-12-29 13:11:23 +05:30
Rajat Dabade
cfc239e3c9 refactor: added 3 days global timestamp (#4290)
* refactor: added 3 days global timestamp

* refactor: updated 3 days data in right container

* refactor: common function for calculate start and end time
2023-12-29 12:54:02 +05:30
Srikanth Chekuri
3572baa5eb fix: adjust the start and end more accurately (#4263)
* fix: adjust the start and end more accurately
Part of https://github.com/SigNoz/signoz/issues/1327

* chore: cache friendly timestamps
2023-12-29 12:35:22 +05:30
Rajat Dabade
ff26c5f69c fix: make fill gap persistent (#4302) 2023-12-29 12:23:27 +05:30
Srikanth Chekuri
9230f2442f fix: normalize label name to follow prometheus spec (#4264) 2023-12-28 20:22:42 +05:30
Raj Kamal Singh
7fed80b145 Fix: log pipelines contains and ncontains filters should be case insensitive (#4299)
* chore: add test validating contains and ncontains in pipeline filter are case insensitive

* chore: qb2expr: translate contains and ncontains to case insensitive comparison

* chore: minor cleanup
2023-12-28 19:44:17 +05:30
Yunus M
a268bb910c fix: update logic to handle step paths in Kubernetes APM flow (#4297)
* fix: update logic to handle step paths in kubernetes APM flow

* fix: don't reset service name on data source component mount
2023-12-28 18:30:41 +05:30
Rajat Dabade
fbbe0bef86 [Fix]: live view details modal disappear bug (#4249) 2023-12-28 16:02:55 +05:30
Raj Kamal Singh
bcd6ac47f7 Fix: Logs: Pipelines: add nil check for grok parser parseFrom field in generated collector config (#4286)
* chore: add test validating grok parser doesn't spam logs if parse from is missing

* chore: add nil check for grok parser parseFrom
2023-12-28 11:03:31 +05:30
Raj Kamal Singh
ec27916fa5 Fix: QS: Log Pipelines: generate correct nil checks for operators referencing fields like attributes["http.status.code"] (#4284)
* chore: add test validating that using paths like attributes["http.method"] works

* chore: refactor nil checks on processor fields generated for pipelines

* chore: get nil checks working on paths like attributes["http.method"]

* chore: use parsed AST for generating nil checks for add operator value expressions

* chore: some cleanup

* chore: some more cleanup

* chore: some more cleanup

* chore: some more cleanup

---------

Co-authored-by: Nityananda Gohain <nityanandagohain@gmail.com>
2023-12-28 10:31:36 +05:30
Srikanth Chekuri
263ac9fa5a fix: ignore timestamp from the subquery result for value panel (#4293) 2023-12-27 19:25:24 +05:30
Rajat Dabade
e3b2882811 [Fix]: scroll bar issue in table panel (#4043) 2023-12-27 10:56:36 +05:30
Rajat Dabade
63efb2b25a [Fix]: threshold table issue (#4247)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-12-27 10:38:22 +05:30
Srikanth Chekuri
788a38d39c chore: update CODEOWNERS (#4285) 2023-12-26 18:54:49 +05:30
Sanjib Kumar Sah
bff39daef0 fix: word overflow for large number in flamegraph (#4122)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-12-26 15:41:01 +05:30
CheetoDa
f2521b4c49 feat: onboarding flow updates and new flow addition (#4222)
* feat: onboarding flow updates and new flow addition

* feat: added reactjs files

* feat: added content for reactjs and others

* chore: implemented feedback

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
Co-authored-by: Yunus M <myounis.ar@live.com>
2023-12-26 10:43:55 +05:30
Ankit Nayan
16b846006a Merge pull request #4278 from SigNoz/release/v0.36.0
Release/v0.36.0
2023-12-22 15:18:38 +05:30
Prashant Shahi
0ea8e8e6b8 Merge branch 'develop' into release/v0.36.0 2023-12-22 15:12:32 +05:45
Prashant Shahi
da0ea7eb49 fix(dockerfile): copy invitation email templates for EE build (#4274)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-12-22 14:55:30 +05:30
Prashant Shahi
ca41d7011e chore(signoz): 📌 pin versions: SigNoz 0.36.0, SigNoz OtelCol 0.88.4
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-12-22 14:37:29 +05:45
Vishal Sharma
f15e8f2fed Update new maintainers (#4277) 2023-12-22 12:46:21 +05:30
Yunus M
2e0fdbb498 feat: show rate limit warning in services page when total RPS > 100 (#4266)
* feat: show rate limit warning in services page when total rps > 100

* feat: update message

* feat: rate limit message should be shown only to cloud users on trail

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-12-22 00:51:37 +05:30
Vishal Sharma
585d6e2a21 chore: send event only if there are dashboards or alerts (#4253) 2023-12-21 19:06:13 +05:30
Vishal Sharma
d93cc767a6 chore: update active user event (#4271)
Merged on request by Visha
2023-12-21 19:05:21 +05:30
Prashant Shahi
a363b98657 feat(query-service): support for SMTP service (#4258)
* feat(query-service): support for SMTP service

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* feat(query-service): smtp minor fixes

Signed-off-by: Prashant Shahi <prashant@signoz.io>

* chore: fix smtp and add email template

* chore: update template

* chore(smpt-service): configurable invite email template path

Signed-off-by: Prashant Shahi <prashant@signoz.io>

---------

Signed-off-by: Prashant Shahi <prashant@signoz.io>
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-12-21 18:27:30 +05:30
Vishal Sharma
2031a014a7 Revert "Fix: lettercase bug in query-builder (#4120)" (#4255)
This reverts commit a6b6abf1a7.

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-12-21 13:36:56 +05:30
Raj Kamal Singh
43d5ee9651 FE: Log Detail View: Support for dots in log attributes (#4252)
* chore: add support for showing attrib names containing dots in log details

* chore: add support for field names with dot in filter actions

* chore: minor cleanup

* chore: add support for filtering by clicking fields with dots in log details
2023-12-21 13:21:20 +05:30
Nityananda Gohain
f8bb42a13c fix: dot support in attribute name (#4121)
* fix: dot support

* fix: column name updated for materialized columns

* fix: tests updated

* fix: comments updated

* fix: enrichment test updated

* fix: dont return underscore fields in the fields API

* fix: update fields function changed to support default instead of materialized

* fix: updated how formulas are built and test added

* fix: don't create index for bool attributes

* fix: support for limit queries updated
2023-12-21 12:11:35 +05:30
CheetoDa
1be4731710 feat: added frontend for newly addded flows (#4151)
* feat: added frontend for newly addded flows

* chore: added content for flows

* chore: updated content for dotnet docs

* chore: updated go instrumentation and http logs content

* fix: removed console log and return true

* fix: quickstart by default and cloudwatch logs

* fix: removed console log
2023-12-20 20:16:21 +05:30
Yunus M
90b8959045 feat: gh-4211: show copy and share invite link message next to pending invites (#4260)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-12-20 18:18:27 +05:30
Rajat Dabade
f487c1956b [Fix]: range issue in uplot charts (#4262)
* fix: range issue in uplot charts

* refactor: updated logic to strickly check is parsed value is number

* refactor: safe check for number value
2023-12-20 17:36:13 +05:30
Rajat Dabade
6b2f03d43f [Refactor]: Added tag and datatype in options for query builder (#3555)
Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-12-20 15:31:37 +05:30
Raj Kamal Singh
581bd07b35 Fix: query service: escape dollars in collector config generated for pipelines. (#4242)
* chore: add test validating pipeline config containing dollar works

* chore: collector simulator: use fileprovider with expandconverter like actual collector

* chore: get tests passing

* chore: take a configGenerator func in simulation and unify config generation logic

* fix: escape $ in config generated for log pipelines
2023-12-19 21:24:53 +05:30
Vikrant Gupta
c5cba68b53 fix: suggestions not populating without space (#4257) 2023-12-19 21:08:55 +05:30
Sanjib Kumar Sah
a6b6abf1a7 Fix: lettercase bug in query-builder (#4120)
* fix: lettercase bug in query-builder

* fix: suggesting similar value when entering diffrnt case value

---------

Co-authored-by: Vishal Sharma <makeavish786@gmail.com>
2023-12-19 16:03:30 +05:30
Yunus M
7526888886 feat: show trace details on hover (#4241)
* feat: show trace details on hover

* feat: handle sider anchor styles in dark and light mode
2023-12-18 17:03:38 +05:30
Vikrant Gupta
ce8fdd509b fix: [GH-3585]: operator suggestion should work on the substring typed in by the user (#4246)
* fix: [GH-3585]: operator suggestion logic

* fix: [GH-3585]: address review comments

* fix: [GH-3585]: address review comments
2023-12-18 13:51:39 +05:30
Nityananda Gohain
2baa6028b5 fix: enrichment for json in alerts and disable timestamp adjustment (#4240)
* fix: enrichment for json in alerts and disable timestamp adjustment

* fix: tests updated
2023-12-16 17:06:49 +05:30
Srikanth Chekuri
8e653f9500 fix: do not use grouping sets when there is no tags for group by (#4237) 2023-12-15 18:56:05 +05:30
Rajat Dabade
cb1a823f91 fix: the min data point as 0 in time series (#4203) 2023-12-15 17:44:13 +05:30
Yunus M
c0b0920901 Round off x axis max timestamp to T - 1 min and 0th second (#4238)
* feat: round of x axis max timestamp to t - 1 min and 0th second

* feat: set min width of time selection dropdown to 120px

* feat: update logic comment

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-12-15 17:29:54 +05:30
Rajat Dabade
77b4e71543 [refactor]: persistance of sorting and page in table (#4221) 2023-12-15 17:23:01 +05:30
Palash Gupta
9d44ce3ee2 feat: on create alerts query range format is called to fill the variables (#4204) 2023-12-15 17:08:35 +05:30
Yunus M
1d014ab4f7 Rearrange variables (#4187)
* feat: variable re-arrange

* feat: update variable update from dashboard description

* feat: update variable update from dashboard description

* feat: update custom variable dropdown values on change

* feat: handle dependent value updates to dashboard description

* feat: handle dependent 0th order variable update

* feat: update variable item test

* feat: transform variables data to support rearraging

* feat: update modal import

* feat: remove console logs

* feat: ts-ignore

* feat: show variable name in delete modal
2023-12-15 13:10:02 +05:30
Yunus M
418ab67d50 Uplot time range (#4144)
* feat: show range bound chart based on the selected time range

* feat: handle no data

* feat: show bigger point if only data point exists

* feat: show bigger point if only data point exists

* feat: widget ui fixes

* feat: no data - full view fix

* fix: show closed point on hover

* feat: handle widget time preference in case of dashboard, edit view, full view and chart preview
2023-12-14 22:56:25 +05:30
Vikrant Gupta
7efe907757 fix: [GH-3790]: timerange not working for different users (#4192) 2023-12-14 22:14:58 +05:30
Rajat Dabade
1d1154aa8c [Refactor]: added tooltip for graph manager (#4236) 2023-12-14 18:10:52 +05:30
Nityananda Gohain
a16fca6376 fix: remove timestamp roundup for logs list api call (#4229)
* fix: remove timestamp roundup for logs list api call

* fix: test updated
2023-12-14 16:52:02 +05:30
Rajat Dabade
9c1ea0cde9 refactor: pop for unsaved changes (#4188) 2023-12-14 11:43:02 +05:30
Nityananda Gohain
ec500831ef feat: upgrade clickhouse to 23.11.1 (#4225) 2023-12-14 11:22:20 +05:30
Prashant Shahi
fcbf82c2f3 Merge pull request #4232 from SigNoz/release/v0.35.1
Release/v0.35.1
2023-12-13 22:42:29 +05:30
Prashant Shahi
a805eb7533 chore(signoz): 📌 pin versions: SigNoz 0.35.1, SigNoz OtelCollector 0.88.3
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-12-13 21:13:09 +05:45
Vishal Sharma
a8edc4fd95 chore: better error handling in getAlertsInfo (#4230) 2023-12-13 19:12:35 +05:30
Vishal Sharma
c66c8c2823 chore: add new dashboard/alerts info events (#4214)
* chore: add new dashboard/alerts info events
2023-12-13 18:14:55 +05:30
Srikanth Chekuri
c7b59d4405 chore: update .github/CODEOWNERS (#3539)
* chore: update .github/CODEOWNERS

* chore: remove team
2023-12-13 17:53:18 +05:30
Vishal Sharma
f56b5cb971 fix: createPAT method to return id (#4078)
Update token expiry validations
2023-12-13 17:05:59 +05:30
Srikanth Chekuri
29b1344557 chore: add prepare query for cumulative/unspecified timeseries (#4166) 2023-12-13 16:40:17 +05:30
Rajat Dabade
55664872bd [Feat]: only clicked legend graph visible (#4226)
* refactor: only clicked legend graph visible

* refactor: fix graph manage toggle issue
2023-12-13 16:26:25 +05:30
Yunus M
221861230a feat: track channel click event in support page (#4217) 2023-12-13 01:18:19 +05:30
Yunus M
8b1a781f58 feat: pass abort signal to cancel api request on query-key change or … (#4193)
* feat: pass abort signal to cancel api request on query-key change or dashboard unmount

* fix: transformIgnorePatterns axios

* fix: remove axios types

* feat: handle error type from dashboardAPI response

* feat: remove console.log
2023-12-12 17:18:57 +05:30
Yunus M
b557ca5519 fix: use updated query value on test query, restrict direct commit to… (#4210)
* fix: use updated query value on test query, restrict direct commit to develop,main

* fix: reset error preview on success
2023-12-12 16:30:22 +05:30
Palash Gupta
e557ff273f test: metrics application test are added (#4137)
* test: metrics application test are added

* fix: getTopOperationList is moved under __mocks__
2023-12-12 14:16:06 +05:30
Yunus M
3c284fc9ee Revert "fix: variable edit flow - use updated query value on test query" (#4207)
This reverts commit bcebe050b1.
2023-12-12 11:38:06 +05:30
Yunus M
bcebe050b1 fix: variable edit flow - use updated query value on test query 2023-12-12 11:19:06 +05:30
Srikanth Chekuri
9360c61dca chore: update BuilderQuery struct and add PrepareTimeseriesFilterQuery (#4165) 2023-12-12 07:24:33 +05:30
guangwu
fb1dbdc05e chore: use bytes.Equal instead (#4201) 2023-12-11 18:45:47 +05:30
Rajat Dabade
6170b2c5dc [Refactor]: added percent 0 - 100 in yaxis for alerts (#4173) 2023-12-11 18:34:24 +05:30
Srikanth Chekuri
9826ab04b3 chore: add new endpoint for variable replacement (#4191)
Co-authored-by: Palash Gupta <palashgdev@gmail.com>
2023-12-11 17:46:08 +05:30
Srikanth Chekuri
fd9566d471 fix: incorrect alert description and summary for prom rules (#4190) 2023-12-11 16:09:28 +05:30
Raj Kamal Singh
3a1e8d523a Fix: qs: allow saving pipelines without connected agents (#4189)
* chore: add test validating pipelines can be saved without connected agents

* chore: allow pipelines to be saved without connected agents
2023-12-09 10:17:06 +05:30
Gaurav Sharma
6dd34a7f29 Fix/2967 (#4071) 2023-12-08 12:37:19 +05:30
Avijeet Pandey
170e5e1686 fix(FE): Fixes the background color of the dashboards full screen view as per the mode selected i.e dark or light mode (#4175)
* fix: full screen bg color of graphs as per dark mode

* fix: colors from the constants
2023-12-08 11:53:56 +05:30
Prashant Shahi
16502feaad Merge pull request #4177 from SigNoz/release/v0.35.0
Release/v0.35.0
2023-12-06 22:15:19 +05:30
Prashant Shahi
09d579311e chore(signoz): 📌 pin versions: SigNoz 0.35.0
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-12-06 22:10:36 +05:45
dependabot[bot]
8072fede85 chore(deps): bump tj-actions/branch-names in /.github/workflows (#4164)
Bumps [tj-actions/branch-names](https://github.com/tj-actions/branch-names) from 5.1 to 7.0.7.
- [Release notes](https://github.com/tj-actions/branch-names/releases)
- [Changelog](https://github.com/tj-actions/branch-names/blob/main/HISTORY.md)
- [Commits](https://github.com/tj-actions/branch-names/compare/v5.1...v7.0.7)

---
updated-dependencies:
- dependency-name: tj-actions/branch-names
  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-12-06 08:40:47 +05:30
Raj Kamal Singh
112783d618 Feat: fe: logs pipelines severity parsing processor (#4149) 2023-12-05 18:30:46 +05:30
Yunus M
4644b1c200 fix: custom variables options are not populated (#4154) 2023-12-05 16:09:50 +05:30
Yunus M
bb09c84679 fix: text formatting issues and upgrade button style updates (#4141) 2023-12-05 11:15:08 +05:30
Raj Kamal Singh
fc5f0fbf9e Feat: fe: logs pipelines timestamp parsing processor (#4106)
* chore: add processor config for time parsing processor

* chore: add select input and processor fields with enumerated options

* feat: set timestamp layout to default value when layout_type is changed

* chore: minor cleanup

* chore: some more cleanup

* chore: some more cleanup

* chore: get jest passing

* chore: normalize ts in pipelines previews input and output

* chore: some cleanup

* fix: set correct field id for timestamp format input
2023-12-04 15:57:14 +05:30
Ankit Nayan
d6f0559adc fix: ee/query-service/Dockerfile to reduce vulnerabilities (#4145)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6032386
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6032386
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6055795
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6055795

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-12-03 08:00:33 +05:30
Yunus M
0d7f7df76c fix: pkg/query-service/Dockerfile to reduce vulnerabilities (#4146)
The following vulnerabilities are fixed with an upgrade:
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6032386
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6032386
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6055795
- https://snyk.io/vuln/SNYK-ALPINE318-OPENSSL-6055795

Co-authored-by: snyk-bot <snyk-bot@snyk.io>
2023-12-03 07:53:15 +05:30
Vikrant Gupta
7104d8e0f5 feat: [GH-4093]: move the name to the left and the actions to the right for widget header (#4130) 2023-12-02 14:47:08 +05:30
Yunus M
a20693fa9f fix: add onboarding complete event (#4140) 2023-12-01 21:55:21 +05:30
Rajat Dabade
0b991331d7 [Fix]: threshold in alerts (#4074) 2023-12-01 18:16:25 +05:30
Raj Kamal Singh
aad44a1037 Feat: QS: logs pipelines severity parsing processor (#4132)
* chore: update test helper for making logs

* chore: add happy case test for severity parser

* feat: get severity parsing processor working and add more happy path tests

* chore: add test for validating severity parser doesn't spam collector logs

* chore: add if condition to generated severity_parser operators

* chore: add postablePipeline validation for severity parser

* chore: minor cleanup in tests

* chore: allow trace and fatal in severity mappings
2023-12-01 17:22:22 +05:30
Yunus M
3e29161fea fix: update logic for handling data for uplot charts (#4131)
* fix: update logic for handling data for uplot charts

* fix: hide tooltip if no tooltip values present

* fix: remove console log
2023-12-01 17:08:24 +05:30
Rajat Dabade
b616dca52d fix: the full view in service layer (#4133)
Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-12-01 16:42:19 +05:30
dependabot[bot]
be519666a3 chore(deps): bump @adobe/css-tools from 4.3.1 to 4.3.2 in /frontend (#4134)
Bumps [@adobe/css-tools](https://github.com/adobe/css-tools) from 4.3.1 to 4.3.2.
- [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>
2023-12-01 11:14:14 +05:30
Rajat Dabade
a48edac13b fix: the default query issue in log (#4108) 2023-11-30 18:56:09 +05:30
Palash Gupta
0a77c7ab85 fix: onRun Query offset is made zero (#4083) 2023-11-30 18:41:26 +05:30
Prashant Shahi
9fb32acf6d ci(staging-deployment): ✏️ fix command to pull latest schema migrator image (#4123)
Signed-off-by: Prashant Shahi <prashant@signoz.io>
2023-11-30 18:02:18 +05:30
Yunus M
b2d6d75eef feat: dashboard perf improvements (#4010)
* feat: dashboard perf improvements

* feat: remove console logs

* fix: remove console.log

* fix: update tests

* fix: update tests

---------

Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
2023-11-30 13:56:49 +05:30
Prashant Shahi
07d126c669 Merge pull request #4114 from SigNoz/release/v0.34.4
Release/v0.34.4
2023-11-29 22:55:53 +05:30
682 changed files with 30417 additions and 5442 deletions

7
.github/CODEOWNERS vendored
View File

@@ -1,15 +1,10 @@
# CODEOWNERS info: https://help.github.com/en/articles/about-code-owners
# Owners are automatically requested for review for PRs that changes code
# that they own.
* @ankitnayan
/frontend/ @palashgdev @YounixM
/frontend/ @YounixM
/frontend/src/container/MetricsApplication @srikanthccv
/frontend/src/container/NewWidget/RightContainer/types.ts @srikanthccv
/deploy/ @prashant-shahi
/sample-apps/ @prashant-shahi
**/query-service/ @srikanthccv
Makefile @srikanthccv
go.* @srikanthccv
.git* @srikanthccv
.github @prashant-shahi

View File

@@ -34,7 +34,7 @@ jobs:
id: short-sha
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v5.1
uses: tj-actions/branch-names@v7.0.7
- name: Set docker tag environment
run: |
if [ '${{ steps.branch-name.outputs.is_tag }}' == 'true' ]; then
@@ -78,7 +78,7 @@ jobs:
id: short-sha
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v5.1
uses: tj-actions/branch-names@v7.0.7
- name: Set docker tag environment
run: |
if [ '${{ steps.branch-name.outputs.is_tag }}' == 'true' ]; then
@@ -127,7 +127,7 @@ jobs:
id: short-sha
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v5.1
uses: tj-actions/branch-names@v7.0.7
- name: Set docker tag environment
run: |
if [ '${{ steps.branch-name.outputs.is_tag }}' == 'true' ]; then
@@ -176,7 +176,7 @@ jobs:
id: short-sha
- name: Get branch name
id: branch-name
uses: tj-actions/branch-names@v5.1
uses: tj-actions/branch-names@v7.0.7
- name: Set docker tag environment
run: |
if [ '${{ steps.branch-name.outputs.is_tag }}' == 'true' ]; then

View File

@@ -29,7 +29,7 @@ jobs:
export PATH="/usr/local/go/bin/:$PATH" # needed for Golang to work
docker system prune --force
docker pull signoz/signoz-otel-collector:main
docker pull signoz/signoz/signoz-schema-migrator:main
docker pull signoz/signoz-schema-migrator:main
cd ~/signoz
git status
git add .

View File

@@ -11,7 +11,6 @@
<img alt="tweet" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social"> </a>
</p>
<h3 align="center">
<a href="https://signoz.io/docs"><b>Dokumentation</b></a> &bull;
<a href="https://github.com/SigNoz/signoz/blob/develop/README.md"><b>Readme auf Englisch </b></a> &bull;
@@ -40,12 +39,13 @@ SigNoz hilft Entwicklern, Anwendungen zu überwachen und Probleme in ihren berei
👉 Einfache Einrichtung von Benachrichtigungen mit dem selbst erstellbaren Abfrage-Builder.
##
### Anwendung Metriken
![application_metrics](https://user-images.githubusercontent.com/83692067/226637410-900dbc5e-6705-4b11-a10c-bd0faeb2a92f.png)
### Verteiltes Tracing
<img width="2068" alt="distributed_tracing_2 2" src="https://user-images.githubusercontent.com/83692067/226536447-bae58321-6a22-4ed3-af80-e3e964cb3489.png">
<img width="2068" alt="distributed_tracing_1" src="https://user-images.githubusercontent.com/83692067/226536462-939745b6-4f9d-45a6-8016-814837e7f7b4.png">
@@ -62,22 +62,18 @@ SigNoz hilft Entwicklern, Anwendungen zu überwachen und Probleme in ihren berei
![exceptions_light](https://user-images.githubusercontent.com/83692067/226637967-4188d024-3ac9-4799-be95-f5ea9c45436f.png)
### Alarme
<img width="2068" alt="alerts_management" src="https://user-images.githubusercontent.com/83692067/226536548-2c81e2e8-c12d-47e8-bad7-c6be79055def.png">
<br /><br />
## Werde Teil unserer Slack Community
Sag Hi zu uns auf [Slack](https://signoz.io/slack) 👋
<br /><br />
## Funktionen:
- Einheitliche Benutzeroberfläche für Metriken, Traces und Logs. Keine Notwendigkeit, zwischen Prometheus und Jaeger zu wechseln, um Probleme zu debuggen oder ein separates Log-Tool wie Elastic neben Ihrer Metriken- und Traces-Stack zu verwenden.
@@ -93,7 +89,6 @@ Sag Hi zu uns auf [Slack](https://signoz.io/slack) 👋
<br /><br />
## Wieso SigNoz?
Als Entwickler fanden wir es anstrengend, uns für jede kleine Funktion, die wir haben wollten, auf Closed Source SaaS Anbieter verlassen zu müssen. Closed Source Anbieter überraschen ihre Kunden zum Monatsende oft mit hohen Rechnungen, die keine Transparenz bzgl. der Kostenaufteilung bieten.
@@ -116,12 +111,10 @@ Wir unterstützen [OpenTelemetry](https://opentelemetry.io) als Bibliothek, mit
- Elixir
- Rust
Hier findest du die vollständige Liste von unterstützten Programmiersprachen - https://opentelemetry.io/docs/
<br /><br />
## Erste Schritte mit SigNoz
### Bereitstellung mit Docker
@@ -138,7 +131,6 @@ Bitte folge den [hier](https://signoz.io/docs/deployment/helm_chart) aufgelistet
<br /><br />
## Vergleiche mit bekannten Tools
### SigNoz vs Prometheus
@@ -179,7 +171,6 @@ Wir haben Benchmarks veröffentlicht, die Loki mit SigNoz vergleichen. Schauen S
<br /><br />
## Zum Projekt beitragen
Wir ❤️ Beiträge zum Projekt, egal ob große oder kleine. Bitte lies dir zuerst die [CONTRIBUTING.md](CONTRIBUTING.md), durch, bevor du anfängst, Beiträge zu SigNoz zu machen.
@@ -197,6 +188,8 @@ Du bist dir nicht sicher, wie du anfangen sollst? Schreib uns einfach auf dem #c
#### Frontend
- [Palash Gupta](https://github.com/palashgdev)
- [Yunus M](https://github.com/YounixM)
- [Rajat Dabade](https://github.com/Rajat-Dabade)
#### DevOps
@@ -204,16 +197,12 @@ Du bist dir nicht sicher, wie du anfangen sollst? Schreib uns einfach auf dem #c
<br /><br />
## Dokumentation
Du findest unsere Dokumentation unter https://signoz.io/docs/. Falls etwas unverständlich ist oder fehlt, öffne gerne ein Github Issue mit dem Label `documentation` oder schreib uns über den Community Slack Channel.
<br /><br />
## Gemeinschaft
Werde Teil der [slack community](https://signoz.io/slack) um mehr über verteilte Einzelschritt-Fehlersuche, Messung von Systemzuständen oder SigNoz zu erfahren und sich mit anderen Nutzern und Mitwirkenden in Verbindung zu setzen.

View File

@@ -199,10 +199,13 @@ Not sure how to get started? Just ping us on `#contributing` in our [slack commu
#### Frontend
- [Palash Gupta](https://github.com/palashgdev)
- [Yunus M](https://github.com/YounixM)
- [Rajat Dabade](https://github.com/Rajat-Dabade)
#### DevOps
- [Prashant Shahi](https://github.com/prashant-shahi)
- [Dhawal Sanghvi](https://github.com/dhawal1248)
<br /><br />

View File

@@ -19,7 +19,7 @@
<a href="https://twitter.com/SigNozHq"><b>Twitter</b></a>
</h3>
##
##
SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可以使用 SigNoz 实现如下能力:
@@ -67,7 +67,7 @@ SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可
## 加入我们 Slack 社区
来 [Slack](https://signoz.io/slack) 和我们打招呼吧 👋
来 [Slack](https://signoz.io/slack) 和我们打招呼吧 👋
<br /><br />
@@ -83,7 +83,7 @@ SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可
- 通过 服务名、操作方式、延迟、错误、标签/注释 过滤 traces 数据
- 通过聚合 trace 数据而获得业务相关的 metrics。 比如你可以通过 `customer_type: gold` 或者 `deployment_version: v2` 或者 `external_call: paypal` 获取错误率和 P99 延迟数据
- 通过聚合 trace 数据而获得业务相关的 metrics。 比如你可以通过 `customer_type: gold` 或者 `deployment_version: v2` 或者 `external_call: paypal` 获取错误率和 P99 延迟数据
- 原生支持 OpenTelemetry 日志,高级日志查询,自动收集 k8s 相关日志
@@ -101,7 +101,7 @@ SigNoz 帮助开发人员监控应用并排查已部署应用的问题。你可
我们想做一个自托管并且可开源的工具,像 DataDog 和 NewRelic 那样, 为那些担心数据隐私和安全的公司提供第三方服务。
作为开源的项目,你完全可以自己掌控你的配置、样本和更新。你同样可以基于 SigNoz 拓展特定的业务模块。
作为开源的项目,你完全可以自己掌控你的配置、样本和更新。你同样可以基于 SigNoz 拓展特定的业务模块。
### 支持的编程语言:
@@ -153,9 +153,9 @@ Jaeger 仅仅是一个分布式追踪系统。 但是 SigNoz 可以提供 metric
而且, SigNoz 相较于 Jaeger 拥有更对的高级功能:
- Jaegar UI 不能提供任何基于 traces 的 metrics 查询和过滤。
- Jaegar UI 不能提供任何基于 traces 的 metrics 查询和过滤。
- Jaeger 不能针对过滤的 traces 做聚合。 比如, p99 延迟的请求有个标签是 customer_type='premium'。 而这些在 SigNoz 可以轻松做到。
- Jaeger 不能针对过滤的 traces 做聚合。 比如, p99 延迟的请求有个标签是 customer_type='premium'。 而这些在 SigNoz 可以轻松做到。
<p>&nbsp </p>
@@ -185,7 +185,7 @@ Jaeger 仅仅是一个分布式追踪系统。 但是 SigNoz 可以提供 metric
我们 ❤️ 你的贡献,无论大小。 请先阅读 [CONTRIBUTING.md](CONTRIBUTING.md) 再开始给 SigNoz 做贡献。
如果你不知道如何开始? 只需要在 [slack 社区](https://signoz.io/slack) 通过 `#contributing` 频道联系我们。
如果你不知道如何开始? 只需要在 [slack 社区](https://signoz.io/slack) 通过 `#contributing` 频道联系我们。
### 项目维护人员
@@ -199,6 +199,8 @@ Jaeger 仅仅是一个分布式追踪系统。 但是 SigNoz 可以提供 metric
#### 前端
- [Palash Gupta](https://github.com/palashgdev)
- [Yunus M](https://github.com/YounixM)
- [Rajat Dabade](https://github.com/Rajat-Dabade)
#### 运维开发

View File

@@ -1,7 +1,7 @@
version: "3.9"
x-clickhouse-defaults: &clickhouse-defaults
image: clickhouse/clickhouse-server:23.7.3-alpine
image: clickhouse/clickhouse-server:23.11.1-alpine
tty: true
deploy:
restart_policy:
@@ -146,11 +146,11 @@ services:
condition: on-failure
query-service:
image: signoz/query-service:0.34.4
image: signoz/query-service:0.37.1
command:
[
"-config=/root/config/prometheus.yml",
"--prefer-delta=true"
# "--prefer-delta=true"
]
# ports:
# - "6060:6060" # pprof port
@@ -186,7 +186,7 @@ services:
<<: *db-depend
frontend:
image: signoz/frontend:0.34.4
image: signoz/frontend:0.37.1
deploy:
restart_policy:
condition: on-failure
@@ -199,7 +199,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector:
image: signoz/signoz-otel-collector:0.88.1
image: signoz/signoz-otel-collector:0.88.8
command:
[
"--config=/etc/otel-collector-config.yaml",
@@ -237,7 +237,7 @@ services:
- query-service
otel-collector-migrator:
image: signoz/signoz-schema-migrator:0.88.1
image: signoz/signoz-schema-migrator:0.88.8
deploy:
restart_policy:
condition: on-failure
@@ -249,25 +249,6 @@ services:
# - clickhouse-2
# - clickhouse-3
otel-collector-metrics:
image: signoz/signoz-otel-collector:0.88.1
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",
"--feature-gates=-pkg.translator.prometheus.NormalizeName"
]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
# ports:
# - "1777:1777" # pprof extension
# - "8888:8888" # OtelCollector internal metrics
# - "13133:13133" # Health check extension
# - "55679:55679" # zPages extension
deploy:
restart_policy:
condition: on-failure
<<: *db-depend
logspout:
image: "gliderlabs/logspout:v3.2.14"
volumes:

View File

@@ -15,13 +15,9 @@ receivers:
# please remove names from below if you want to collect logs from them
- type: filter
id: signoz_logs_filter
expr: 'attributes.container_name matches "^signoz_(logspout|frontend|alertmanager|query-service|otel-collector|otel-collector-metrics|clickhouse|zookeeper)"'
expr: 'attributes.container_name matches "^signoz_(logspout|frontend|alertmanager|query-service|otel-collector|clickhouse|zookeeper)"'
opencensus:
endpoint: 0.0.0.0:55678
otlp/spanmetrics:
protocols:
grpc:
endpoint: localhost:12345
otlp:
protocols:
grpc:
@@ -69,8 +65,8 @@ processors:
# Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels.
detectors: [env, system] # include ec2 for AWS, gcp for GCP and azure for Azure.
timeout: 2s
signozspanmetrics/prometheus:
metrics_exporter: prometheus
signozspanmetrics/cumulative:
metrics_exporter: clickhousemetricswrite
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000
dimensions:
@@ -97,6 +93,20 @@ processors:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
signozspanmetrics/delta:
metrics_exporter: clickhousemetricswrite
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000
aggregation_temporality: AGGREGATION_TEMPORALITY_DELTA
dimensions:
- name: service.namespace
default: default
- name: deployment.environment
default: default
# This is added to ensure the uniqueness of the timeseries
# Otherwise, identical timeseries produced by multiple replicas of
# collectors result in incorrect APM metrics
- name: signoz.collector.id
exporters:
clickhousetraces:
@@ -109,8 +119,6 @@ exporters:
enabled: true
clickhousemetricswrite/prometheus:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
prometheus:
endpoint: 0.0.0.0:8889
# logging: {}
clickhouselogsexporter:
dsn: tcp://clickhouse:9000/
@@ -140,7 +148,7 @@ service:
pipelines:
traces:
receivers: [jaeger, otlp]
processors: [signozspanmetrics/prometheus, batch]
processors: [signozspanmetrics/cumulative, signozspanmetrics/delta, batch]
exporters: [clickhousetraces]
metrics:
receivers: [otlp]
@@ -154,9 +162,6 @@ service:
receivers: [prometheus]
processors: [batch]
exporters: [clickhousemetricswrite/prometheus]
metrics/spanmetrics:
receivers: [otlp/spanmetrics]
exporters: [prometheus]
logs:
receivers: [otlp, tcplog/docker]
processors: [batch]

View File

@@ -1,64 +0,0 @@
receivers:
prometheus:
config:
scrape_configs:
# otel-collector-metrics internal metrics
- job_name: otel-collector-metrics
scrape_interval: 60s
static_configs:
- targets:
- localhost:8888
labels:
job_name: otel-collector-metrics
# SigNoz span metrics
- job_name: signozspanmetrics-collector
scrape_interval: 60s
dns_sd_configs:
- names:
- tasks.otel-collector
type: A
port: 8889
processors:
batch:
send_batch_size: 10000
send_batch_max_size: 11000
timeout: 10s
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
exporters:
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
extensions:
health_check:
endpoint: 0.0.0.0:13133
zpages:
endpoint: 0.0.0.0:55679
pprof:
endpoint: 0.0.0.0:1777
service:
telemetry:
metrics:
address: 0.0.0.0:8888
extensions: [health_check, zpages, pprof]
pipelines:
metrics:
receivers: [prometheus]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -66,7 +66,7 @@ services:
- --storage.path=/data
otel-collector-migrator:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.1}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.8}
container_name: otel-migrator
command:
- "--dsn=tcp://clickhouse:9000"
@@ -81,7 +81,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.88.1
image: signoz/signoz-otel-collector:0.88.8
command:
[
"--config=/etc/otel-collector-config.yaml",
@@ -116,28 +116,6 @@ services:
query-service:
condition: service_healthy
otel-collector-metrics:
container_name: signoz-otel-collector-metrics
image: signoz/signoz-otel-collector:0.88.1
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",
"--feature-gates=-pkg.translator.prometheus.NormalizeName"
]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
# ports:
# - "1777:1777" # pprof extension
# - "8888:8888" # OtelCollector internal metrics
# - "13133:13133" # Health check extension
# - "55679:55679" # zPages extension
restart: on-failure
depends_on:
clickhouse:
condition: service_healthy
otel-collector-migrator:
condition: service_completed_successfully
logspout:
image: "gliderlabs/logspout:v3.2.14"
container_name: signoz-logspout

View File

@@ -25,7 +25,7 @@ services:
command:
[
"-config=/root/config/prometheus.yml",
"--prefer-delta=true"
# "--prefer-delta=true"
]
ports:
- "6060:6060"

View File

@@ -3,7 +3,7 @@ version: "2.4"
x-clickhouse-defaults: &clickhouse-defaults
restart: on-failure
# addding non LTS version due to this fix https://github.com/ClickHouse/ClickHouse/commit/32caf8716352f45c1b617274c7508c86b7d1afab
image: clickhouse/clickhouse-server:23.7.3-alpine
image: clickhouse/clickhouse-server:23.11.1-alpine
tty: true
depends_on:
- zookeeper-1
@@ -164,12 +164,12 @@ 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.34.4}
image: signoz/query-service:${DOCKER_TAG:-0.37.1}
container_name: signoz-query-service
command:
[
"-config=/root/config/prometheus.yml",
"--prefer-delta=true"
# "--prefer-delta=true"
]
# ports:
# - "6060:6060" # pprof port
@@ -203,7 +203,7 @@ services:
<<: *db-depend
frontend:
image: signoz/frontend:${DOCKER_TAG:-0.34.4}
image: signoz/frontend:${DOCKER_TAG:-0.37.1}
container_name: signoz-frontend
restart: on-failure
depends_on:
@@ -215,7 +215,7 @@ services:
- ../common/nginx-config.conf:/etc/nginx/conf.d/default.conf
otel-collector-migrator:
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.1}
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-0.88.8}
container_name: otel-migrator
command:
- "--dsn=tcp://clickhouse:9000"
@@ -229,7 +229,7 @@ services:
otel-collector:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.1}
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.8}
container_name: signoz-otel-collector
command:
[
@@ -268,24 +268,6 @@ services:
query-service:
condition: service_healthy
otel-collector-metrics:
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-0.88.1}
container_name: signoz-otel-collector-metrics
command:
[
"--config=/etc/otel-collector-metrics-config.yaml",
"--feature-gates=-pkg.translator.prometheus.NormalizeName"
]
volumes:
- ./otel-collector-metrics-config.yaml:/etc/otel-collector-metrics-config.yaml
# ports:
# - "1777:1777" # pprof extension
# - "8888:8888" # OtelCollector internal metrics
# - "13133:13133" # Health check extension
# - "55679:55679" # zPages extension
restart: on-failure
<<: *db-depend
logspout:
image: "gliderlabs/logspout:v3.2.14"
container_name: signoz-logspout

View File

@@ -15,13 +15,9 @@ receivers:
# please remove names from below if you want to collect logs from them
- type: filter
id: signoz_logs_filter
expr: 'attributes.container_name matches "^signoz-(logspout|frontend|alertmanager|query-service|otel-collector|otel-collector-metrics|clickhouse|zookeeper)"'
expr: 'attributes.container_name matches "^signoz-(logspout|frontend|alertmanager|query-service|otel-collector|clickhouse|zookeeper)"'
opencensus:
endpoint: 0.0.0.0:55678
otlp/spanmetrics:
protocols:
grpc:
endpoint: localhost:12345
otlp:
protocols:
grpc:
@@ -66,8 +62,9 @@ processors:
send_batch_size: 10000
send_batch_max_size: 11000
timeout: 10s
signozspanmetrics/prometheus:
metrics_exporter: prometheus
signozspanmetrics/cumulative:
metrics_exporter: clickhousemetricswrite
metrics_flush_interval: 60s
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000
dimensions:
@@ -98,6 +95,21 @@ processors:
# Using OTEL_RESOURCE_ATTRIBUTES envvar, env detector adds custom labels.
detectors: [env, system] # include ec2 for AWS, gcp for GCP and azure for Azure.
timeout: 2s
signozspanmetrics/delta:
metrics_exporter: clickhousemetricswrite
metrics_flush_interval: 60s
latency_histogram_buckets: [100us, 1ms, 2ms, 6ms, 10ms, 50ms, 100ms, 250ms, 500ms, 1000ms, 1400ms, 2000ms, 5s, 10s, 20s, 40s, 60s ]
dimensions_cache_size: 100000
aggregation_temporality: AGGREGATION_TEMPORALITY_DELTA
dimensions:
- name: service.namespace
default: default
- name: deployment.environment
default: default
# This is added to ensure the uniqueness of the timeseries
# Otherwise, identical timeseries produced by multiple replicas of
# collectors result in incorrect APM metrics
- name: signoz.collector.id
extensions:
health_check:
@@ -118,8 +130,6 @@ exporters:
enabled: true
clickhousemetricswrite/prometheus:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
prometheus:
endpoint: 0.0.0.0:8889
# logging: {}
clickhouselogsexporter:
@@ -145,7 +155,7 @@ service:
pipelines:
traces:
receivers: [jaeger, otlp]
processors: [signozspanmetrics/prometheus, batch]
processors: [signozspanmetrics/cumulative, signozspanmetrics/delta, batch]
exporters: [clickhousetraces]
metrics:
receivers: [otlp]
@@ -159,9 +169,6 @@ service:
receivers: [prometheus]
processors: [batch]
exporters: [clickhousemetricswrite/prometheus]
metrics/spanmetrics:
receivers: [otlp/spanmetrics]
exporters: [prometheus]
logs:
receivers: [otlp, tcplog/docker]
processors: [batch]

View File

@@ -1,69 +0,0 @@
receivers:
otlp:
protocols:
grpc:
http:
prometheus:
config:
scrape_configs:
# otel-collector-metrics internal metrics
- job_name: otel-collector-metrics
scrape_interval: 60s
static_configs:
- targets:
- localhost:8888
labels:
job_name: otel-collector-metrics
# SigNoz span metrics
- job_name: signozspanmetrics-collector
scrape_interval: 60s
static_configs:
- targets:
- otel-collector:8889
processors:
batch:
send_batch_size: 10000
send_batch_max_size: 11000
timeout: 10s
# memory_limiter:
# # 80% of maximum memory up to 2G
# limit_mib: 1500
# # 25% of limit up to 2G
# spike_limit_mib: 512
# check_interval: 5s
#
# # 50% of the maximum memory
# limit_percentage: 50
# # 20% of max memory usage spike expected
# spike_limit_percentage: 20
# queued_retry:
# num_workers: 4
# queue_size: 100
# retry_on_failure: true
extensions:
health_check:
endpoint: 0.0.0.0:13133
zpages:
endpoint: 0.0.0.0:55679
pprof:
endpoint: 0.0.0.0:1777
exporters:
clickhousemetricswrite:
endpoint: tcp://clickhouse:9000/?database=signoz_metrics
service:
telemetry:
metrics:
address: 0.0.0.0:8888
extensions:
- health_check
- zpages
- pprof
pipelines:
metrics:
receivers: [prometheus]
processors: [batch]
exporters: [clickhousemetricswrite]

View File

@@ -1,5 +1,5 @@
# use a minimal alpine image
FROM alpine:3.18.3
FROM alpine:3.18.5
# Add Maintainer Info
LABEL maintainer="signoz"
@@ -18,6 +18,7 @@ COPY ee/query-service/bin/query-service-${TARGETOS}-${TARGETARCH} /root/query-se
# copy prometheus YAML config
COPY pkg/query-service/config/prometheus.yml /root/config/prometheus.yml
COPY pkg/query-service/templates /root/templates
# Make query-service executable for non-root users
RUN chmod 755 /root /root/query-service

View File

@@ -152,9 +152,9 @@ func (ah *APIHandler) RegisterRoutes(router *mux.Router, am *baseapp.AuthMiddlew
router.HandleFunc("/api/v2/metrics/query_range", am.ViewAccess(ah.queryRangeMetricsV2)).Methods(http.MethodPost)
// PAT APIs
router.HandleFunc("/api/v1/pat", am.OpenAccess(ah.createPAT)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/pat", am.OpenAccess(ah.getPATs)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/pat/{id}", am.OpenAccess(ah.deletePAT)).Methods(http.MethodDelete)
router.HandleFunc("/api/v1/pat", am.AdminAccess(ah.createPAT)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/pat", am.AdminAccess(ah.getPATs)).Methods(http.MethodGet)
router.HandleFunc("/api/v1/pat/{id}", am.AdminAccess(ah.deletePAT)).Methods(http.MethodDelete)
router.HandleFunc("/api/v1/checkout", am.AdminAccess(ah.checkout)).Methods(http.MethodPost)
router.HandleFunc("/api/v1/billing", am.AdminAccess(ah.getBilling)).Methods(http.MethodGet)

View File

@@ -40,6 +40,7 @@ type billingDetails struct {
BillingPeriodEnd int64 `json:"billingPeriodEnd"`
Details details `json:"details"`
Discount float64 `json:"discount"`
SubscriptionStatus string `json:"subscriptionStatus"`
} `json:"data"`
}

View File

@@ -12,6 +12,7 @@ import (
"github.com/gorilla/mux"
"go.signoz.io/signoz/ee/query-service/model"
"go.signoz.io/signoz/pkg/query-service/auth"
basemodel "go.signoz.io/signoz/pkg/query-service/model"
"go.uber.org/zap"
)
@@ -47,8 +48,18 @@ func (ah *APIHandler) createPAT(w http.ResponseWriter, r *http.Request) {
req.CreatedAt = time.Now().Unix()
req.Token = generatePATToken()
// default expiry is 30 days
if req.ExpiresAt == 0 {
req.ExpiresAt = time.Now().AddDate(0, 0, 30).Unix()
}
// max expiry is 1 year
if req.ExpiresAt > time.Now().AddDate(1, 0, 0).Unix() {
req.ExpiresAt = time.Now().AddDate(1, 0, 0).Unix()
}
zap.S().Debugf("Got PAT request: %+v", req)
if apierr := ah.AppDao().CreatePAT(ctx, &req); apierr != nil {
var apierr basemodel.BaseApiError
if req, apierr = ah.AppDao().CreatePAT(ctx, req); apierr != nil {
RespondError(w, apierr, nil)
return
}

View File

@@ -193,7 +193,7 @@ func NewServer(serverOptions *ServerOptions) (*Server, error) {
}
// start the usagemanager
usageManager, err := usage.New("sqlite", localDB, lm.GetRepo(), reader.GetConn())
usageManager, err := usage.New("sqlite", modelDao, lm.GetRepo(), reader.GetConn())
if err != nil {
return nil, err
}
@@ -331,6 +331,7 @@ func (s *Server) createPublicServer(apiHandler *api.APIHandler) (*http.Server, e
apiHandler.RegisterMetricsRoutes(r, am)
apiHandler.RegisterLogsRoutes(r, am)
apiHandler.RegisterQueryRangeV3Routes(r, am)
apiHandler.RegisterQueryRangeV4Routes(r, am)
c := cors.New(cors.Options{
AllowedOrigins: []string{"*"},
@@ -480,7 +481,7 @@ func (s *Server) analyticsMiddleware(next http.Handler) http.Handler {
}
}
if _, ok := telemetry.IgnoredPaths()[path]; !ok {
if _, ok := telemetry.EnabledPaths()[path]; ok {
userEmail, err := auth.GetEmailFromJwt(r.Context())
if err == nil {
telemetry.GetInstance().SendEvent(telemetry.TELEMETRY_EVENT_PATH, data, userEmail)

View File

@@ -33,7 +33,7 @@ type ModelDao interface {
DeleteDomain(ctx context.Context, id uuid.UUID) basemodel.BaseApiError
GetDomainByEmail(ctx context.Context, email string) (*model.OrgDomain, basemodel.BaseApiError)
CreatePAT(ctx context.Context, p *model.PAT) basemodel.BaseApiError
CreatePAT(ctx context.Context, p model.PAT) (model.PAT, basemodel.BaseApiError)
GetPAT(ctx context.Context, pat string) (*model.PAT, basemodel.BaseApiError)
GetPATByID(ctx context.Context, id string) (*model.PAT, basemodel.BaseApiError)
GetUserByPAT(ctx context.Context, token string) (*basemodel.UserPayload, basemodel.BaseApiError)

View File

@@ -3,14 +3,15 @@ package sqlite
import (
"context"
"fmt"
"strconv"
"go.signoz.io/signoz/ee/query-service/model"
basemodel "go.signoz.io/signoz/pkg/query-service/model"
"go.uber.org/zap"
)
func (m *modelDao) CreatePAT(ctx context.Context, p *model.PAT) basemodel.BaseApiError {
_, err := m.DB().ExecContext(ctx,
func (m *modelDao) CreatePAT(ctx context.Context, p model.PAT) (model.PAT, basemodel.BaseApiError) {
result, err := m.DB().ExecContext(ctx,
"INSERT INTO personal_access_tokens (user_id, token, name, created_at, expires_at) VALUES ($1, $2, $3, $4, $5)",
p.UserID,
p.Token,
@@ -19,9 +20,15 @@ func (m *modelDao) CreatePAT(ctx context.Context, p *model.PAT) basemodel.BaseAp
p.ExpiresAt)
if err != nil {
zap.S().Errorf("Failed to insert PAT in db, err: %v", zap.Error(err))
return model.InternalError(fmt.Errorf("PAT insertion failed"))
return model.PAT{}, model.InternalError(fmt.Errorf("PAT insertion failed"))
}
return nil
id, err := result.LastInsertId()
if err != nil {
zap.S().Errorf("Failed to get last inserted id, err: %v", zap.Error(err))
return model.PAT{}, model.InternalError(fmt.Errorf("PAT insertion failed"))
}
p.Id = strconv.Itoa(int(id))
return p, nil
}
func (m *modelDao) ListPATs(ctx context.Context, userID string) ([]model.PAT, basemodel.BaseApiError) {
@@ -90,7 +97,7 @@ func (m *modelDao) GetUserByPAT(ctx context.Context, token string) (*basemodel.U
u.org_id,
u.group_id
FROM users u, personal_access_tokens p
WHERE u.id = p.user_id and p.token=?;`
WHERE u.id = p.user_id and p.token=? and p.expires_at >= strftime('%s', 'now');`
if err := m.DB().Select(&users, query, token); err != nil {
return nil, model.InternalError(fmt.Errorf("failed to fetch user from PAT, err: %v", err))

View File

@@ -6,5 +6,5 @@ type PAT struct {
Token string `json:"token" db:"token"`
Name string `json:"name" db:"name"`
CreatedAt int64 `json:"createdAt" db:"created_at"`
ExpiresAt int64 `json:"expiresAt" db:"expires_at"` // unused as of now
ExpiresAt int64 `json:"expiresAt" db:"expires_at"`
}

View File

@@ -52,14 +52,14 @@ var BasicPlan = basemodel.FeatureSet{
Name: basemodel.QueryBuilderPanels,
Active: true,
Usage: 0,
UsageLimit: 5,
UsageLimit: 20,
Route: "",
},
basemodel.Feature{
Name: basemodel.QueryBuilderAlerts,
Active: true,
Usage: 0,
UsageLimit: 5,
UsageLimit: 10,
Route: "",
},
basemodel.Feature{

View File

@@ -20,6 +20,8 @@ type Usage struct {
TimeStamp time.Time `json:"timestamp"`
Count int64 `json:"count"`
Size int64 `json:"size"`
OrgName string `json:"orgName"`
TenantId string `json:"tenantId"`
}
type UsageDB struct {

View File

@@ -4,6 +4,8 @@ import (
"context"
"encoding/json"
"fmt"
"os"
"regexp"
"strings"
"sync/atomic"
"time"
@@ -11,10 +13,10 @@ import (
"github.com/ClickHouse/clickhouse-go/v2"
"github.com/go-co-op/gocron"
"github.com/google/uuid"
"github.com/jmoiron/sqlx"
"go.uber.org/zap"
"go.signoz.io/signoz/ee/query-service/dao"
licenseserver "go.signoz.io/signoz/ee/query-service/integrations/signozio"
"go.signoz.io/signoz/ee/query-service/license"
"go.signoz.io/signoz/ee/query-service/model"
@@ -38,15 +40,29 @@ type Manager struct {
licenseRepo *license.Repo
scheduler *gocron.Scheduler
modelDao dao.ModelDao
tenantID string
}
func New(dbType string, db *sqlx.DB, licenseRepo *license.Repo, clickhouseConn clickhouse.Conn) (*Manager, error) {
func New(dbType string, modelDao dao.ModelDao, licenseRepo *license.Repo, clickhouseConn clickhouse.Conn) (*Manager, error) {
hostNameRegex := regexp.MustCompile(`tcp://(?P<hostname>.*):`)
hostNameRegexMatches := hostNameRegex.FindStringSubmatch(os.Getenv("ClickHouseUrl"))
tenantID := ""
if len(hostNameRegexMatches) == 2 {
tenantID = hostNameRegexMatches[1]
tenantID = strings.TrimRight(tenantID, "-clickhouse")
}
m := &Manager{
// repository: repo,
clickhouseConn: clickhouseConn,
licenseRepo: licenseRepo,
scheduler: gocron.NewScheduler(time.UTC).Every(1).Day().At("00:00"), // send usage every at 00:00 UTC
modelDao: modelDao,
tenantID: tenantID,
}
return m, nil
}
@@ -123,6 +139,19 @@ func (lm *Manager) UploadUsage() {
zap.S().Info("uploading usage data")
// Try to get the org name
orgName := ""
orgNames, err := lm.modelDao.GetOrgs(ctx)
if err != nil {
zap.S().Errorf("failed to get org data: %v", zap.Error(err))
} else {
if len(orgNames) != 1 {
zap.S().Errorf("expected one org but got %d orgs", len(orgNames))
} else {
orgName = orgNames[0].Name
}
}
usagesPayload := []model.Usage{}
for _, usage := range usages {
usageDataBytes, err := encryption.Decrypt([]byte(usage.ExporterID[:32]), []byte(usage.Data))
@@ -142,6 +171,8 @@ func (lm *Manager) UploadUsage() {
usageData.ExporterID = usage.ExporterID
usageData.Type = usage.Type
usageData.Tenant = usage.Tenant
usageData.OrgName = orgName
usageData.TenantId = lm.tenantID
usagesPayload = append(usagesPayload, usageData)
}

View File

@@ -86,6 +86,7 @@ module.exports = {
},
],
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
'no-plusplus': 'off',
'jsx-a11y/label-has-associated-control': [
'error',
{
@@ -109,7 +110,6 @@ module.exports = {
// eslint rules need to remove
'@typescript-eslint/no-shadow': 'off',
'import/no-cycle': 'off',
'prettier/prettier': [
'error',
{},

View File

@@ -2,3 +2,19 @@
. "$(dirname "$0")/_/husky.sh"
cd frontend && yarn run commitlint --edit $1
branch="$(git rev-parse --abbrev-ref HEAD)"
color_red="$(tput setaf 1)"
bold="$(tput bold)"
reset="$(tput sgr0)"
if [ "$branch" = "main" ]; then
echo "${color_red}${bold}You can't commit directly to the main branch${reset}"
exit 1
fi
if [ "$branch" = "develop" ]; then
echo "${color_red}${bold}You can't commit directly to the develop branch${reset}"
exit 1
fi

View File

@@ -22,7 +22,7 @@ const config: Config.InitialOptions = {
'^.+\\.(js|jsx)$': 'babel-jest',
},
transformIgnorePatterns: [
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend)/)',
'node_modules/(?!(lodash-es|react-dnd|core-dnd|@react-dnd|dnd-core|react-dnd-html5-backend|axios|@signozhq/design-tokens)/)',
],
setupFilesAfterEnv: ['<rootDir>jest.setup.ts'],
testPathIgnorePatterns: ['/node_modules/', '/public/'],

View File

@@ -29,16 +29,22 @@
"dependencies": {
"@ant-design/colors": "6.0.0",
"@ant-design/icons": "4.8.0",
"@dnd-kit/core": "6.1.0",
"@dnd-kit/modifiers": "7.0.0",
"@dnd-kit/sortable": "8.0.0",
"@grafana/data": "^9.5.2",
"@mdx-js/loader": "2.3.0",
"@mdx-js/react": "2.3.0",
"@monaco-editor/react": "^4.3.1",
"@radix-ui/react-tabs": "1.0.4",
"@radix-ui/react-tooltip": "1.0.7",
"@signozhq/design-tokens": "0.0.8",
"@uiw/react-md-editor": "3.23.5",
"@xstate/react": "^3.0.0",
"ansi-to-html": "0.7.2",
"antd": "5.11.0",
"antd-table-saveas-excel": "2.2.1",
"axios": "^0.21.0",
"axios": "1.6.2",
"babel-eslint": "^10.1.0",
"babel-jest": "^29.6.4",
"babel-loader": "9.1.3",
@@ -71,7 +77,7 @@
"less": "^4.1.2",
"less-loader": "^10.2.0",
"lodash-es": "^4.17.21",
"lucide-react": "0.288.0",
"lucide-react": "0.321.0",
"mini-css-extract-plugin": "2.4.5",
"papaparse": "5.4.1",
"react": "18.2.0",
@@ -87,7 +93,7 @@
"react-helmet-async": "1.3.0",
"react-i18next": "^11.16.1",
"react-markdown": "8.0.7",
"react-query": "^3.34.19",
"react-query": "3.39.3",
"react-redux": "^7.2.2",
"react-router-dom": "^5.2.0",
"react-syntax-highlighter": "15.5.0",

View File

@@ -0,0 +1 @@
<svg width="32" height="33" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M15.91 28.675c-6.199 0-12.888-3.888-12.888-12.421S9.711 3.832 15.911 3.832c3.444 0 6.621 1.134 8.977 3.2 2.555 2.267 3.91 5.466 3.91 9.222 0 3.755-1.355 6.933-3.91 9.2-2.356 2.066-5.555 3.221-8.977 3.221z" fill="url(#prefix__paint0_radial_2122_6520)"/><path d="M26.552 8.87c1.185 1.91 1.803 4.186 1.803 6.717 0 3.756-1.356 6.933-3.911 9.2-2.356 2.066-5.556 3.222-8.978 3.222-4.013 0-8.221-1.634-10.706-5.098 2.391 3.924 6.889 5.764 11.15 5.764 3.423 0 6.623-1.155 8.978-3.222 2.555-2.266 3.911-5.444 3.911-9.2 0-2.83-.771-5.346-2.247-7.383z" fill="#EB8F00"/><path d="M20.123 22.905c0 1.685-1.846 2.667-4.124 2.667-2.277 0-4.124-.989-4.124-2.667 0-1.677 1.847-3.522 4.124-3.522 2.278 0 4.124 1.838 4.124 3.522zM12.06 14.852l1.88-1.748c.267-.331.307-.778.038-1.045-.353-.355-.98-.269-1.32.136-.018.033-.03.042-.049.075l-1.333 1.938-1.804-1.682c-.027-.03-.042-.034-.067-.062-.42-.32-1.05-.267-1.315.157-.207.32-.07.745.264 1.011l2.313 1.372-1.96 1.833c-.262.326-.31.77-.04 1.044.351.358.978.276 1.32-.127.018-.033.031-.042.051-.075l1.405-2.031 1.706 1.609c.027.029.043.035.067.064.418.322 1.049.273 1.318-.149.206-.32.07-.746-.26-1.013l-2.213-1.307zM20.61 14.852l-1.879-1.748c-.267-.331-.307-.778-.036-1.045.354-.355.978-.269 1.318.136.018.033.034.042.051.075l1.334 1.938 1.806-1.682c.025-.03.04-.034.065-.062.422-.32 1.05-.267 1.317.157.205.32.067.745-.266 1.011L22 15.004l1.96 1.833c.268.33.313.775.042 1.044-.349.358-.976.276-1.318-.127-.02-.033-.033-.042-.051-.075l-1.404-2.031-1.71 1.609c-.024.029-.04.035-.066.064-.418.322-1.046.273-1.315-.149-.21-.32-.074-.746.257-1.013l2.216-1.307zM11.911 8.696c.511.044.711-.645.178-.8a4.07 4.07 0 00-1.289-.133A4.596 4.596 0 007.689 9.14c-.378.4.156.89.556.6a5.829 5.829 0 013.666-1.044zM20.044 8.696a5.85 5.85 0 013.689 1.044c.4.29.933-.2.555-.6a4.645 4.645 0 00-3.11-1.377 4.07 4.07 0 00-1.29.133.408.408 0 00-.282.504c.053.194.24.318.438.296z" fill="#422B0D"/><defs><radialGradient id="prefix__paint0_radial_2122_6520" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(15.91 16.254) scale(12.657)"><stop offset=".5" stop-color="#FDE030"/><stop offset=".92" stop-color="#F7C02B"/><stop offset="1" stop-color="#F4A223"/></radialGradient></defs></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@@ -0,0 +1 @@
<svg width="32" height="33" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M14.309 13.108l-6.704-3.32s-.016-.317.284-.477c.302-.16 5.053-2.107 5.435-2.107.383 0 2.62.431 4.249.793 1.629.363 5.933 1.287 5.953 1.57.02.281-4.404 4.806-4.404 4.806l-4.813-1.265z" fill="#C3FECE"/><path d="M20.423 11.037s-2.811-.826-5.546-1.469c-1.274-.3-5.016-1.084-5.016-1.084s.398-.173.698-.3c.305-.127.547-.193.547-.193s2.44.486 4.253.873c2.453.522 5.886 1.547 5.966 1.709.082.16-.902.464-.902.464z" fill="#fff"/><path d="M14.98 10.26c-.598.415-.011.666 1.09.924 1.207.282 2.127.698 2.903.247.7-.405-1.014-.845-1.8-1.014-.6-.129-1.731-.478-2.193-.158z" fill="#ACB1B2"/><path d="M17.17 11.095c-.005 0 .02-4.869.02-5.049 0-.18-.203-.342.02-.724.222-.382.804-.342.804-.342s2.416-.702 3.38-.945c.964-.242 3.098-.804 3.098-.804l.142 1.22s-2.236.631-3.342.913c-1.107.282-2.616.745-2.616.745l-.222.202.064 4.757s-.206.231-.668.231c-.45-.002-.68-.204-.68-.204z" fill="#FFD816"/><path d="M24.095 3.855c.018.38.22.616.46.616.24 0 .404-.307.369-.707-.038-.398-.296-.58-.516-.506-.22.073-.327.32-.313.597zM18.46 6.422a.209.209 0 01-.123-.038l-1.153-.769a.225.225 0 01-.063-.309.222.222 0 01.31-.062l1.153.769a.224.224 0 01.062.309.228.228 0 01-.187.1z" fill="#FEB804"/><path d="M18.636 6.235a.225.225 0 01-.178-.089c-.295-.393-.633-.84-.693-.909a.225.225 0 01-.031-.284.222.222 0 01.309-.062c.04.027.062.042.771.986.073.098.007.238-.091.312-.04.03-.04.046-.087.046z" fill="#FEB804"/><path d="M18.365 6.609c-.01 0-.022 0-.035-.003l-1.111-.175a.221.221 0 11.069-.438l1.11.176c.12.02.225.042.205.164-.016.107-.129.276-.238.276z" fill="#FEB804"/><path d="M7.596 9.764c.353 0 3.188.744 4.65 1.013 1.463.27 5.878 1.314 6.027 1.342.149.03.12 1.94.12 1.94s2.089 10.8 2.029 11.309c-.06.506-1.431 4.415-1.431 4.415s-.807.12-2.865-.478c-2.057-.598-7.488-2.089-7.817-2.506-.329-.418-.12-5.938-.298-9.338-.182-3.402-.415-7.697-.415-7.697z" fill="#79DD8A"/><path d="M24.06 27.036c.113-.375-.518-4.402-.607-8.101-.089-3.698.229-9.324.076-9.369-.154-.042-5.256 2.553-5.256 2.553s-.022 3.671.04 7.133c.08 4.48.438 10.41.676 10.53.238.12 2.302-1.035 2.924-1.372 1.102-.598 2.058-1.074 2.147-1.374z" fill="#02AB46"/><path d="M20.408 13.82l.011-2.787.914-.45.026 3.056-.422.74-.529-.56z" fill="#DBDFE1"/><path d="M12.322 14.797c-1.973-.211-3.34 1.549-3.233 3.842.127 2.709 1.91 4.704 3.842 5.102 1.93.398 3.802-.44 3.842-3.402.044-3.087-2.669-5.353-4.451-5.542z" fill="#FEFEFD"/><path d="M13.637 17.27s-.4-1.344-1.602-.986c-1.202.357-1.853 2.973.187 4.15 1.96 1.131 3.764-.944 3.133-2.288-.574-1.227-1.718-.876-1.718-.876z" fill="#EF5B44"/><path d="M13.18 15.626c-.136.049-.243.602-.1 1.13.106.396.446.939.643.903.158-.029.278-.651.13-1.173-.174-.602-.516-.918-.674-.86z" fill="#B8CF17"/><path d="M13.15 18.746c-.564-.171-1.2 1.769-.057 2.977 1.26 1.331 2.73.158 2.69-.1-.057-.358-1.044-.615-1.53-1.215-.487-.605-.774-1.562-1.102-1.662z" fill="#FD8F01"/><path d="M11.346 18.417s.113-.849-.673-.802c-.76.046-.574.944-.574.944s-.633.076-.526.778c.08.53.64.524.64.524s-.616.242-.336.945c.249.624.822.373.822.373s-.21.609.287.93c.42.272.787.043.787.043s-.023.52.557.616c.703.115 1.007-.74.507-1.136-.38-.3-.724-.067-.724-.067s.07-.166.004-.357c-.045-.125-.116-.171-.116-.171s.616-.058.516-.758c-.1-.702-.716-.616-.716-.616s.358-.286.216-.802c-.14-.518-.671-.444-.671-.444z" fill="#A281D0"/><path d="M21.04 14.595c-.511 0-2.691-2.167-2.711-2.189a.222.222 0 01.024-.313.224.224 0 01.314.022c.14.155 1.806 1.702 2.286 2 .311-.465 1.322-2.498 2.191-4.333a.224.224 0 01.296-.107.223.223 0 01.106.296c-2.142 4.526-2.353 4.586-2.466 4.617-.013.007-.027.007-.04.007z" fill="#2D802D"/></svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@@ -0,0 +1,19 @@
<svg width="32" height="33" viewBox="0 0 32 33" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.36806 25.9481C5.93935 25.9481 3.15283 21.7098 3.15283 16.5002C3.15283 11.2907 5.94157 7.05238 9.36806 7.05238C12.7945 7.05238 15.5833 11.2907 15.5833 16.5002C15.5833 21.7098 12.7945 25.9481 9.36806 25.9481Z" fill="#FAFAFA"/>
<path d="M9.36815 7.49694C10.8414 7.49694 12.2524 8.38594 13.3391 10.0017C14.499 11.7241 15.139 14.0333 15.139 16.5003C15.139 18.9673 14.499 21.2764 13.3391 22.9989C12.2524 24.6146 10.8414 25.5036 9.36815 25.5036C7.89489 25.5036 6.48385 24.6146 5.39724 22.9989C4.23508 21.2764 3.59734 18.9673 3.59734 16.5003C3.59734 14.0333 4.23731 11.7241 5.39724 10.0017C6.48385 8.38594 7.89267 7.49694 9.36815 7.49694ZM9.36815 6.60794C5.69056 6.60794 2.7085 11.0374 2.7085 16.5003C2.7085 21.9632 5.69056 26.3926 9.36815 26.3926C13.0457 26.3926 16.0278 21.9632 16.0278 16.5003C16.0278 11.0374 13.0457 6.60794 9.36815 6.60794Z" fill="#B0BEC5"/>
<path d="M7.47266 15.5762C6.87269 15.0118 7.00602 13.8919 7.77487 13.0741C7.81486 13.0319 7.85486 12.9919 7.89708 12.9541C7.55488 12.7608 7.17934 12.6519 6.78381 12.6519C5.18611 12.6519 3.89062 14.414 3.89062 16.585C3.89062 18.756 5.18611 20.5182 6.78381 20.5182C8.3815 20.5182 9.67699 18.756 9.67699 16.585C9.67699 16.1962 9.63477 15.8184 9.55699 15.4629C8.83703 15.9806 7.97708 16.0495 7.47266 15.5762Z" fill="url(#paint0_linear_2122_5062)"/>
<path d="M22.6294 26.3932C26.3074 26.3932 29.289 21.9642 29.289 16.5008C29.289 11.0374 26.3074 6.60847 22.6294 6.60847C18.9514 6.60847 15.9697 11.0374 15.9697 16.5008C15.9697 21.9642 18.9514 26.3932 22.6294 26.3932Z" fill="#EEEEEE"/>
<path d="M22.6283 25.9493C19.2018 25.9493 16.4131 21.711 16.4131 16.5014C16.4131 11.2919 19.2018 7.05357 22.6283 7.05357C26.0548 7.05357 28.8435 11.2919 28.8435 16.5014C28.8435 21.711 26.057 25.9493 22.6283 25.9493Z" fill="#FAFAFA"/>
<path d="M22.6284 7.49816C24.1017 7.49816 25.5127 8.38716 26.5993 10.0029C27.7592 11.7254 28.3992 14.0345 28.3992 16.5015C28.3992 18.9685 27.7592 21.2777 26.5993 23.0001C25.5127 24.6159 24.1017 25.5049 22.6284 25.5049C21.1551 25.5049 19.7441 24.6159 18.6575 23.0001C17.4976 21.2777 16.8576 18.9685 16.8576 16.5015C16.8576 14.0345 17.4976 11.7254 18.6575 10.0029C19.7441 8.38716 21.1551 7.49816 22.6284 7.49816ZM22.6284 6.60916C18.9508 6.60916 15.9688 11.0386 15.9688 16.5015C15.9688 21.9644 18.9508 26.3939 22.6284 26.3939C26.306 26.3939 29.2881 21.9644 29.2881 16.5015C29.2881 11.0386 26.306 6.60916 22.6284 6.60916Z" fill="#B0BEC5"/>
<path d="M20.7339 15.5767C20.1339 15.0123 20.2672 13.8924 21.0361 13.0746C21.0761 13.0324 21.1161 12.9924 21.1583 12.9546C20.8161 12.7613 20.4406 12.6524 20.045 12.6524C18.4473 12.6524 17.1519 14.4146 17.1519 16.5856C17.1519 18.7566 18.4473 20.5187 20.045 20.5187C21.6427 20.5187 22.9382 18.7566 22.9382 16.5856C22.9382 16.1967 22.896 15.8189 22.8182 15.4634C22.1005 15.9812 21.2383 16.05 20.7339 15.5767Z" fill="url(#paint1_linear_2122_5062)"/>
<defs>
<linearGradient id="paint0_linear_2122_5062" x1="6.78232" y1="12.651" x2="6.78232" y2="20.5188" gradientUnits="userSpaceOnUse">
<stop stop-color="#424242"/>
<stop offset="1" stop-color="#212121"/>
</linearGradient>
<linearGradient id="paint1_linear_2122_5062" x1="20.0449" y1="12.6515" x2="20.0449" y2="20.5193" gradientUnits="userSpaceOnUse">
<stop stop-color="#424242"/>
<stop offset="1" stop-color="#212121"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 957 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,11 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_2048_2251)">
<path opacity="0.9" d="M8.02226 15.9866C3.56539 15.9866 -6.10352e-05 12.4896 -6.10352e-05 8.11832C-6.10352e-05 3.79075 3.56539 0.25 8.02226 0.25H13.0584C14.7075 0.25 15.9999 1.56139 15.9999 3.13506V8.11832C15.9999 12.4896 12.4345 15.9866 8.02226 15.9866Z" fill="#F25733"/>
<path d="M7.95919 4.71207C4.63025 4.71207 2.75514 7.46868 2.67693 7.58603C2.48413 7.87508 2.48413 8.24888 2.67707 8.53816C2.75514 8.65528 4.63025 11.4119 7.95919 11.4119C11.2881 11.4119 13.1633 8.65528 13.2414 8.53792C13.4342 8.24888 13.4342 7.87508 13.2413 7.58582C13.1632 7.46868 11.2881 4.71207 7.95919 4.71207ZM3.13771 8.23088C3.06925 8.12832 3.06925 7.99571 3.13771 7.89307C3.20059 7.79867 4.53564 5.83764 6.92256 5.36723C5.84092 5.78476 5.07127 6.83485 5.07127 8.062C5.07127 9.28912 5.84092 10.3392 6.92256 10.7567C4.53564 10.2863 3.20059 8.32528 3.13771 8.23088ZM6.62838 8.062C6.62838 8.21488 6.50443 8.3388 6.35151 8.3388C6.19859 8.3388 6.07465 8.21488 6.07465 8.062C6.07465 7.02287 6.92003 6.17748 7.95916 6.17748C8.11207 6.17748 8.23599 6.30141 8.23599 6.45434C8.23599 6.60727 8.11207 6.73119 7.95916 6.73119C7.22535 6.73119 6.62838 7.32815 6.62838 8.062ZM7.95919 8.73504C7.58803 8.73504 7.2861 8.43312 7.2861 8.062C7.2861 7.69085 7.58803 7.3889 7.95919 7.3889C8.33039 7.3889 8.63231 7.69083 8.63231 8.062C8.63231 8.43312 8.33039 8.73504 7.95919 8.73504ZM12.7806 8.23088C12.7178 8.32528 11.3827 10.2863 8.99583 10.7567C10.0775 10.3392 10.8471 9.28912 10.8471 8.062C10.8471 6.83487 10.0775 5.78477 8.99583 5.36724C11.3827 5.83768 12.7178 7.7987 12.7806 7.89307C12.8491 7.99571 12.8491 8.12832 12.7806 8.23088Z" fill="#F9F2F9"/>
</g>
<defs>
<clipPath id="clip0_2048_2251">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -62,6 +62,7 @@
"button_cancel": "No",
"field_promql_expr": "PromQL Expression",
"field_alert_name": "Alert Name",
"field_notification_channel": "Notification Channel",
"field_alert_desc": "Alert Description",
"field_labels": "Labels",
"field_severity": "Severity",
@@ -100,7 +101,7 @@
"user_guide_ch_step3a": "Set alert severity, name and descriptions",
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
"user_tooltip_more_help": "More details on how to create alerts",
"choose_alert_type": "Choose a type for the alert:",
"choose_alert_type": "Choose a type for the alert",
"metric_based_alert": "Metric based Alert",
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
"log_based_alert": "Log-based Alert",

View File

@@ -21,5 +21,9 @@
"error_while_updating_variable": "Error while updating variable",
"dashboard_has_been_updated": "Dashboard has been updated",
"do_you_want_to_refresh_the_dashboard": "Do you want to refresh the dashboard?",
"delete_dashboard_success": "{{name}} dashboard deleted successfully"
"delete_dashboard_success": "{{name}} dashboard deleted successfully",
"dashboard_unsave_changes": "There are unsaved changes in the Query builder, please stage and run the query or the changes will be lost. Press OK to discard.",
"dashboard_save_changes": "Your graph built with {{queryTag}} query will be saved. Press OK to confirm.",
"your_graph_build_with": "Your graph built with",
"dashboar_ok_confirm": "query will be saved. Press OK to confirm."
}

View File

@@ -14,5 +14,6 @@
"delete_domain_message": "Are you sure you want to delete this domain?",
"delete_domain": "Delete Domain",
"add_domain": "Add Domains",
"saml_settings":"Your SAML settings have been saved, please login from incognito window to confirm that it has been set up correctly"
"saml_settings": "Your SAML settings have been saved, please login from incognito window to confirm that it has been set up correctly",
"invite_link_share_manually": "After inviting members, please copy the invite link and send them the link manually"
}

View File

@@ -3,6 +3,7 @@
"alert_channels": "Alert Channels",
"organization_settings": "Organization Settings",
"ingestion_settings": "Ingestion Settings",
"api_keys": "API Keys",
"my_settings": "My Settings",
"overview_metrics": "Overview Metrics",
"dbcall_metrics": "Database Calls",

View File

@@ -54,6 +54,7 @@
"field_promql_expr": "PromQL Expression",
"field_alert_name": "Alert Name",
"field_alert_desc": "Alert Description",
"field_notification_channel": "Notification Channel",
"field_labels": "Labels",
"field_severity": "Severity",
"option_critical": "Critical",

View File

@@ -0,0 +1,3 @@
{
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support."
}

View File

@@ -26,6 +26,7 @@
"MY_SETTINGS": "SigNoz | My Settings",
"ORG_SETTINGS": "SigNoz | Organization Settings",
"INGESTION_SETTINGS": "SigNoz | Ingestion Settings",
"API_KEYS": "SigNoz | API Keys",
"SOMETHING_WENT_WRONG": "SigNoz | Something Went Wrong",
"UN_AUTHORIZED": "SigNoz | Unauthorized",
"NOT_FOUND": "SigNoz | Page Not Found",

View File

@@ -63,6 +63,7 @@
"field_promql_expr": "PromQL Expression",
"field_alert_name": "Alert Name",
"field_alert_desc": "Alert Description",
"field_notification_channel": "Notification Channel",
"field_labels": "Labels",
"field_severity": "Severity",
"option_critical": "Critical",
@@ -100,7 +101,7 @@
"user_guide_ch_step3a": "Set alert severity, name and descriptions",
"user_guide_ch_step3b": "Add tags to the alert in the Label field if needed",
"user_tooltip_more_help": "More details on how to create alerts",
"choose_alert_type": "Choose a type for the alert:",
"choose_alert_type": "Choose a type for the alert",
"metric_based_alert": "Metric based Alert",
"metric_based_alert_desc": "Send a notification when a condition occurs in the metric data",
"log_based_alert": "Log-based Alert",

View File

@@ -0,0 +1,3 @@
{
"delete_confirm_message": "Are you sure you want to delete {{keyName}} key? Deleting a key is irreversible and cannot be undone."
}

View File

@@ -24,5 +24,9 @@
"do_you_want_to_refresh_the_dashboard": "Do you want to refresh the dashboard?",
"locked_dashboard_delete_tooltip_admin_author": "Dashboard is locked. Please unlock the dashboard to enable delete.",
"locked_dashboard_delete_tooltip_editor": "Dashboard is locked. Please contact admin to delete the dashboard.",
"delete_dashboard_success": "{{name}} dashboard deleted successfully"
"delete_dashboard_success": "{{name}} dashboard deleted successfully",
"dashboard_unsave_changes": "There are unsaved changes in the Query builder, please stage and run the query or the changes will be lost. Press OK to discard.",
"dashboard_save_changes": "Your graph built with {{queryTag}} query will be saved. Press OK to confirm.",
"your_graph_build_with": "Your graph built with",
"dashboar_ok_confirm": "query will be saved. Press OK to confirm."
}

View File

@@ -1,3 +1,4 @@
{
"name_of_the_view": "Name of the view"
"name_of_the_view": "Name of the view",
"delete_confirm_message": "Are you sure you want to delete {{viewName}} view? Deleting a view is irreversible and cannot be undone."
}

View File

@@ -14,5 +14,6 @@
"delete_domain_message": "Are you sure you want to delete this domain?",
"delete_domain": "Delete Domain",
"add_domain": "Add Domains",
"saml_settings":"Your SAML settings have been saved, please login from incognito window to confirm that it has been set up correctly"
"saml_settings": "Your SAML settings have been saved, please login from incognito window to confirm that it has been set up correctly",
"invite_link_share_manually": "After inviting members, please copy the invite link and send them the link manually"
}

View File

@@ -3,6 +3,7 @@
"alert_channels": "Alert Channels",
"organization_settings": "Organization Settings",
"ingestion_settings": "Ingestion Settings",
"api_keys": "API Keys",
"my_settings": "My Settings",
"overview_metrics": "Overview Metrics",
"dbcall_metrics": "Database Calls",

View File

@@ -54,6 +54,7 @@
"field_promql_expr": "PromQL Expression",
"field_alert_name": "Alert Name",
"field_alert_desc": "Alert Description",
"field_notification_channel": "Notification Channel",
"field_labels": "Labels",
"field_severity": "Severity",
"option_critical": "Critical",

View File

@@ -0,0 +1,3 @@
{
"rps_over_100": "You are sending data at more than 100 RPS, your ingestion may be rate limited. Please reach out to us via Intercom support."
}

View File

@@ -26,11 +26,13 @@
"MY_SETTINGS": "SigNoz | My Settings",
"ORG_SETTINGS": "SigNoz | Organization Settings",
"INGESTION_SETTINGS": "SigNoz | Ingestion Settings",
"API_KEYS": "SigNoz | API Keys",
"SOMETHING_WENT_WRONG": "SigNoz | Something Went Wrong",
"UN_AUTHORIZED": "SigNoz | Unauthorized",
"NOT_FOUND": "SigNoz | Page Not Found",
"LOGS": "SigNoz | Logs",
"LOGS_EXPLORER": "SigNoz | Logs Explorer",
"OLD_LOGS_EXPLORER": "SigNoz | Old Logs Explorer",
"LIVE_LOGS": "SigNoz | Live Logs",
"LOGS_PIPELINES": "SigNoz | Logs Pipelines",
"HOME_PAGE": "Open source Observability Platform | SigNoz",
@@ -38,5 +40,7 @@
"LIST_LICENSES": "SigNoz | List of Licenses",
"WORKSPACE_LOCKED": "SigNoz | Workspace Locked",
"SUPPORT": "SigNoz | Support",
"LOGS_SAVE_VIEWS": "SigNoz | Logs Save Views",
"TRACES_SAVE_VIEWS": "SigNoz | Traces Save Views",
"DEFAULT": "Open source Observability Platform | SigNoz"
}

View File

@@ -98,6 +98,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
if (
userResponse &&
route &&
route.find((e) => e === userResponse.payload.role) === undefined
) {
history.push(ROUTES.UN_AUTHORIZED);
@@ -160,7 +161,7 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
if (currentRoute) {
const { isPrivate, key } = currentRoute;
if (isPrivate && key !== ROUTES.WORKSPACE_LOCKED) {
if (isPrivate && key !== String(ROUTES.WORKSPACE_LOCKED)) {
handlePrivateRoutes(key);
} else {
// no need to fetch the user and make user fetching false

View File

@@ -28,7 +28,11 @@ import AppReducer, { User } from 'types/reducer/app';
import { extractDomain, isCloudUser, isEECloudUser } from 'utils/app';
import PrivateRoute from './Private';
import defaultRoutes, { AppRoutes, SUPPORT_ROUTE } from './routes';
import defaultRoutes, {
AppRoutes,
LIST_LICENSES,
SUPPORT_ROUTE,
} from './routes';
function App(): JSX.Element {
const themeConfig = useThemeConfig();
@@ -150,6 +154,10 @@ function App(): JSX.Element {
if (isCloudUserVal || isEECloudUser()) {
const newRoutes = [...routes, SUPPORT_ROUTE];
setRoutes(newRoutes);
} else {
const newRoutes = [...routes, LIST_LICENSES];
setRoutes(newRoutes);
}

View File

@@ -15,9 +15,20 @@ export const ServiceMapPage = Loadable(
() => import(/* webpackChunkName: "ServiceMapPage" */ 'modules/Servicemap'),
);
export const LogsSaveViews = Loadable(
() => import(/* webpackChunkName: "LogsSaveViews" */ 'pages/LogsModulePage'), // TODO: Add a wrapper so that the same component can be used in traces
);
export const TracesExplorer = Loadable(
() =>
import(/* webpackChunkName: "Traces Explorer Page" */ 'pages/TracesExplorer'),
import(
/* webpackChunkName: "Traces Explorer Page" */ 'pages/TracesModulePage'
),
);
export const TracesSaveViews = Loadable(
() =>
import(/* webpackChunkName: "Traces Save Views" */ 'pages/TracesModulePage'),
);
export const TraceFilter = Loadable(
@@ -49,7 +60,8 @@ export const Onboarding = Loadable(
);
export const DashboardPage = Loadable(
() => import(/* webpackChunkName: "DashboardPage" */ 'pages/Dashboard'),
() =>
import(/* webpackChunkName: "DashboardPage" */ 'pages/DashboardsListPage'),
);
export const NewDashboardPage = Loadable(
@@ -106,22 +118,34 @@ export const IngestionSettings = Loadable(
() => import(/* webpackChunkName: "Ingestion Settings" */ 'pages/Settings'),
);
export const APIKeys = Loadable(
() => import(/* webpackChunkName: "All Settings" */ 'pages/Settings'),
);
export const MySettings = Loadable(
() => import(/* webpackChunkName: "All MySettings" */ 'pages/MySettings'),
);
export const Logs = Loadable(
() => import(/* webpackChunkName: "Logs" */ 'pages/Logs'),
() => import(/* webpackChunkName: "Logs" */ 'pages/LogsModulePage'),
);
export const LogsExplorer = Loadable(
() => import(/* webpackChunkName: "Logs Explorer" */ 'pages/LogsExplorer'),
() => import(/* webpackChunkName: "Logs Explorer" */ 'pages/LogsModulePage'),
);
export const OldLogsExplorer = Loadable(
() => import(/* webpackChunkName: "Logs Explorer" */ 'pages/Logs'),
);
export const LiveLogs = Loadable(
() => import(/* webpackChunkName: "Live Logs" */ 'pages/LiveLogs'),
);
export const PipelinePage = Loadable(
() => import(/* webpackChunkName: "Pipelines" */ 'pages/LogsModulePage'),
);
export const Login = Loadable(
() => import(/* webpackChunkName: "Login" */ 'pages/Login'),
);
@@ -150,10 +174,6 @@ export const LogsIndexToFields = Loadable(
import(/* webpackChunkName: "LogsIndexToFields Page" */ 'pages/LogsSettings'),
);
export const PipelinePage = Loadable(
() => import(/* webpackChunkName: "Pipelines" */ 'pages/Pipelines'),
);
export const BillingPage = Loadable(
() => import(/* webpackChunkName: "BillingPage" */ 'pages/Billing'),
);

View File

@@ -5,6 +5,7 @@ import { RouteProps } from 'react-router-dom';
import {
AllAlertChannels,
AllErrors,
APIKeys,
BillingPage,
CreateAlertChannelAlerts,
CreateNewAlerts,
@@ -21,8 +22,10 @@ import {
Logs,
LogsExplorer,
LogsIndexToFields,
LogsSaveViews,
MySettings,
NewDashboardPage,
OldLogsExplorer,
Onboarding,
OrganizationSettings,
PasswordReset,
@@ -38,6 +41,7 @@ import {
TraceDetail,
TraceFilter,
TracesExplorer,
TracesSaveViews,
UnAuthorized,
UsageExplorerPage,
} from './pageComponents';
@@ -85,6 +89,13 @@ const routes: AppRoutes[] = [
exact: true,
key: 'SERVICE_MAP',
},
{
path: ROUTES.LOGS_SAVE_VIEWS,
component: LogsSaveViews,
isPrivate: true,
exact: true,
key: 'LOGS_SAVE_VIEWS',
},
{
path: ROUTES.TRACE_DETAIL,
exact: true,
@@ -162,6 +173,13 @@ const routes: AppRoutes[] = [
isPrivate: true,
key: 'TRACES_EXPLORER',
},
{
path: ROUTES.TRACES_SAVE_VIEWS,
exact: true,
component: TracesSaveViews,
isPrivate: true,
key: 'TRACES_SAVE_VIEWS',
},
{
path: ROUTES.CHANNELS_NEW,
exact: true,
@@ -190,13 +208,6 @@ const routes: AppRoutes[] = [
component: AllErrors,
key: 'ALL_ERROR',
},
{
path: ROUTES.LIST_LICENSES,
exact: true,
component: LicensePage,
isPrivate: true,
key: 'LIST_LICENSES',
},
{
path: ROUTES.ERROR_DETAIL,
exact: true,
@@ -225,6 +236,13 @@ const routes: AppRoutes[] = [
isPrivate: true,
key: 'INGESTION_SETTINGS',
},
{
path: ROUTES.API_KEYS,
exact: true,
component: APIKeys,
isPrivate: true,
key: 'API_KEYS',
},
{
path: ROUTES.MY_SETTINGS,
exact: true,
@@ -246,6 +264,13 @@ const routes: AppRoutes[] = [
key: 'LOGS_EXPLORER',
isPrivate: true,
},
{
path: ROUTES.OLD_LOGS_EXPLORER,
exact: true,
component: OldLogsExplorer,
key: 'OLD_LOGS_EXPLORER',
isPrivate: true,
},
{
path: ROUTES.LIVE_LOGS,
exact: true,
@@ -312,6 +337,14 @@ export const SUPPORT_ROUTE: AppRoutes = {
isPrivate: true,
};
export const LIST_LICENSES: AppRoutes = {
path: ROUTES.LIST_LICENSES,
exact: true,
component: LicensePage,
isPrivate: true,
key: 'LIST_LICENSES',
};
export interface AppRoutes {
component: RouteProps['component'];
path: RouteProps['path'];

View File

@@ -1,4 +1,4 @@
import { AxiosError } from 'axios';
import { AxiosError, AxiosResponse } from 'axios';
import { ErrorResponse } from 'types/api';
import { ErrorStatusCode } from 'types/common';
@@ -10,7 +10,7 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse {
const statusCode = response.status as ErrorStatusCode;
if (statusCode >= 400 && statusCode < 500) {
const { data } = response;
const { data } = response as AxiosResponse;
if (statusCode === 404) {
return {

View File

@@ -3,9 +3,9 @@ import { ApiResponse } from 'types/api';
import { Props } from 'types/api/dashboard/get';
import { Dashboard } from 'types/api/dashboard/getAll';
const get = (props: Props): Promise<Dashboard> =>
const getDashboard = (props: Props): Promise<Dashboard> =>
axios
.get<ApiResponse<Dashboard>>(`/dashboards/${props.uuid}`)
.then((res) => res.data.data);
export default get;
export default getDashboard;

View File

@@ -0,0 +1,15 @@
import { ApiV3Instance as axios } from 'api';
import { ApiResponse } from 'types/api';
import { ICompositeMetricQuery } from 'types/api/alerts/compositeQuery';
import { QueryRangePayload } from 'types/api/metrics/getQueryRange';
interface IQueryRangeFormat {
compositeQuery: ICompositeMetricQuery;
}
export const getQueryRangeFormat = (
props?: Partial<QueryRangePayload>,
): Promise<IQueryRangeFormat> =>
axios
.post<ApiResponse<IQueryRangeFormat>>('/query_range/format', props)
.then((res) => res.data.data);

View File

@@ -4,7 +4,7 @@ import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import { PayloadProps, Props } from 'types/api/dashboard/update';
const update = async (
const updateDashboard = async (
props: Props,
): Promise<SuccessResponse<PayloadProps> | ErrorResponse> => {
try {
@@ -23,4 +23,4 @@ const update = async (
}
};
export default update;
export default updateDashboard;

View File

@@ -0,0 +1,30 @@
import { ApiV2Instance as axios } from 'api';
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError } from 'axios';
import { ErrorResponse, SuccessResponse } from 'types/api';
import {
Props,
VariableResponseProps,
} from 'types/api/dashboard/variables/query';
const dashboardVariablesQuery = async (
props: Props,
): Promise<SuccessResponse<VariableResponseProps> | ErrorResponse> => {
try {
const response = await axios.post(`/variables/query`, props);
return {
statusCode: 200,
error: null,
message: response.data.status,
payload: response.data.data,
};
} catch (error) {
const formattedError = ErrorResponseHandler(error as AxiosError);
// eslint-disable-next-line @typescript-eslint/no-throw-literal
throw { message: 'Error fetching data', details: formattedError };
}
};
export default dashboardVariablesQuery;

View File

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

View File

@@ -4,7 +4,7 @@
import getLocalStorageApi from 'api/browser/localstorage/get';
import loginApi from 'api/user/login';
import afterLogin from 'AppRoutes/utils';
import axios, { AxiosRequestConfig, AxiosResponse } from 'axios';
import axios, { AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import { ENVIRONMENT } from 'constants/env';
import { LOCALSTORAGE } from 'constants/localStorage';
import store from 'store';
@@ -17,14 +17,16 @@ const interceptorsResponse = (
): Promise<AxiosResponse<any>> => Promise.resolve(value);
const interceptorsRequestResponse = (
value: AxiosRequestConfig,
): AxiosRequestConfig => {
value: InternalAxiosRequestConfig,
): InternalAxiosRequestConfig => {
const token =
store.getState().app.user?.accessJwt ||
getLocalStorageApi(LOCALSTORAGE.AUTH_TOKEN) ||
'';
value.headers.Authorization = token ? `Bearer ${token}` : '';
if (value && value.headers) {
value.headers.Authorization = token ? `Bearer ${token}` : '';
}
return value;
};
@@ -92,8 +94,8 @@ const instance = axios.create({
baseURL: `${ENVIRONMENT.baseURL}${apiV1}`,
});
instance.interceptors.response.use(interceptorsResponse, interceptorRejected);
instance.interceptors.request.use(interceptorsRequestResponse);
instance.interceptors.response.use(interceptorsResponse, interceptorRejected);
export const AxiosAlertManagerInstance = axios.create({
baseURL: `${ENVIRONMENT.baseURL}${apiAlertManager}`,

View File

@@ -4,5 +4,6 @@ import { MetricMetaProps } from 'types/api/metrics/getApDex';
export const getMetricMeta = (
metricName: string,
servicename: string,
): Promise<AxiosResponse<MetricMetaProps>> =>
axios.get(`/metric_meta?metricName=${metricName}`);
axios.get(`/metric_meta?metricName=${metricName}&serviceName=${servicename}`);

View File

@@ -9,9 +9,10 @@ import {
export const getMetricsQueryRange = async (
props: QueryRangePayload,
signal: AbortSignal,
): Promise<SuccessResponse<MetricRangePayloadV3> | ErrorResponse> => {
try {
const response = await axios.post('/query_range', props);
const response = await axios.post('/query_range', props, { signal });
return {
statusCode: 200,

View File

@@ -66,7 +66,11 @@ export const Logout = (): void => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.Intercom('shutdown');
if (window && window.Intercom) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
window.Intercom('shutdown');
}
history.push(ROUTES.LOGIN);
};

View File

@@ -0,0 +1,121 @@
.custom-time-picker {
display: flex;
flex-direction: column;
}
.time-options-container {
.time-options-item {
margin: 2px 0;
padding: 8px;
border-radius: 2px;
&.active {
background-color: rgba($color: #000000, $alpha: 0.2);
&:hover {
cursor: pointer;
background-color: rgba($color: #000000, $alpha: 0.3);
}
}
&:hover {
cursor: pointer;
background-color: rgba($color: #000000, $alpha: 0.3);
}
}
}
.time-selection-dropdown-content {
min-width: 172px;
width: 100%;
}
.timeSelection-input {
display: flex;
gap: 8px;
height: 33px;
align-items: center;
padding: 4px 8px;
padding-left: 0px !important;
&.custom-time {
input:not(:focus) {
min-width: 240px;
}
}
input::placeholder {
color: white;
}
input:focus::placeholder {
color: rgba($color: #ffffff, $alpha: 0.4);
}
}
.valid-format-error {
margin-top: 4px;
color: var(--bg-cherry-400) !important;
font-size: 13px !important;
font-weight: 400 !important;
}
.info-text {
display: flex;
align-items: center;
justify-content: center;
padding: 4px;
cursor: default;
color: var(--bg-vanilla-400, #c0c1c3) !important;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.14px;
}
.info-text:hover {
&.ant-btn-text {
background-color: unset !important;
}
}
.lightMode {
.time-options-container {
.time-options-item {
&.active {
background-color: rgba($color: #ffffff, $alpha: 0.2);
&:hover {
cursor: pointer;
background-color: rgba($color: #ffffff, $alpha: 0.3);
}
}
&:hover {
cursor: pointer;
background-color: rgba($color: #ffffff, $alpha: 0.3);
}
}
}
.timeSelection-input {
display: flex;
gap: 8px;
align-items: center;
padding: 4px 8px;
padding-left: 0px !important;
input::placeholder {
color: var(---bg-ink-300);
}
input:focus::placeholder {
color: rgba($color: #000000, $alpha: 0.4);
}
}
.info-text {
color: var(--bg-slate-400) !important;
}
}

View File

@@ -0,0 +1,309 @@
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/no-static-element-interactions */
import './CustomTimePicker.styles.scss';
import { Input, Popover, Tooltip, Typography } from 'antd';
import cx from 'classnames';
import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal';
import { Options } from 'container/TopNav/DateTimeSelection/config';
import {
FixedDurationSuggestionOptions,
RelativeDurationSuggestionOptions,
} from 'container/TopNav/DateTimeSelectionV2/config';
import dayjs from 'dayjs';
import { defaultTo, noop } from 'lodash-es';
import debounce from 'lodash-es/debounce';
import { CheckCircle, ChevronDown, Clock } from 'lucide-react';
import {
ChangeEvent,
Dispatch,
SetStateAction,
useEffect,
useState,
} from 'react';
import { popupContainer } from 'utils/selectPopupContainer';
import CustomTimePickerPopoverContent from './CustomTimePickerPopoverContent';
const maxAllowedMinTimeInMonths = 6;
interface CustomTimePickerProps {
onSelect: (value: string) => void;
onError: (value: boolean) => void;
selectedValue: string;
selectedTime: string;
onValidCustomDateChange: ([t1, t2]: any[]) => void;
open: boolean;
setOpen: Dispatch<SetStateAction<boolean>>;
items: any[];
newPopover?: boolean;
customDateTimeVisible?: boolean;
setCustomDTPickerVisible?: Dispatch<SetStateAction<boolean>>;
onCustomDateHandler?: (dateTimeRange: DateTimeRangeType) => void;
handleGoLive?: () => void;
}
function CustomTimePicker({
onSelect,
onError,
items,
selectedValue,
selectedTime,
open,
setOpen,
onValidCustomDateChange,
newPopover,
customDateTimeVisible,
setCustomDTPickerVisible,
onCustomDateHandler,
handleGoLive,
}: CustomTimePickerProps): JSX.Element {
const [
selectedTimePlaceholderValue,
setSelectedTimePlaceholderValue,
] = useState('Select / Enter Time Range');
const [inputValue, setInputValue] = useState('');
const [inputStatus, setInputStatus] = useState<'' | 'error' | 'success'>('');
const [inputErrorMessage, setInputErrorMessage] = useState<string | null>(
null,
);
const [isInputFocused, setIsInputFocused] = useState(false);
const getSelectedTimeRangeLabel = (
selectedTime: string,
selectedTimeValue: string,
): string => {
if (selectedTime === 'custom') {
return selectedTimeValue;
}
for (let index = 0; index < Options.length; index++) {
if (Options[index].value === selectedTime) {
return Options[index].label;
}
}
for (
let index = 0;
index < RelativeDurationSuggestionOptions.length;
index++
) {
if (RelativeDurationSuggestionOptions[index].value === selectedTime) {
return RelativeDurationSuggestionOptions[index].label;
}
}
for (let index = 0; index < FixedDurationSuggestionOptions.length; index++) {
if (FixedDurationSuggestionOptions[index].value === selectedTime) {
return FixedDurationSuggestionOptions[index].label;
}
}
return '';
};
useEffect(() => {
const value = getSelectedTimeRangeLabel(selectedTime, selectedValue);
setSelectedTimePlaceholderValue(value);
}, [selectedTime, selectedValue]);
const hide = (): void => {
setOpen(false);
};
const handleOpenChange = (newOpen: boolean): void => {
setOpen(newOpen);
};
const debouncedHandleInputChange = debounce((inputValue): void => {
const isValidFormat = /^(\d+)([mhdw])$/.test(inputValue);
if (isValidFormat) {
setInputStatus('success');
onError(false);
setInputErrorMessage(null);
const match = inputValue.match(/^(\d+)([mhdw])$/);
const value = parseInt(match[1], 10);
const unit = match[2];
const currentTime = dayjs();
const maxAllowedMinTime = currentTime.subtract(
maxAllowedMinTimeInMonths,
'month',
);
let minTime = null;
switch (unit) {
case 'm':
minTime = currentTime.subtract(value, 'minute');
break;
case 'h':
minTime = currentTime.subtract(value, 'hour');
break;
case 'd':
minTime = currentTime.subtract(value, 'day');
break;
case 'w':
minTime = currentTime.subtract(value, 'week');
break;
default:
break;
}
if (minTime && minTime < maxAllowedMinTime) {
setInputStatus('error');
onError(true);
setInputErrorMessage('Please enter time less than 6 months');
} else {
onValidCustomDateChange([minTime, currentTime]);
}
} else {
setInputStatus('error');
onError(true);
setInputErrorMessage(null);
}
}, 300);
const handleInputChange = (event: ChangeEvent<HTMLInputElement>): void => {
const inputValue = event.target.value;
if (inputValue.length > 0) {
setOpen(false);
} else {
setOpen(true);
}
setInputValue(inputValue);
// Call the debounced function with the input value
debouncedHandleInputChange(inputValue);
};
const handleSelect = (label: string, value: string): void => {
onSelect(value);
setSelectedTimePlaceholderValue(label);
setInputStatus('');
onError(false);
setInputErrorMessage(null);
setInputValue('');
if (value !== 'custom') {
hide();
}
};
const content = (
<div className="time-selection-dropdown-content">
<div className="time-options-container">
{items?.map(({ value, label }) => (
<div
onClick={(): void => {
handleSelect(label, value);
}}
key={value}
className={cx(
'time-options-item',
selectedValue === value ? 'active' : '',
)}
>
{label}
</div>
))}
</div>
</div>
);
const handleFocus = (): void => {
setIsInputFocused(true);
};
const handleBlur = (): void => {
setIsInputFocused(false);
};
return (
<div className="custom-time-picker">
<Popover
className={cx(
'timeSelection-input-container',
selectedTime === 'custom' && inputValue === '' ? 'custom-time' : '',
)}
placement="bottomRight"
getPopupContainer={popupContainer}
rootClassName="date-time-root"
content={
newPopover ? (
<CustomTimePickerPopoverContent
setIsOpen={setOpen}
customDateTimeVisible={defaultTo(customDateTimeVisible, false)}
setCustomDTPickerVisible={defaultTo(setCustomDTPickerVisible, noop)}
onCustomDateHandler={defaultTo(onCustomDateHandler, noop)}
onSelectHandler={handleSelect}
handleGoLive={defaultTo(handleGoLive, noop)}
options={items}
selectedTime={selectedTime}
/>
) : (
content
)
}
arrow={false}
trigger="hover"
open={open}
onOpenChange={handleOpenChange}
style={{
padding: 0,
}}
>
<Input
className="timeSelection-input"
type="text"
status={inputValue && inputStatus === 'error' ? 'error' : ''}
placeholder={
isInputFocused
? 'Time Format (1m or 2h or 3d or 4w)'
: selectedTimePlaceholderValue
}
value={inputValue}
onFocus={handleFocus}
onBlur={handleBlur}
onChange={handleInputChange}
prefix={
inputValue && inputStatus === 'success' ? (
<CheckCircle size={14} color="#51E7A8" />
) : (
<Tooltip title="Enter time in format (e.g., 1m, 2h, 3d, 4w)">
<Clock size={14} />
</Tooltip>
)
}
suffix={
<ChevronDown
size={14}
onClick={(): void => {
setOpen(!open);
}}
/>
}
/>
</Popover>
{inputStatus === 'error' && inputErrorMessage && (
<Typography.Title level={5} className="valid-format-error">
{inputErrorMessage}
</Typography.Title>
)}
</div>
);
}
export default CustomTimePicker;
CustomTimePicker.defaultProps = {
newPopover: false,
customDateTimeVisible: false,
setCustomDTPickerVisible: noop,
onCustomDateHandler: noop,
handleGoLive: noop,
};

View File

@@ -0,0 +1,133 @@
import './CustomTimePicker.styles.scss';
import { Button, DatePicker } from 'antd';
import cx from 'classnames';
import ROUTES from 'constants/routes';
import { DateTimeRangeType } from 'container/TopNav/CustomDateTimeModal';
import {
Option,
RelativeDurationSuggestionOptions,
} from 'container/TopNav/DateTimeSelectionV2/config';
import dayjs, { Dayjs } from 'dayjs';
import { Dispatch, SetStateAction, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';
interface CustomTimePickerPopoverContentProps {
options: any[];
setIsOpen: Dispatch<SetStateAction<boolean>>;
customDateTimeVisible: boolean;
setCustomDTPickerVisible: Dispatch<SetStateAction<boolean>>;
onCustomDateHandler: (dateTimeRange: DateTimeRangeType) => void;
onSelectHandler: (label: string, value: string) => void;
handleGoLive: () => void;
selectedTime: string;
}
function CustomTimePickerPopoverContent({
options,
setIsOpen,
customDateTimeVisible,
setCustomDTPickerVisible,
onCustomDateHandler,
onSelectHandler,
handleGoLive,
selectedTime,
}: CustomTimePickerPopoverContentProps): JSX.Element {
const { RangePicker } = DatePicker;
const { pathname } = useLocation();
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
(state) => state.globalTime,
);
const isLogsExplorerPage = useMemo(() => pathname === ROUTES.LOGS_EXPLORER, [
pathname,
]);
const disabledDate = (current: Dayjs): boolean => {
const currentDay = dayjs(current);
return currentDay.isAfter(dayjs());
};
const onPopoverClose = (visible: boolean): void => {
if (!visible) {
setCustomDTPickerVisible(false);
}
setIsOpen(visible);
};
const onModalOkHandler = (date_time: any): void => {
if (date_time?.[1]) {
onPopoverClose(false);
}
onCustomDateHandler(date_time);
};
function getTimeChips(options: Option[]): JSX.Element {
return (
<div className="relative-date-time-section">
{options.map((option) => (
<Button
type="text"
className="time-btns"
key={option.label + option.value}
onClick={(): void => {
onSelectHandler(option.label, option.value);
}}
>
{option.label}
</Button>
))}
</div>
);
}
return (
<div className="date-time-popover">
<div className="date-time-options">
{isLogsExplorerPage && (
<Button className="data-time-live" type="text" onClick={handleGoLive}>
Live
</Button>
)}
{options.map((option) => (
<Button
type="text"
key={option.label + option.value}
onClick={(): void => {
onSelectHandler(option.label, option.value);
}}
className={cx(
'date-time-options-btn',
selectedTime === option.value && 'active',
)}
>
{option.label}
</Button>
))}
</div>
<div className="relative-date-time">
{selectedTime === 'custom' || customDateTimeVisible ? (
<RangePicker
disabledDate={disabledDate}
allowClear
onCalendarChange={onModalOkHandler}
// eslint-disable-next-line react/jsx-props-no-spreading
{...(selectedTime === 'custom' && {
defaultValue: [dayjs(minTime / 1000000), dayjs(maxTime / 1000000)],
})}
/>
) : (
<div>
<div className="time-heading">RELATIVE TIMES</div>
<div>{getTimeChips(RelativeDurationSuggestionOptions)}</div>
</div>
)}
</div>
</div>
);
}
export default CustomTimePickerPopoverContent;

View File

@@ -6,7 +6,6 @@ import {
} from '@ant-design/icons';
import {
Button,
Card,
Col,
Dropdown,
MenuProps,
@@ -152,95 +151,100 @@ function ExplorerCard({
const saveButtonType = isQueryUpdated ? 'default' : 'primary';
const saveButtonIcon = isQueryUpdated ? null : <SaveOutlined />;
const showSaveView = false;
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}
{showSaveView && (
<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}
>
{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}
>
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}
data-testid="traces-save-view-action"
>
{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>
<Button
type={saveButtonType}
icon={saveButtonIcon}
data-testid="traces-save-view-action"
>
{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>
)}
<div>{children}</div>
</>
);
}

View File

@@ -3,6 +3,7 @@ import styled, { CSSProperties } from 'styled-components';
export const ExplorerCardHeadContainer = styled(Card)`
margin: 1rem 0;
padding: 0;
`;
export const OffSetCol = styled(Col)`

View File

@@ -1,4 +1,4 @@
import { fireEvent, render, screen } from '@testing-library/react';
import { render, screen } from '@testing-library/react';
import ROUTES from 'constants/routes';
import MockQueryClientProvider from 'providers/test/MockQueryClientProvider';
import { DataSource } from 'types/common/queryBuilder';
@@ -46,7 +46,7 @@ describe('ExplorerCard', () => {
<ExplorerCard sourcepage={DataSource.TRACES}>child</ExplorerCard>
</MockQueryClientProvider>,
);
expect(screen.getByText('Query Builder')).toBeInTheDocument();
expect(screen.queryByText('Query Builder')).not.toBeInTheDocument();
});
it('renders a save view button', () => {
@@ -55,19 +55,6 @@ describe('ExplorerCard', () => {
<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();
});
expect(screen.queryByText('Save view')).not.toBeInTheDocument();
});
});

View File

@@ -5,6 +5,7 @@ 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 { Query } from 'types/api/queryBuilder/queryBuilderData';
import {
DeleteViewHandlerProps,
@@ -13,7 +14,7 @@ import {
SaveViewHandlerProps,
} from './types';
const showErrorNotification = (
export const showErrorNotification = (
notifications: NotificationInstance,
err: Error,
): void => {
@@ -35,6 +36,45 @@ export const getViewDetailsUsingViewKey: GetViewDetailsUsingViewKey = (
return undefined;
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const omitIdFromQuery = (query: Query | null): any => ({
...query,
builder: {
...query?.builder,
queryData: query?.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,
};
}),
},
});
export const isQueryUpdatedInView = ({
viewKey,
data,
@@ -48,43 +88,15 @@ export const isQueryUpdatedInView = ({
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,
};
}),
},
};
const updatedCurrentQuery = omitIdFromQuery(stagedQuery);
if (
updatedCurrentQuery?.builder === undefined ||
updatedCurrentQuery.clickhouse_sql === undefined ||
updatedCurrentQuery.promql === undefined
) {
return false;
}
return (
panelType !== currentPanelType ||
@@ -153,7 +165,7 @@ export const deleteViewHandler = ({
if (viewId === viewKey) {
redirectWithQueryBuilderData(
updateAllQueriesOperators(
initialQueriesMap.traces,
initialQueriesMap[sourcePage],
panelType || PANEL_TYPES.LIST,
sourcePage,
),

View File

@@ -3,8 +3,11 @@ import { AddToQueryHOCProps } from 'components/Logs/AddToQueryHOC';
import { ActionItemProps } from 'container/LogDetailedView/ActionItem';
import { ILog } from 'types/api/logs/log';
import { VIEWS } from './constants';
export type LogDetailProps = {
log: ILog | null;
selectedTab: VIEWS;
} & Pick<AddToQueryHOCProps, 'onAddToQuery'> &
Pick<ActionItemProps, 'onClickActionItem'> &
Partial<Pick<ActionItemProps, 'onClickActionItem'>> &
Pick<DrawerProps, 'onClose'>;

View File

@@ -0,0 +1,224 @@
.log-detail-drawer {
border-left: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
box-shadow: -4px 10px 16px 2px rgba(0, 0, 0, 0.2);
.ant-drawer-header {
padding: 8px 16px;
border-bottom: none;
align-items: stretch;
border-bottom: 1px solid var(--bg-slate-500);
background: var(--bg-ink-400);
}
.ant-drawer-close {
margin-inline-end: 0px;
}
.ant-drawer-body {
padding: 16px;
}
.title {
color: var(--text-vanilla-400);
font-family: Inter;
font-size: var(--font-size-sm);
font-style: normal;
font-weight: var(--font-weight-normal);
line-height: 20px; /* 142.857% */
letter-spacing: -0.07px;
}
.radio-button {
display: flex;
align-items: center;
justify-content: center;
padding-top: var(--padding-1);
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
}
.log-detail-drawer__log {
width: 100%;
display: flex;
align-items: center;
gap: 4px;
position: relative;
.log-body {
font-family: 'SF Mono';
font-family: 'Space Mono', monospace;
font-size: var(--font-size-sm);
font-weight: var(--font-weight-normal);
line-height: 18px;
letter-spacing: -0.07px;
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
color: var(--text-vanilla-400);
opacity: 0.6;
}
.log-type-indicator {
height: 24px;
border: 2px solid var(--bg-slate-400);
border-radius: 5px;
margin-left: 0;
&.INFO {
border-color: #1d212d;
}
&.WARNING {
border-color: #ffcd56;
}
&.ERROR {
border-color: #e5484d;
}
}
.log-overflow-shadow {
background: linear-gradient(270deg, #121317 10.4%, rgba(18, 19, 23, 0) 100%);
width: 196px;
position: absolute;
right: 0;
}
}
.tabs-and-search {
display: flex;
justify-content: space-between;
align-items: center;
margin: 16px 0;
.action-btn {
border-radius: 2px;
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-300);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
display: flex;
align-items: center;
justify-content: center;
}
.json-action-btn {
display: flex;
gap: 8px;
}
}
.views-tabs {
color: var(--text-vanilla-400);
.view-title {
display: flex;
gap: var(--margin-2);
align-items: center;
justify-content: center;
font-size: var(--font-size-xs);
font-style: normal;
font-weight: var(--font-weight-normal);
}
.tab {
border: 1px solid var(--bg-slate-400);
width: 114px;
}
.tab::before {
background: var(--bg-slate-400);
}
.selected_view {
background: var(--bg-slate-300);
color: var(--text-vanilla-100);
border: 1px solid var(--bg-slate-400);
}
.selected_view::before {
background: var(--bg-slate-400);
}
}
.search-input {
margin-top: var(--margin-2);
border: 1px solid var(--bg-slate-400);
height: 46px;
padding: var(--padding-1) var(--padding-2);
}
}
.lightMode {
.ant-drawer-header {
border-bottom: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
}
.log-detail-drawer {
.title {
color: var(--text-ink-300);
}
.log-detail-drawer__log {
.log-overflow-shadow {
background: linear-gradient(
270deg,
var(--bg-vanilla-100) 10.4%,
rgba(255, 255, 255, 0) 100%
);
}
.log-type-indicator {
border: 2px solid var(--bg-vanilla-400);
}
.ant-typography {
color: var(--text-ink-300);
background: transparent;
}
}
.radio-button {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
.views-tabs {
.tab {
background: var(--bg-vanilla-100);
}
.selected_view {
background: var(--bg-vanilla-300);
border: 1px solid var(--bg-slate-300);
color: var(--text-ink-400);
}
.selected_view::before {
background: var(--bg-vanilla-300);
border-left: 1px solid var(--bg-slate-300);
}
}
.tabs-and-search {
.action-btn {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
}
.search-input {
border: 1px solid var(--bg-vanilla-200);
background: var(--bg-vanilla-100);
color: var(--text-ink-300);
}
}
}

View File

@@ -0,0 +1,10 @@
.query-builder-search-wrapper {
margin-top: 10px;
height: 46px;
border: 1px solid var(--bg-slate-400);
border-bottom: none;
.ant-select-selector {
border: none !important;
}
}

View File

@@ -0,0 +1,77 @@
import './QueryBuilderSearchWrapper.styles.scss';
import useInitialQuery from 'container/LogsExplorerContext/useInitialQuery';
import QueryBuilderSearch from 'container/QueryBuilder/filters/QueryBuilderSearch';
import { Dispatch, SetStateAction, useEffect } from 'react';
import { ILog } from 'types/api/logs/log';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
function QueryBuilderSearchWrapper({
log,
filters,
contextQuery,
isEdit,
suffixIcon,
setFilters,
setContextQuery,
}: QueryBuilderSearchWraperProps): JSX.Element {
const initialContextQuery = useInitialQuery(log);
useEffect(() => {
setContextQuery(initialContextQuery);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const handleSearch = (tagFilters: TagFilter): void => {
const tagFiltersLength = tagFilters.items.length;
if (
(!tagFiltersLength && (!filters || !filters.items.length)) ||
tagFiltersLength === filters?.items.length ||
!contextQuery
)
return;
const nextQuery: Query = {
...contextQuery,
builder: {
...contextQuery.builder,
queryData: contextQuery.builder.queryData.map((item) => ({
...item,
filters: tagFilters,
})),
},
};
setFilters({ ...tagFilters });
setContextQuery({ ...nextQuery });
};
// eslint-disable-next-line react/jsx-no-useless-fragment
if (!contextQuery || !isEdit) return <></>;
return (
<QueryBuilderSearch
query={contextQuery?.builder.queryData[0]}
onChange={handleSearch}
className="query-builder-search-wrapper"
suffixIcon={suffixIcon}
/>
);
}
interface QueryBuilderSearchWraperProps {
log: ILog;
isEdit: boolean;
contextQuery: Query | undefined;
setContextQuery: Dispatch<SetStateAction<Query | undefined>>;
filters: TagFilter | null;
setFilters: Dispatch<SetStateAction<TagFilter | null>>;
suffixIcon?: React.ReactNode;
}
QueryBuilderSearchWrapper.defaultProps = {
suffixIcon: undefined,
};
export default QueryBuilderSearchWrapper;

View File

@@ -0,0 +1,7 @@
export const VIEW_TYPES = {
OVERVIEW: 'OVERVIEW',
JSON: 'JSON',
CONTEXT: 'CONTEXT',
} as const;
export type VIEWS = typeof VIEW_TYPES[keyof typeof VIEW_TYPES];

View File

@@ -1,50 +1,207 @@
import { Drawer, Tabs } from 'antd';
import JSONView from 'container/LogDetailedView/JsonView';
import TableView from 'container/LogDetailedView/TableView';
import { useMemo } from 'react';
/* eslint-disable sonarjs/cognitive-complexity */
import './LogDetails.styles.scss';
import { Color, Spacing } from '@signozhq/design-tokens';
import { Button, Divider, Drawer, Radio, Tooltip, Typography } from 'antd';
import { RadioChangeEvent } from 'antd/lib';
import cx from 'classnames';
import { LogType } from 'components/Logs/LogStateIndicator/LogStateIndicator';
import ContextView from 'container/LogDetailedView/ContextView/ContextView';
import JSONView from 'container/LogDetailedView/JsonView';
import Overview from 'container/LogDetailedView/Overview';
import { aggregateAttributesResourcesToString } from 'container/LogDetailedView/utils';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useNotifications } from 'hooks/useNotifications';
import {
Braces,
Copy,
Filter,
HardHat,
Table,
TextSelect,
X,
} from 'lucide-react';
import { useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import { Query, TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { VIEW_TYPES, VIEWS } from './constants';
import { LogDetailProps } from './LogDetail.interfaces';
import QueryBuilderSearchWrapper from './QueryBuilderSearchWrapper';
function LogDetail({
log,
onClose,
onAddToQuery,
onClickActionItem,
selectedTab,
}: LogDetailProps): JSX.Element {
const items = useMemo(
() => [
{
label: 'Table',
key: '1',
children: log && (
<TableView
logData={log}
onAddToQuery={onAddToQuery}
onClickActionItem={onClickActionItem}
/>
),
},
{
label: 'JSON',
key: '2',
children: log && <JSONView logData={log} />,
},
],
[log, onAddToQuery, onClickActionItem],
);
const [, copyToClipboard] = useCopyToClipboard();
const [selectedView, setSelectedView] = useState<VIEWS>(selectedTab);
const [isFilterVisibile, setIsFilterVisible] = useState<boolean>(false);
const [contextQuery, setContextQuery] = useState<Query | undefined>();
const [filters, setFilters] = useState<TagFilter | null>(null);
const [isEdit, setIsEdit] = useState<boolean>(false);
const isDarkMode = useIsDarkMode();
const { notifications } = useNotifications();
const LogJsonData = log ? aggregateAttributesResourcesToString(log) : '';
const handleModeChange = (e: RadioChangeEvent): void => {
setSelectedView(e.target.value);
setIsEdit(false);
setIsFilterVisible(false);
};
const handleFilterVisible = (): void => {
setIsFilterVisible(!isFilterVisibile);
setIsEdit(!isEdit);
};
const drawerCloseHandler = (
e: React.MouseEvent | React.KeyboardEvent,
): void => {
if (onClose) {
onClose(e);
}
};
const handleJSONCopy = (): void => {
copyToClipboard(LogJsonData);
notifications.success({
message: 'Copied to clipboard',
});
};
if (!log) {
// eslint-disable-next-line react/jsx-no-useless-fragment
return <></>;
}
const logType = log?.attributes_string?.log_level || LogType.INFO;
return (
<Drawer
width="60%"
title="Log Details"
title={
<>
<Divider type="vertical" className={cx('log-type-indicator', LogType)} />
<Typography.Text className="title">Log details</Typography.Text>
</>
}
placement="right"
closable
onClose={onClose}
// closable
onClose={drawerCloseHandler}
open={log !== null}
style={{ overscrollBehavior: 'contain' }}
style={{
overscrollBehavior: 'contain',
background: isDarkMode ? Color.BG_INK_400 : Color.BG_VANILLA_100,
}}
className="log-detail-drawer"
destroyOnClose
closeIcon={<X size={16} style={{ marginTop: Spacing.MARGIN_1 }} />}
>
<Tabs defaultActiveKey="1" items={items} />
<div className="log-detail-drawer__log">
<Divider type="vertical" className={cx('log-type-indicator', logType)} />
<Tooltip title={log?.body} placement="left">
<Typography.Text className="log-body">{log?.body}</Typography.Text>
</Tooltip>
<div className="log-overflow-shadow">&nbsp;</div>
</div>
<div className="tabs-and-search">
<Radio.Group
className="views-tabs"
onChange={handleModeChange}
value={selectedView}
>
<Radio.Button
className={
// eslint-disable-next-line sonarjs/no-duplicate-string
selectedView === VIEW_TYPES.OVERVIEW ? 'selected_view tab' : 'tab'
}
value={VIEW_TYPES.OVERVIEW}
>
<div className="view-title">
<Table size={14} />
Overview
</div>
</Radio.Button>
<Radio.Button
className={selectedView === VIEW_TYPES.JSON ? 'selected_view tab' : 'tab'}
value={VIEW_TYPES.JSON}
>
<div className="view-title">
<Braces size={14} />
JSON
</div>
</Radio.Button>
<Radio.Button
className={
selectedView === VIEW_TYPES.CONTEXT ? 'selected_view tab' : 'tab'
}
value={VIEW_TYPES.CONTEXT}
>
<div className="view-title">
<TextSelect size={14} />
Context
</div>
</Radio.Button>
</Radio.Group>
{selectedView === VIEW_TYPES.JSON && (
<div className="json-action-btn">
<Button
className="action-btn"
icon={<Copy size={16} />}
onClick={handleJSONCopy}
/>
</div>
)}
{selectedView === VIEW_TYPES.CONTEXT && (
<Button
className="action-btn"
icon={<Filter size={16} />}
onClick={handleFilterVisible}
/>
)}
</div>
<QueryBuilderSearchWrapper
isEdit={isEdit}
log={log}
filters={filters}
setContextQuery={setContextQuery}
setFilters={setFilters}
contextQuery={contextQuery}
suffixIcon={
<HardHat size={12} style={{ paddingRight: Spacing.PADDING_2 }} />
}
/>
{selectedView === VIEW_TYPES.OVERVIEW && (
<Overview
logData={log}
onAddToQuery={onAddToQuery}
onClickActionItem={onClickActionItem}
/>
)}
{selectedView === VIEW_TYPES.JSON && <JSONView logData={log} />}
{selectedView === VIEW_TYPES.CONTEXT && (
<ContextView
log={log}
filters={filters}
contextQuery={contextQuery}
isEdit={isEdit}
/>
)}
</Drawer>
);
}

View File

@@ -0,0 +1,103 @@
.log-field-key {
padding-right: 5px;
color: var(--text-vanilla-400, #c0c1c3);
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px; /* 128.571% */
letter-spacing: -0.07px;
}
.log-value {
color: var(--text-vanilla-400, #c0c1c3);
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px; /* 128.571% */
letter-spacing: -0.07px;
}
.log-line {
display: flex;
overflow: hidden;
.log-state-indicator {
padding-left: 0;
}
transition: background-color 0.2s ease-in;
&:hover {
background-color: rgba(171, 189, 255, 0.04) !important;
}
}
.log-selected-fields {
display: flex;
width: 100%;
overflow: hidden;
align-items: center;
.selected-log-field-key {
color: var(--bg-robin-400) !important;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px; /* 128.571% */
letter-spacing: -0.07px;
}
.selected-log-value {
color: var(--bg-sienna-500);
border-radius: 2px;
background: rgba(173, 127, 88, 0.08);
padding: 0px 2px;
margin-left: 7px;
font-weight: 400;
line-height: 18px;
letter-spacing: -0.07px;
font-size: 14px;
}
.selected-log-kv {
min-height: 24px;
display: flex;
align-items: center;
}
}
.log-action-buttons {
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
right: 0;
cursor: pointer;
height: 32px;
width: 68px;
border-radius: 2px;
border: 1px solid var(--bg-slate-400, #1d212d);
background: var(--bg-ink-400, #121317);
box-shadow: 0px 0px 8px 0px rgba(0, 0, 0, 0.1);
.context-btn {
width: 50% !important;
}
.copy-link-btn {
width: 50% !important;
border-left: 1px solid var(--bg-slate-400, #1d212d) !important;
}
.ant-btn-default {
border: none;
box-shadow: none;
}
}
.lightMode {
.log-field-key {
color: var(--text-slate-400);
}
.log-value {
color: var(--text-slate-400);
}
.log-line {
&:hover {
background-color: var(--text-vanilla-200) !important;
}
}
}

View File

@@ -1,36 +1,32 @@
import { blue, grey, orange } from '@ant-design/colors';
import {
CopyFilled,
ExpandAltOutlined,
LinkOutlined,
MonitorOutlined,
} from '@ant-design/icons';
import './ListLogView.styles.scss';
import { blue } from '@ant-design/colors';
import Convert from 'ansi-to-html';
import { Button, Divider, Row, Typography } from 'antd';
import { Typography } from 'antd';
import LogDetail from 'components/LogDetail';
import LogsExplorerContext from 'container/LogsExplorerContext';
import { VIEW_TYPES } from 'components/LogDetail/constants';
import dayjs from 'dayjs';
import dompurify from 'dompurify';
import { useActiveLog } from 'hooks/logs/useActiveLog';
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
import { useNotifications } from 'hooks/useNotifications';
// utils
import { FlatLogData } from 'lib/logs/flatLogData';
import { useCallback, useMemo } from 'react';
import { useCopyToClipboard } from 'react-use';
import { useCallback, useMemo, useState } from 'react';
// interfaces
import { IField } from 'types/api/logs/fields';
import { ILog } from 'types/api/logs/log';
// components
import AddToQueryHOC, { AddToQueryHOCProps } from '../AddToQueryHOC';
import CopyClipboardHOC from '../CopyClipboardHOC';
import LogLinesActionButtons from '../LogLinesActionButtons/LogLinesActionButtons';
import LogStateIndicator, {
LogType,
} from '../LogStateIndicator/LogStateIndicator';
// styles
import {
Container,
LogContainer,
LogText,
SelectedLog,
Text,
TextContainer,
} from './styles';
@@ -56,12 +52,10 @@ function LogGeneralField({ fieldKey, fieldValue }: LogFieldProps): JSX.Element {
return (
<TextContainer>
<Text ellipsis type="secondary">
{`${fieldKey}: `}
<Text ellipsis type="secondary" className="log-field-key">
{`${fieldKey} : `}
</Text>
<CopyClipboardHOC textToCopy={fieldValue}>
<LogText dangerouslySetInnerHTML={html} />
</CopyClipboardHOC>
<LogText dangerouslySetInnerHTML={html} className="log-value" />
</TextContainer>
);
}
@@ -72,68 +66,75 @@ function LogSelectedField({
onAddToQuery,
}: LogSelectedFieldProps): JSX.Element {
return (
<SelectedLog>
<div className="log-selected-fields">
<AddToQueryHOC
fieldKey={fieldKey}
fieldValue={fieldValue}
onAddToQuery={onAddToQuery}
>
<Typography.Text>
<span style={{ color: blue[4] }}>{fieldKey}</span>
<span style={{ color: blue[4] }} className="selected-log-field-key">
{fieldKey}
</span>
</Typography.Text>
</AddToQueryHOC>
<CopyClipboardHOC textToCopy={fieldValue}>
<Typography.Text ellipsis>
<span>{': '}</span>
<span style={{ color: orange[6] }}>{fieldValue || "''"}</span>
</Typography.Text>
</CopyClipboardHOC>
</SelectedLog>
<Typography.Text ellipsis className="selected-log-kv">
<span className="selected-log-field-key">{': '}</span>
<span className="selected-log-value">{fieldValue || "''"}</span>
</Typography.Text>
</div>
);
}
type ListLogViewProps = {
logData: ILog;
selectedFields: IField[];
onSetActiveLog: (log: ILog) => void;
onAddToQuery: AddToQueryHOCProps['onAddToQuery'];
activeLog?: ILog | null;
};
function ListLogView({
logData,
selectedFields,
onSetActiveLog,
onAddToQuery,
activeLog,
}: ListLogViewProps): JSX.Element {
const flattenLogData = useMemo(() => FlatLogData(logData), [logData]);
const [, setCopy] = useCopyToClipboard();
const { notifications } = useNotifications();
const [hasActionButtons, setHasActionButtons] = useState<boolean>(false);
const { isHighlighted, isLogsExplorerPage, onLogCopy } = useCopyLogLink(
logData.id,
);
const {
activeLog: activeContextLog,
onAddToQuery: handleAddToQuery,
onSetActiveLog: handleSetActiveContextLog,
onClearActiveLog: handleClearActiveContextLog,
} = useActiveLog();
const {
activeLog,
onSetActiveLog,
onClearActiveLog,
onAddToQuery,
} = useActiveLog();
const handlerClearActiveContextLog = useCallback(
(event: React.MouseEvent | React.KeyboardEvent) => {
event.preventDefault();
event.stopPropagation();
handleClearActiveContextLog();
},
[handleClearActiveContextLog],
);
const handleDetailedView = useCallback(() => {
onSetActiveLog(logData);
}, [logData, onSetActiveLog]);
const handleShowContext = useCallback(() => {
handleSetActiveContextLog(logData);
}, [logData, handleSetActiveContextLog]);
const handleCopyJSON = (): void => {
setCopy(JSON.stringify(logData, null, 2));
notifications.success({
message: 'Copied to clipboard',
});
};
const handleShowContext = useCallback(
(event: React.MouseEvent) => {
event.preventDefault();
event.stopPropagation();
handleSetActiveContextLog(logData);
},
[logData, handleSetActiveContextLog],
);
const updatedSelecedFields = useMemo(
() => selectedFields.filter((e) => e.name !== 'id'),
@@ -148,90 +149,74 @@ function ListLogView({
[flattenLogData.timestamp],
);
const logType = logData?.attributes_string?.log_level || LogType.INFO;
const handleMouseEnter = (): void => {
setHasActionButtons(true);
};
const handleMouseLeave = (): void => {
setHasActionButtons(false);
};
return (
<Container $isActiveLog={isHighlighted}>
<div>
<LogContainer>
<>
<LogGeneralField fieldKey="log" fieldValue={flattenLogData.body} />
{flattenLogData.stream && (
<LogGeneralField fieldKey="stream" fieldValue={flattenLogData.stream} />
)}
<LogGeneralField fieldKey="timestamp" fieldValue={timestampValue} />
</>
</LogContainer>
<div>
{updatedSelecedFields.map((field) =>
isValidLogField(flattenLogData[field.name] as never) ? (
<LogSelectedField
key={field.name}
fieldKey={field.name}
fieldValue={flattenLogData[field.name] as never}
onAddToQuery={onAddToQuery}
/>
) : null,
)}
<>
<Container
$isActiveLog={isHighlighted}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onClick={handleDetailedView}
>
<div className="log-line">
<LogStateIndicator
type={logType}
isActive={
activeLog?.id === logData.id || activeContextLog?.id === logData.id
}
/>
<div>
<LogContainer>
<LogGeneralField fieldKey="Log" fieldValue={flattenLogData.body} />
{flattenLogData.stream && (
<LogGeneralField fieldKey="Stream" fieldValue={flattenLogData.stream} />
)}
<LogGeneralField fieldKey="Timestamp" fieldValue={timestampValue} />
{updatedSelecedFields.map((field) =>
isValidLogField(flattenLogData[field.name] as never) ? (
<LogSelectedField
key={field.name}
fieldKey={field.name}
fieldValue={flattenLogData[field.name] as never}
onAddToQuery={onAddToQuery}
/>
) : null,
)}
</LogContainer>
</div>
</div>
</div>
<Divider style={{ padding: 0, margin: '0.4rem 0', opacity: 0.5 }} />
<Row>
<Button
size="small"
type="text"
onClick={handleDetailedView}
style={{ color: blue[5] }}
icon={<ExpandAltOutlined />}
>
View Details
</Button>
<Button
size="small"
type="text"
onClick={handleCopyJSON}
style={{ color: grey[1] }}
icon={<CopyFilled />}
>
Copy JSON
</Button>
{isLogsExplorerPage && (
<>
<Button
size="small"
type="text"
onClick={handleShowContext}
style={{ color: grey[1] }}
icon={<MonitorOutlined />}
>
Show in Context
</Button>
<Button
size="small"
type="text"
onClick={onLogCopy}
style={{ color: grey[1] }}
icon={<LinkOutlined />}
>
Copy Link
</Button>
</>
)}
{activeContextLog && (
<LogsExplorerContext
log={activeContextLog}
onClose={handleClearActiveContextLog}
{hasActionButtons && isLogsExplorerPage && (
<LogLinesActionButtons
handleShowContext={handleShowContext}
onLogCopy={onLogCopy}
/>
)}
</Container>
{activeContextLog && (
<LogDetail
log={activeLog}
onClose={onClearActiveLog}
onAddToQuery={onAddToQuery}
onClickActionItem={onAddToQuery}
log={activeContextLog}
onAddToQuery={handleAddToQuery}
selectedTab={VIEW_TYPES.CONTEXT}
onClose={handlerClearActiveContextLog}
/>
</Row>
</Container>
)}
</>
);
}
ListLogView.defaultProps = {
activeLog: null,
};
export default ListLogView;

View File

@@ -7,6 +7,7 @@ export const Container = styled(Card)<{
}>`
width: 100% !important;
margin-bottom: 0.3rem;
cursor: pointer;
.ant-card-body {
padding: 0.3rem 0.6rem;
}
@@ -29,11 +30,13 @@ export const TextContainer = styled.div`
export const LogContainer = styled.div`
margin-left: 0.5rem;
display: flex;
flex-direction: column;
gap: 6px;
`;
export const LogText = styled.div`
display: inline-block;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;

View File

@@ -0,0 +1,44 @@
.log-line-action-buttons {
display: flex;
position: absolute;
transform: translate(-50%, -50%);
top: 50%;
right: 0;
cursor: pointer;
border-radius: 2px;
border: 1px solid var(--bg-slate-400);
background: var(--bg-ink-400);
.ant-btn-default {
border: none;
box-shadow: none;
padding: 9px;
justify-content: center;
align-items: center;
display: flex;
&.active-tab {
background-color: var(--bg-slate-400);
}
}
.copy-log-btn {
border-left: 1px solid var(--bg-slate-400);
border-color: var(--bg-slate-400) !important;
}
}
.lightMode {
.log-line-action-buttons {
border: 1px solid var(--bg-vanilla-400);
background: var(--bg-vanilla-400);
.ant-btn-default {
}
.copy-log-btn {
border-left: 1px solid var(--bg-vanilla-400);
border-color: var(--bg-vanilla-400) !important;
}
}
}

View File

@@ -0,0 +1,42 @@
import './LogLinesActionButtons.styles.scss';
import { LinkOutlined } from '@ant-design/icons';
import { Button, Tooltip } from 'antd';
import { TextSelect } from 'lucide-react';
import { MouseEventHandler } from 'react';
export interface LogLinesActionButtonsProps {
handleShowContext: MouseEventHandler<HTMLElement>;
onLogCopy: MouseEventHandler<HTMLElement>;
customClassName?: string;
}
export default function LogLinesActionButtons({
handleShowContext,
onLogCopy,
customClassName = '',
}: LogLinesActionButtonsProps): JSX.Element {
return (
<div className={`log-line-action-buttons ${customClassName}`}>
<Tooltip title="Show Context">
<Button
size="small"
icon={<TextSelect size={14} />}
className="show-context-btn"
onClick={handleShowContext}
/>
</Tooltip>
<Tooltip title="Copy Link">
<Button
size="small"
icon={<LinkOutlined size={14} />}
onClick={onLogCopy}
className="copy-log-btn"
/>
</Tooltip>
</div>
);
}
LogLinesActionButtons.defaultProps = {
customClassName: '',
};

View File

@@ -0,0 +1,30 @@
.log-state-indicator {
padding-left: 8px;
.line {
margin: 0 8px;
min-height: 24px;
height: 100%;
width: 3px;
border-radius: 50px;
background-color: transparent;
&.INFO {
background-color: #1d212d;
}
&.WARNING {
background-color: #ffcd56;
}
&.ERROR {
background-color: #e5484d;
}
}
&.isActive {
.line {
background-color: var(--bg-robin-400, #7190f9);
}
}
}

View File

@@ -0,0 +1,28 @@
import './LogStateIndicator.styles.scss';
import cx from 'classnames';
export const LogType = {
INFO: 'INFO',
WARNING: 'WARNING',
ERROR: 'ERROR',
};
function LogStateIndicator({
type,
isActive,
}: {
type: string;
isActive?: boolean;
}): JSX.Element {
return (
<div className={cx('log-state-indicator', isActive ? 'isActive' : '')}>
<div className={cx('line', type)}> </div>
</div>
);
}
LogStateIndicator.defaultProps = {
isActive: false,
};
export default LogStateIndicator;

View File

@@ -1,11 +1,9 @@
import {
ExpandAltOutlined,
LinkOutlined,
MonitorOutlined,
} from '@ant-design/icons';
import './RawLogView.styles.scss';
import Convert from 'ansi-to-html';
import { Button, DrawerProps, Tooltip } from 'antd';
import { DrawerProps } from 'antd';
import LogDetail from 'components/LogDetail';
import { VIEW_TYPES, VIEWS } from 'components/LogDetail/constants';
import LogsExplorerContext from 'container/LogsExplorerContext';
import dayjs from 'dayjs';
import dompurify from 'dompurify';
@@ -13,6 +11,8 @@ import { useActiveLog } from 'hooks/logs/useActiveLog';
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
// hooks
import { useIsDarkMode } from 'hooks/useDarkMode';
import { FlatLogData } from 'lib/logs/flatLogData';
import { isEmpty, isUndefined } from 'lodash-es';
import {
KeyboardEvent,
MouseEvent,
@@ -22,13 +22,12 @@ import {
useState,
} from 'react';
import LogLinesActionButtons from '../LogLinesActionButtons/LogLinesActionButtons';
import LogStateIndicator, {
LogType,
} from '../LogStateIndicator/LogStateIndicator';
// styles
import {
ActionButtonsWrapper,
ExpandIconWrapper,
RawLogContent,
RawLogViewContainer,
} from './styles';
import { RawLogContent, RawLogViewContainer } from './styles';
import { RawLogViewProps } from './types';
const convert = new Convert();
@@ -39,13 +38,15 @@ function RawLogView({
data,
linesPerRow,
isTextOverflowEllipsisDisabled,
selectedFields = [],
}: RawLogViewProps): JSX.Element {
const { isHighlighted, isLogsExplorerPage, onLogCopy } = useCopyLogLink(
data.id,
);
const flattenLogData = useMemo(() => FlatLogData(data), [data]);
const {
activeLog: activeContextLog,
onSetActiveLog: handleSetActiveContextLog,
onClearActiveLog: handleClearActiveContextLog,
} = useActiveLog();
const {
@@ -56,24 +57,47 @@ function RawLogView({
} = useActiveLog();
const [hasActionButtons, setHasActionButtons] = useState<boolean>(false);
const [selectedTab, setSelectedTab] = useState<VIEWS | undefined>();
const isDarkMode = useIsDarkMode();
const isReadOnlyLog = !isLogsExplorerPage || isReadOnly;
const severityText = data.severity_text ? `${data.severity_text} |` : '';
const logType = data?.attributes_string?.log_level || LogType.INFO;
const updatedSelecedFields = useMemo(
() => selectedFields.filter((e) => e.name !== 'id'),
[selectedFields],
);
const attributesValues = updatedSelecedFields
.map((field) => flattenLogData[field.name])
.filter((attribute) => !isUndefined(attribute) && !isEmpty(attribute));
let attributesText = attributesValues.join(' | ');
if (attributesText.length > 0) {
attributesText += ' | ';
}
const text = useMemo(
() =>
typeof data.timestamp === 'string'
? `${dayjs(data.timestamp).format()} | ${severityText} ${data.body}`
: `${dayjs(data.timestamp / 1e6).format()} | ${severityText} ${data.body}`,
[data.timestamp, data.body, severityText],
? `${dayjs(data.timestamp).format()} | ${attributesText} ${severityText} ${
data.body
}`
: `${dayjs(
data.timestamp / 1e6,
).format()} | ${attributesText} ${severityText} ${data.body}`,
[data.timestamp, data.body, severityText, attributesText],
);
const handleClickExpand = useCallback(() => {
if (activeContextLog || isReadOnly) return;
onSetActiveLog(data);
setSelectedTab(VIEW_TYPES.OVERVIEW);
}, [activeContextLog, isReadOnly, data, onSetActiveLog]);
const handleCloseLogDetail: DrawerProps['onClose'] = useCallback(
@@ -84,6 +108,7 @@ function RawLogView({
event.stopPropagation();
onClearActiveLog();
setSelectedTab(undefined);
},
[onClearActiveLog],
);
@@ -104,9 +129,11 @@ function RawLogView({
(event) => {
event.preventDefault();
event.stopPropagation();
handleSetActiveContextLog(data);
// handleSetActiveContextLog(data);
setSelectedTab(VIEW_TYPES.CONTEXT);
onSetActiveLog(data);
},
[data, handleSetActiveContextLog],
[data, onSetActiveLog],
);
const html = useMemo(
@@ -123,37 +150,30 @@ function RawLogView({
align="middle"
$isDarkMode={isDarkMode}
$isReadOnly={isReadOnly}
$isActiveLog={isHighlighted}
$isHightlightedLog={isHighlighted}
$isActiveLog={isActiveLog}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
{!isReadOnly && (
<ExpandIconWrapper flex="30px">
<ExpandAltOutlined />
</ExpandIconWrapper>
)}
<LogStateIndicator
type={logType}
isActive={activeLog?.id === data.id || activeContextLog?.id === data.id}
/>
<RawLogContent
$isReadOnly={isReadOnly}
$isActiveLog={isActiveLog}
$isDarkMode={isDarkMode}
$isTextOverflowEllipsisDisabled={isTextOverflowEllipsisDisabled}
linesPerRow={linesPerRow}
dangerouslySetInnerHTML={html}
/>
{hasActionButtons && (
<ActionButtonsWrapper>
<Tooltip title="Show Context">
<Button
size="small"
icon={<MonitorOutlined />}
onClick={handleShowContext}
/>
</Tooltip>
<Tooltip title="Copy Link">
<Button size="small" icon={<LinkOutlined />} onClick={onLogCopy} />
</Tooltip>
</ActionButtonsWrapper>
<LogLinesActionButtons
handleShowContext={handleShowContext}
onLogCopy={onLogCopy}
/>
)}
{activeContextLog && (
@@ -162,12 +182,15 @@ function RawLogView({
onClose={handleClearActiveContextLog}
/>
)}
<LogDetail
log={activeLog}
onClose={handleCloseLogDetail}
onAddToQuery={onAddToQuery}
onClickActionItem={onAddToQuery}
/>
{selectedTab && (
<LogDetail
selectedTab={selectedTab}
log={activeLog}
onClose={handleCloseLogDetail}
onAddToQuery={onAddToQuery}
onClickActionItem={onAddToQuery}
/>
)}
</RawLogViewContainer>
);
}

View File

@@ -1,4 +1,5 @@
import { blue } from '@ant-design/colors';
import { Color } from '@signozhq/design-tokens';
import { Col, Row, Space } from 'antd';
import styled from 'styled-components';
import { getActiveLogBackground, getDefaultLogBackground } from 'utils/logs';
@@ -9,20 +10,25 @@ export const RawLogViewContainer = styled(Row)<{
$isDarkMode: boolean;
$isReadOnly?: boolean;
$isActiveLog?: boolean;
$isHightlightedLog: boolean;
}>`
position: relative;
width: 100%;
font-weight: 700;
font-size: 0.625rem;
line-height: 1.25rem;
display: flex;
align-items: stretch;
transition: background-color 0.2s ease-in;
.log-state-indicator {
margin: 4px 0;
}
${({ $isActiveLog }): string => getActiveLogBackground($isActiveLog)}
${({ $isReadOnly, $isDarkMode, $isActiveLog }): string =>
${({ $isReadOnly, $isActiveLog, $isDarkMode }): string =>
$isActiveLog
? getActiveLogBackground()
? getActiveLogBackground($isActiveLog, $isDarkMode)
: getDefaultLogBackground($isReadOnly, $isDarkMode)}
`;
@@ -30,13 +36,17 @@ export const ExpandIconWrapper = styled(Col)`
color: ${blue[6]};
padding: 0.25rem 0.375rem;
cursor: pointer;
font-size: 12px;
`;
export const RawLogContent = styled.div<RawLogContentProps>`
margin-bottom: 0;
font-family: Fira Code, monospace;
font-weight: 300;
font-family: 'SF Mono', monospace;
font-family: 'Space Mono', monospace;
font-size: 13px;
font-weight: 400;
text-align: left;
color: ${({ $isDarkMode }): string =>
$isDarkMode ? Color.BG_VANILLA_400 : Color.BG_INK_400};
${({ $isTextOverflowEllipsisDisabled, linesPerRow }): string =>
$isTextOverflowEllipsisDisabled
@@ -48,14 +58,12 @@ export const RawLogContent = styled.div<RawLogContentProps>`
line-clamp: ${linesPerRow};
-webkit-box-orient: vertical;`};
font-size: 1rem;
line-height: 2rem;
line-height: 24px;
letter-spacing: -0.07px;
padding: 4px;
cursor: ${({ $isActiveLog, $isReadOnly }): string =>
$isActiveLog || $isReadOnly ? 'initial' : 'pointer'};
${({ $isActiveLog, $isReadOnly }): string =>
$isReadOnly && $isActiveLog ? 'padding: 0 1.5rem;' : ''}
`;
export const ActionButtonsWrapper = styled(Space)`

View File

@@ -1,3 +1,4 @@
import { IField } from 'types/api/logs/fields';
import { ILog } from 'types/api/logs/log';
export interface RawLogViewProps {
@@ -6,11 +7,13 @@ export interface RawLogViewProps {
isTextOverflowEllipsisDisabled?: boolean;
data: ILog;
linesPerRow: number;
selectedFields?: IField[];
}
export interface RawLogContentProps {
linesPerRow: number;
$isReadOnly?: boolean;
$isActiveLog?: boolean;
$isDarkMode?: boolean;
$isTextOverflowEllipsisDisabled?: boolean;
}

View File

@@ -1,12 +1,21 @@
import { TableProps } from 'antd';
import { CSSProperties } from 'react';
export const defaultCellStyle: CSSProperties = {
paddingTop: 4,
paddingBottom: 6,
paddingRight: 8,
paddingLeft: 8,
};
export function getDefaultCellStyle(isDarkMode?: boolean): CSSProperties {
return {
paddingTop: 4,
paddingBottom: 6,
paddingRight: 8,
paddingLeft: 8,
color: isDarkMode ? 'var(--bg-vanilla-400)' : 'var(--bg-slate-400)',
fontSize: '14px',
fontStyle: 'normal',
fontWeight: 400,
lineHeight: '18px',
letterSpacing: '-0.07px',
marginBottom: '0px',
};
}
export const defaultTableStyle: CSSProperties = {
minWidth: '40rem',

View File

@@ -2,18 +2,22 @@ import styled from 'styled-components';
interface TableBodyContentProps {
linesPerRow: number;
isDarkMode?: boolean;
}
export const TableBodyContent = styled.div<TableBodyContentProps>`
margin-bottom: 0;
color: ${(props): string =>
props.isDarkMode ? 'var(--bg-vanilla-400, #c0c1c3)' : 'var(--bg-slate-400)'};
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px; /* 128.571% */
letter-spacing: -0.07px;
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;
font-size: 0.875rem;
line-height: 2rem;
`;

View File

@@ -22,6 +22,8 @@ export type UseTableViewProps = {
appendTo?: 'center' | 'end';
onOpenLogsContext?: (log: ILog) => void;
onClickExpand?: (log: ILog) => void;
activeLog?: ILog | null;
activeContextLog?: ILog | null;
} & LogsTableViewProps;
export type ActionsColumnProps = {

View File

@@ -0,0 +1,27 @@
.text {
color: var(--bg-vanilla-400);
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 18px; /* 128.571% */
letter-spacing: -0.07px;
}
.table-timestamp {
display: flex;
align-items: center;
.ant-typography {
margin-bottom: 0;
}
.log-state-indicator {
padding: 0px;
}
}
.lightMode {
.text {
color: var(--bg-slate-400);
}
}

View File

@@ -1,22 +1,21 @@
import {
ExpandAltOutlined,
LinkOutlined,
MonitorOutlined,
} from '@ant-design/icons';
import './useTableView.styles.scss';
import Convert from 'ansi-to-html';
import { Button, Space, Typography } from 'antd';
import { Typography } from 'antd';
import { ColumnsType } from 'antd/es/table';
import dayjs from 'dayjs';
import dompurify from 'dompurify';
import { useCopyLogLink } from 'hooks/logs/useCopyLogLink';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { FlatLogData } from 'lib/logs/flatLogData';
import { useCallback, useMemo } from 'react';
import { defaultTo } from 'lodash-es';
import { useMemo } from 'react';
import { ExpandIconWrapper } from '../RawLogView/styles';
import { defaultCellStyle, defaultTableStyle } from './config';
import LogStateIndicator, {
LogType,
} from '../LogStateIndicator/LogStateIndicator';
import { defaultTableStyle, getDefaultCellStyle } from './config';
import { TableBodyContent } from './styles';
import {
ActionsColumnProps,
ColumnTypeRender,
UseTableViewProps,
UseTableViewResult,
@@ -24,60 +23,22 @@ import {
const convert = new Convert();
function ActionsColumn({
logId,
logs,
onOpenLogsContext,
}: ActionsColumnProps): JSX.Element {
const currentLog = useMemo(() => logs.find(({ id }) => id === logId), [
logs,
logId,
]);
const { onLogCopy } = useCopyLogLink(currentLog?.id);
const handleShowContext = useCallback(() => {
if (!onOpenLogsContext || !currentLog) return;
onOpenLogsContext(currentLog);
}, [currentLog, onOpenLogsContext]);
return (
<Space>
<Button
size="small"
onClick={handleShowContext}
icon={<MonitorOutlined />}
/>
<Button size="small" onClick={onLogCopy} icon={<LinkOutlined />} />
</Space>
);
}
export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
const {
logs,
fields,
linesPerRow,
appendTo = 'center',
onOpenLogsContext,
onClickExpand,
activeContextLog,
activeLog,
} = props;
const { isLogsExplorerPage } = useCopyLogLink();
const isDarkMode = useIsDarkMode();
const flattenLogData = useMemo(() => logs.map((log) => FlatLogData(log)), [
logs,
]);
const handleClickExpand = useCallback(
(index: number): void => {
if (!onClickExpand) return;
onClickExpand(logs[index]);
},
[logs, onClickExpand],
);
const columns: ColumnsType<Record<string, unknown>> = useMemo(() => {
const fieldColumns: ColumnsType<Record<string, unknown>> = fields
.filter((e) => e.name !== 'id')
@@ -87,7 +48,7 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
key: name,
render: (field): ColumnTypeRender<Record<string, unknown>> => ({
props: {
style: defaultCellStyle,
style: getDefaultCellStyle(isDarkMode),
},
children: (
<Typography.Paragraph ellipsis={{ rows: linesPerRow }}>
@@ -98,38 +59,30 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
}));
return [
{
title: '',
dataIndex: 'id',
key: 'expand',
// https://github.com/ant-design/ant-design/discussions/36886
render: (_, item, index): ColumnTypeRender<Record<string, unknown>> => ({
props: {
style: defaultCellStyle,
},
children: (
<ExpandIconWrapper
onClick={(): void => {
handleClickExpand(index);
}}
>
<ExpandAltOutlined />
</ExpandIconWrapper>
),
}),
},
{
title: 'timestamp',
dataIndex: 'timestamp',
key: 'timestamp',
// https://github.com/ant-design/ant-design/discussions/36886
render: (field): ColumnTypeRender<Record<string, unknown>> => {
render: (field, item): ColumnTypeRender<Record<string, unknown>> => {
const date =
typeof field === 'string'
? dayjs(field).format()
: dayjs(field / 1e6).format();
return {
children: <Typography.Paragraph ellipsis>{date}</Typography.Paragraph>,
children: (
<div className="table-timestamp">
<LogStateIndicator
type={defaultTo(item.log_level, LogType.INFO) as string}
isActive={
activeLog?.id === item.id || activeContextLog?.id === item.id
}
/>
<Typography.Paragraph ellipsis className="text">
{date}
</Typography.Paragraph>
</div>
),
};
},
},
@@ -148,38 +101,20 @@ export const useTableView = (props: UseTableViewProps): UseTableViewResult => {
__html: convert.toHtml(dompurify.sanitize(field)),
}}
linesPerRow={linesPerRow}
isDarkMode={isDarkMode}
/>
),
}),
},
...(appendTo === 'end' ? fieldColumns : []),
...(isLogsExplorerPage
? ([
{
title: 'actions',
dataIndex: 'actions',
key: 'actions',
render: (_, log): ColumnTypeRender<Record<string, unknown>> => ({
children: (
<ActionsColumn
logId={(log.id as unknown) as string}
logs={logs}
onOpenLogsContext={onOpenLogsContext}
/>
),
}),
},
] as ColumnsType<Record<string, unknown>>)
: []),
];
}, [
logs,
fields,
appendTo,
isDarkMode,
linesPerRow,
isLogsExplorerPage,
handleClickExpand,
onOpenLogsContext,
activeLog?.id,
activeContextLog?.id,
]);
return { columns, dataSource: flattenLogData };

View File

@@ -0,0 +1,394 @@
.nested-menu-container {
z-index: 2;
position: absolute;
right: -2px;
margin: 6px 0;
width: 160px;
border-radius: 4px;
border: 1px solid var(--bg-slate-400, #1d212d);
background: linear-gradient(
139deg,
rgba(18, 19, 23, 0.8) 0%,
rgba(18, 19, 23, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
.menu-container {
padding: 12px;
.title {
font-family: Inter;
font-size: 11px;
font-weight: 600;
line-height: 18px;
letter-spacing: 0.08em;
text-align: left;
color: var(--bg-slate-200, #52575c);
}
.menu-items {
display: flex;
gap: 12px;
flex-direction: column;
margin-top: 12px;
}
.item {
font-family: Inter;
font-size: 13px;
font-weight: 400;
line-height: 17px;
letter-spacing: 0.01em;
text-align: left;
.item-label {
display: flex;
color: var(--bg-vanilla-400, #c0c1c3);
justify-content: space-between;
}
cursor: pointer;
}
}
.horizontal-line {
height: 1px;
background: #1d212d;
}
.max-lines-per-row {
padding: 12px;
.title {
color: var(--bg-slate-200, #52575c);
font-family: Inter;
font-size: 11px;
font-style: normal;
font-weight: 600;
line-height: 18px; /* 163.636% */
letter-spacing: 0.88px;
text-transform: uppercase;
margin-bottom: 12px;
display: flex;
justify-content: space-between;
align-items: center;
.lucide {
color: var(--bg-vanilla-400, #c0c1c3);
cursor: pointer;
}
}
.max-lines-per-row-input {
display: flex;
border: 1px solid var(--bg-slate-400, #1d212d);
.ant-input-number-handler-wrap {
display: none;
}
.ant-input-number {
min-width: 36px;
width: auto;
border: 0px;
text-align: center;
height: 26px;
border-radius: 0;
&:active,
&:focus {
border: none;
box-shadow: none;
}
}
.ant-input-number-focused {
box-shadow: none !important;
}
.ant-input-number-input-wrap {
input {
text-align: center;
font-size: 13px;
&:active,
&:focus {
border: none;
}
}
&:active,
&:focus {
border: none;
}
}
.periscope-btn {
box-shadow: none;
padding: 6px 12px;
height: 26px;
border-radius: 0px 1px 1px 0px;
background: var(--bg-ink-300, #16181d);
}
}
}
.selected-item-content-container {
.add-new-column-header {
padding: 8px;
}
.title {
color: var(--bg-slate-200, #52575c);
font-family: Inter;
font-size: 11px;
font-style: normal;
font-weight: 600;
line-height: 18px; /* 163.636% */
letter-spacing: 0.88px;
text-transform: uppercase;
margin-bottom: 12px;
display: flex;
justify-content: space-between;
align-items: center;
.lucide {
color: var(--bg-vanilla-400, #c0c1c3);
cursor: pointer;
}
}
.horizontal-line {
height: 1px;
background: #1d212d;
}
.loading-container {
margin: 12px 0;
}
.item-content {
padding: 12px;
.column-format,
.column-format-new-options {
display: flex;
gap: 12px;
flex-direction: column;
margin-top: 12px;
.column-name {
color: var(--bg-vanilla-400, #c0c1c3);
font-family: Inter;
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: 20px; /* 142.857% */
letter-spacing: -0.07px;
display: flex;
justify-content: space-between;
align-items: center;
gap: 8px;
cursor: pointer;
.name {
flex: 1;
overflow: hidden;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
cursor: pointer;
}
.delete-btn {
display: none;
flex: 0 0 16px;
cursor: pointer;
}
&:hover {
.delete-btn {
display: block;
}
}
}
overflow-x: hidden;
&::-webkit-scrollbar {
height: 1rem;
width: 0.2rem;
}
}
.column-format {
max-height: 150px;
overflow: auto;
overflow-x: hidden;
}
.column-format-new-options {
max-height: 150px;
overflow-y: auto;
overflow-x: hidden;
}
.column-divider {
margin: 12px 0;
border-top: 2px solid var(--bg-slate-400);
}
}
}
&.active {
.nested-menu-container {
backdrop-filter: blur(18px);
.item {
.item-label {
color: var(--bg-vanilla-400);
}
}
}
.selected-item-content-container {
width: 110%;
margin-left: -5%;
border-radius: 4px;
border: 1px solid var(--bg-slate-400);
background: linear-gradient(
139deg,
rgba(18, 19, 23, 0.8) 0%,
rgba(18, 19, 23, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(0, 0, 0, 0.2);
backdrop-filter: blur(20px);
.column-format {
margin-top: 0px;
}
}
}
}
.lightMode {
.nested-menu-container {
border: 1px solid var(--bg-vanilla-300);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(255, 255, 255, 0.2);
.horizontal-line {
background: var(--bg-vanilla-300);
}
.item-content {
.column-divider {
border-top: 2px solid var(--bg-vanilla-300);
}
}
.max-lines-per-row {
.title {
color: var(--bg-ink-200);
.lucide {
color: var(--bg-ink-300);
}
}
.max-lines-per-row-input {
border: 1px solid var(--bg-vanilla-300);
.periscope-btn {
background: var(--bg-vanilla-300);
}
}
}
.menu-container {
.title {
color: var(--bg-ink-200);
}
.item {
.item-label {
color: var(--bg-ink-400);
}
}
}
.selected-item-content-container {
.title {
color: var(--bg-ink-200);
.lucide {
color: var(--bg-ink-300);
}
}
.horizontal-line {
background: var(--bg-vanilla-300);
}
.item-content {
.max-lines-per-row-input {
border: 1px solid var(--bg-vanilla-300);
.periscope-btn {
background: var(--bg-vanilla-300);
}
}
.column-format,
.column-format-new-options {
.column-name {
color: var(--bg-ink-300);
}
}
}
}
&.active {
.nested-menu-container {
backdrop-filter: blur(18px);
.item {
.item-label {
color: var(--bg-ink-300);
}
}
}
.selected-item-content-container {
border: 1px solid var(--bg-vanilla-300);
background: linear-gradient(
139deg,
rgba(255, 255, 255, 0.8) 0%,
rgba(255, 255, 255, 0.9) 98.68%
);
box-shadow: 4px 10px 16px 2px rgba(255, 255, 255, 0.2);
}
}
}
}

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