Compare commits

..

91 Commits

Author SHA1 Message Date
Vinícius Lourenço
0b1e8aad6e fixup! feat(integrations): adopt reworked @signozhq/ui components 2026-10-06 15:06:37 -03:00
Vinícius Lourenço
5685de5494 fixup! feat(llm-observability): adopt reworked @signozhq/ui components 2026-10-06 15:06:32 -03:00
Vinícius Lourenço
b21742a128 fixup! feat(settings): adopt reworked @signozhq/ui components 2026-10-01 15:00:58 -03:00
Vinícius Lourenço
843feef61d fix(alerts): use Pill.Closeable for classic alert form labels 2026-10-01 12:02:15 -03:00
Vinícius Lourenço
6984683fd9 test(integrations): raise timeout for GCP setup drawer tests 2026-10-01 12:02:15 -03:00
Vinícius Lourenço
1407b26fbb fix(planned-downtime): use Pill.Closeable for selected alert rules 2026-10-01 12:02:15 -03:00
Vinícius Lourenço
aed715be5c fix(pipelines): submit the pipeline form from the Create and Update button 2026-10-01 12:02:14 -03:00
Vinícius Lourenço
8ef90b84b6 test(e2e): update selectors for reworked @signozhq/ui components 2026-10-01 12:02:14 -03:00
Vinícius Lourenço
2315a18fa4 feat(events-exceptions-apis-queues): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:14 -03:00
Vinícius Lourenço
77834e2b22 feat(events-traces): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:14 -03:00
Vinícius Lourenço
a37ee50c7d feat(events-logs): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:14 -03:00
Vinícius Lourenço
a05baddab0 feat(pulse-infra-monitoring): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:14 -03:00
Vinícius Lourenço
099c5135db feat(pulse-alerts): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:13 -03:00
Vinícius Lourenço
268af75098 feat(pulse-dashboards-list): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:13 -03:00
Vinícius Lourenço
a5e395120f feat(pulse-dashboards): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:13 -03:00
Vinícius Lourenço
c4be50c5c2 feat(metrics-apm): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:13 -03:00
Vinícius Lourenço
8dd0f79f70 feat(llm-observability): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:13 -03:00
Vinícius Lourenço
86212a1b1c feat(ai-assistant): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:13 -03:00
Vinícius Lourenço
9f580456ba feat(integrations): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:12 -03:00
Vinícius Lourenço
6e07d9827f feat(auth-onboarding): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:12 -03:00
Vinícius Lourenço
b146c15a97 feat(settings): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:12 -03:00
Vinícius Lourenço
738f341131 feat(navigation): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:12 -03:00
Vinícius Lourenço
fc1d81dda8 feat(query-builder): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:12 -03:00
Vinícius Lourenço
c52e41afbf feat(shared-components): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:11 -03:00
Vinícius Lourenço
e0dc068af3 feat(members-roles-service-accounts): adopt reworked @signozhq/ui components
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:11 -03:00
Vinícius Lourenço
ee4043f42d feat(authz): build AuthZ components on reworked @signozhq/ui
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:11 -03:00
Vinícius Lourenço
f3c4c8685a fix(api): treat requests cancelled before dispatch as cancellations
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:11 -03:00
Vinícius Lourenço
4e7fbdbfeb test(storybook): adopt reworked @signozhq/ui in fixtures and mocks
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:11 -03:00
Vinícius Lourenço
21e2a0bda8 chore(deps): bump @signozhq/ui to 0.2.0 and design-tokens to 2.2.1
Co-authored-by: Manika Malhotra <manika@signoz.io>
2026-10-01 12:02:11 -03:00
Vinícius Lourenço
867b958318 test(storybook): cover classic alert form label states 2026-10-01 12:00:26 -03:00
Vinícius Lourenço
088fe04a20 test(storybook): add planned downtime edit story with specific alert rules 2026-10-01 12:00:26 -03:00
Vinícius Lourenço
0002d9c5f8 test(storybook): hold Noz click-opened state past the thread remount 2026-10-01 12:00:26 -03:00
Vinícius Lourenço
c8b6e83474 test(storybook): drop the fixed pause between filter keystrokes 2026-10-01 12:00:25 -03:00
Vinícius Lourenço
5607edb302 test(storybook): find dashboard settings and panel editor controls by test id 2026-10-01 12:00:25 -03:00
Vinícius Lourenço
680ac5e88f fix(tanstack-table): keep cells mounted when inline row callbacks change 2026-10-01 12:00:25 -03:00
Vinícius Lourenço
09f9d2f3c8 test(storybook): cover panel editor chart options, thresholds and links 2026-10-01 12:00:25 -03:00
Vinícius Lourenço
203d7a0753 test(storybook): cover dashboard settings, variables and authz states 2026-10-01 12:00:25 -03:00
Vinícius Lourenço
3ba8c9390c fix(storybook): attribute failed responses to the story that sent them 2026-10-01 11:59:59 -03:00
Vinícius Lourenço
6cc07a4d75 test(storybook): cover Noz voice recording states 2026-10-01 11:59:58 -03:00
Vinícius Lourenço
856cd91491 test(storybook): assert the in-flight create key button is disabled 2026-10-01 11:59:58 -03:00
Vinícius Lourenço
f22196a2c0 test(storybook): cover ingestion create key validation, expiry and submit states 2026-10-01 11:59:58 -03:00
Vinícius Lourenço
0438850c45 test(storybook): cover ingestion key tag adding and added states 2026-10-01 11:59:58 -03:00
Vinícius Lourenço
2cc9421350 test(storybook): click exceptions filter suggestions as they are found 2026-10-01 11:59:58 -03:00
Vinícius Lourenço
c692297ca6 test(storybook): hold the pod filter stories at their opening height 2026-10-01 11:59:58 -03:00
Vinícius Lourenço
cc6ddd5233 test(storybook): wait for the filter's scrollbars before focusing it 2026-10-01 11:59:57 -03:00
Vinícius Lourenço
d72424d9d0 test(storybook): keep filter focused while scrollbars initialise 2026-10-01 11:59:57 -03:00
Vinícius Lourenço
bbec5691e0 test(storybook): add query builder filter interaction stories 2026-10-01 11:59:57 -03:00
Vinícius Lourenço
cf61f7b31a test(storybook): fix interaction stories against current main 2026-10-01 11:59:57 -03:00
Vinícius Lourenço
02055934ba test(storybook): add interaction stories for menus, drawers and selects 2026-10-01 11:59:57 -03:00
Vinicius Lourenço
434b282549 chore(dashboard-story): answer variable endpoints outside the Data state control (#13000)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
#### Description

To try prevent flakyness of
https://github.com/SigNoz/signoz/actions/runs/36460317287/job/109056950899#step:7:9349
2026-10-01 14:07:41 +00:00
Aditya Singh
ecdc57836c feat(bottom-strip): add right side actions and the per page left slot (#12961)
#### Description

- adds ask noz and support to the right side of the strip. support is
one button covering both floating bubbles.. only one of them ever showed
at a time, so it is pylon for users who have it and the add credit card
modal for trial users without a card. only the bubbles are hidden, noz
in the header and side nav stays for now.
- the support gating was spread across AppRoutes and two components,
each rebuilding the same feature flag + license + trial checks. pulled
into `useChatSupport`, and the add credit card modal into one shared
component.. support page still has its own copy, that goes with cleanup.
- left side is a store the strip subscribes to. pages push a node with
`useBottomStripLeft` and it clears on unmount.. strip knows nothing
about pages. falls back to the build version when nothing is set.
- the node comes from the page, so it is wrapped in an error boundary
that falls back to the version. the strip sits outside the app layout
boundary on purpose so it survives a page crash.. without this a bad
node would reach the top level one and blank the whole app.
- trace details is the first consumer, spans and errors. page passes the
values instead of the node fetching them.. the trace query key includes
the selected span so a self fetching node would refetch on every span
click. header counts stay as is.

#### Issues closed by this PR

Part of https://github.com/SigNoz/events-pod/issues/51
Part of https://github.com/SigNoz/events-pod/issues/52

#### Screen recording


https://github.com/user-attachments/assets/12d476e5-a486-4903-974e-e0964ffa3e3c



#### Additional Information

- no loading state or error handling on the count yet and the numbers
are raw.. doing all three in one pass once the rest of the pages are
wired.
- no analytics here, that comes with the analytics ticket.
- pylon and the add card flow were tested locally with temp code. the
pylon chat window offset and bubble hiding still need a pylon enabled
tenant to verify.
- the conversation history popover for the right side is still to do, so
6075 stays open.
2026-10-01 13:39:35 +00:00
Vikrant Gupta
572345be63 feat(authz): enable FGA for users and reset password tokens (#13020)
#### Description

- Moves the users API off the legacy `AdminAccess` gate onto
`CheckResources` + `ResourceDef`s; `me` and anonymous password flows
stay `OpenAccess`.
- Invite checks `role:attach` per requested role; an empty role list
resolves to no link, so the sibling def skips the check.
- Migration `131_add_user_tuples` backfills admin `user` and
`factor-password` tuples for existing orgs.

#### Issues closed by this PR

Closes: SigNoz/keystone-pod#38
2026-10-01 11:26:18 +00:00
Nikhil Soni
bcf96f2816 feat(traces-qb): gate JSON span attribute reads behind a feature flag (#12966)
#### Description

- The new feature flag `use_trace_attributes_json` (default off) now
gates the JSON columns in the traces `getColumn`, alongside the
evolution entry.
- `SelectEvolutionsForColumns` now ignores evolutions of columns the
mapper didn't return instead of erroring, so a flag-off attribute
resolves to its map even though the key carries the JSON evolution.

Part of https://github.com/SigNoz/signoz/pull/12966

#### Additional Information

- Evolution entry migration: SigNoz/signoz-otel-collector#928
- Original QB PR: #4781
2026-10-01 10:21:10 +00:00
Yunus M
a707ed6928 feat: implement error handling and retry mechanism for assistant messages (#11913)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
## Pull Request

---

### 📄 Summary
> Why does this change exist?  
> What problem does it solve, and why is this the right approach?

The AI Assistant previously surfaced streaming failures with minimal
structure: a plain error string, no distinction between transient vs
permanent failures, and no way for users to recover without retyping or
refreshing. Backend SSE errors now carry `retryAction` (`auto` /
`manual` / `none`) and structured error codes, but the frontend was not
honoring that contract end-to-end.

This PR wires full error handling and retry into the assistant:

- **Centralized error resolution** — `resolveAssistantErrorMessage` is
replaced by `resolveAssistantError`, which maps backend codes to
user-friendly copy, classifies rate-limit vs non-retryable errors, and
derives the correct `retryAction`.
- **Dual retry budgets in the store** — `streamWithAuthRetry` becomes
`streamWithRetry`, handling auth expiry (one silent re-attempt) and
backend-flagged transient errors (up to 2 auto-retries with 500ms /
1500ms backoff). When auto-retries are exhausted, the error is
downgraded to `manual` so the user can still retry.
- **Manual retry UX** — failed turns commit as styled error bubbles
(`isError`, `errorCode`, `retryAction`). Manual errors show an inline
**Retry** button that replays the originating action (send, approve,
clarify, regenerate) without duplicating the user message. A transient
`retryRegistry` holds the replay thunk for the latest failed turn.
- **Analytics** — `RetryClicked` event fired when the user clicks Retry.

This aligns the UI with the backend error contract and gives users a
clear, actionable path to recover from transient failures.

#### Screenshots / Screen Recordings (if applicable)
> Include screenshots or screen recordings that clearly show the
behavior before the change and the result after the change. This helps
reviewers quickly understand the impact and verify the update.

| Before | After |
|--------|-------|
| Generic/unstructured error text in assistant bubble | Error callout
with warning icon, code-specific copy, and **Retry** button for manual
errors |
| No retry affordance | Retry replays the failed action; auto-retries
happen silently for transient errors |
| Feedback bar shown on errors | Feedback/regenerate hidden on error
bubbles; rate-limit errors still suppress retry |

_Add screenshots of: (1) `thread_busy` manual error with Retry, (2)
rate-limit error with no Retry, (3) successful recovery after Retry._

#### Issues closed by this PR
> Reference issues using `Closes #issue-number` to enable automatic
closure on merge.

Fixes:  https://github.com/SigNoz/nerve-pod/issues/92

---

### ✅ Change Type
_Select all that apply_

- [x] ✨ Feature
- [ ] 🐛 Bug fix
- [ ] ♻️ Refactor
- [ ] 🛠️ Infra / Tooling
- [x] 🧪 Test-only

---

### 🐛 Bug Context
> Required if this PR fixes a bug

N/A — this is primarily a feature/enhancement to error handling UX, not
a targeted bug fix.

---

### 🧪 Testing Strategy
> How was this change validated?

- Tests added/updated:
- `resolveAssistantError.test.ts` — error code copy, rate-limit
classification, non-retryable codes, HTTP/SSE error shapes,
`retryAction` derivation
- `useAIAssistantStore.test.ts` — manual error bubbles, manual retry
replay (send + approve), auto-retry with backoff and downgrade to
manual, silent recovery on auto-retry success, rate-limit errors with no
retry
- `MessageBubble.test.tsx` — error styling, Retry button visibility
(`manual` vs `none`), `onRetry` callback, feedback bar suppressed on
errors
- Removed `resolveAssistantErrorMessage.test.ts` (superseded by
`resolveAssistantError`)

- Manual verification:
- Trigger `thread_busy` during an active execution → error bubble with
Retry → click Retry → successful response without duplicate user message
- Trigger rate-limit error → error bubble, no Retry button, no feedback
bar
- Trigger transient `internal_error` with `retryAction: auto` → silent
retries; if all fail, manual Retry appears

- Edge cases covered:
- Auth expiry mid-stream (`invalid_token`) — one auth retry via
`streamWithRetry`
  - Auto-retry budget exhaustion (2 attempts) → manual Retry affordance
- Retry replays originating action for approve/clarify/regenerate, not
just send
  - Retry no-op when `retryAction: none` or no registry entry
  - Retry disabled while streaming is active

---

### ⚠️ Risk & Impact Assessment
> What could break? How do we recover?

- Blast radius: AI Assistant chat only — `useAIAssistantStore`,
`MessageBubble`, `VirtualizedMessages`, error utils
- Potential regressions:
- Error copy regressions if a new backend code is not in
`ERROR_CODE_COPY` (falls back to backend message)
- Auto-retry backoff may add latency (up to ~2s) before surfacing a
manual error for transient failures
- `retryRegistry` is in-memory only — page reload drops retry capability
(acceptable; user can resend)
- Rollback plan: Revert PR; no schema/migration changes

---

### 📝 Changelog
> Fill only if this affects users, APIs, UI, or documented behavior  
> Use **N/A** for internal or non-user-facing changes

| Field | Value |
|------|-------|
| Deployment Type | Cloud / OSS / Enterprise |
| Change Type | Feature |
| Description | AI Assistant now shows clearer error messages with
inline Retry for recoverable failures, and silently retries transient
backend errors before asking the user to retry. |

---

### 📋 Checklist
- [x] Tests added or explicitly not required
- [ ] Manually tested
- [ ] Breaking changes documented
- [x] Backward compatibility considered

---

## 👀 Notes for Reviewers

<!-- Anything reviewers should keep in mind while reviewing -->

- **`resolveAssistantErrorMessage.ts` → `resolveAssistantError.ts`**:
The new util returns a full `AssistantErrorResolution` object instead of
just a string. All call sites in the store were updated accordingly.
- **`streamWithRetry`**: Auth retry (1×) and auto retry (2× with
backoff) are independent budgets. When auto retries are spent,
`retryAction` is forced to `manual` before the error propagates to
`finalizeStreamingError`.
- **`retryRegistry`**: Transient map keyed by `conversationId`; not
persisted. Pairs with the error bubble's lifetime.
- **Error bubble UI**: Uses `@signozhq/ui` `Button` and
`@signozhq/icons` (`TriangleAlert`, `RotateCw`). Feedback/regenerate bar
is hidden on `isError` messages (same as rate-limit).
- **Files touched (12)**: store, error util, MessageBubble (+ styles),
VirtualizedMessages, types, events, 3 new test files, 1 removed test
file.

---
2026-10-01 05:46:02 +00:00
Vikrant Gupta
e374d03e54 revert(authz): restore gjson-based body extraction in resource middleware (#13024)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
#### Description

- Reverts #13014 and #13015. The resource middleware goes back to
reading body-derived resource ids with `BodyJSONPath` / `BodyJSONArray`
over the raw body, and handlers decode their own request bodies again.
- Authz should not own request decoding; that ownership stays with the
handlers.

#### Additional Information

- Contributes to: https://github.com/SigNoz/keystone-pod/issues/37
2026-09-30 13:53:21 +00:00
Swapnil Nakade
d445b6c296 chore: bumping cloud integration agent version to v0.0.15 (#13023)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
Bumping the cloud integration agent's version to latest v0.0.15

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Contributes to https://github.com/SigNoz/keystone-pod/issues/101
2026-09-30 12:38:24 +00:00
Swapnil Nakade
fd8aaac300 feat: adding sync state in cloud integration (#12991)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
The agent only saw the current list of enabled regions, so it couldn’t
tell which regions had been removed. To find stacks to clean up, it
checked unrelated AWS regions, causing unnecessary calls and permission
errors. Sync state keeps track of regions sent to the agent and pending
removals until the agent acknowledges cleanup.

Please check
[comment](https://github.com/SigNoz/keystone-pod/issues/101#issuecomment-5832865898)
for approach

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Contributes to https://github.com/SigNoz/keystone-pod/issues/101

<!--Anything reviewers should keep in mind while reviewing -->
#### Additional Information
This PR should be merged before changes for cloud-integration repo.

<!--Please delete paragraphs that you did not use before submitting.-->
2026-09-30 11:39:46 +00:00
Naman Verma
e4cd8dbf10 chore: store v2 config for notification channels in db (#12984)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

1. add a config column to notification channels table where the channel
config goes without dealing with receiver at all. this helps in cleaning
up all round trip issues caused by dealing with receiver in the storage
layer. v2 apis treat receiver as a side effect now
1a. for applicable fields, defaults are filled in create/update api if
fields are omitted
1b. explicit [] and {} are no longer dropped, and omitted [] and {} are
returned as explicit null
2. add integration tests for all notification channel round trip issues
3. code cleanup of v2 channels types 
4. migration to fill the config column from receiver column, which logs
results like dashboards migration did
4a. it fails for receivers that cannot be modeled in v2. repair api can
be used for them
4b. for types that v2 supports, any fields that v1 supports but v2
doesn't, this migration drops those fields
5. make v1 API reject anything that v2 apis do not support, and also
fill the new config column added
6. add integration tests for v1<>v2 interaction to ensure that alert
manager doesn't break because of new changes added

What breaks/changes for v1:
1. types that v2 does not support can no longer be created
2. channels with multiple receivers cannot be created
3. channels with fields that v2 does not support cannot be created
4. existing channels of types that v2 does not support can no longer be
edited via v1 API. They can be deleted though. Also, they keep on
sending notifications as before (sigh).

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR

Closes https://github.com/SigNoz/pulse-pod/issues/376
Closes https://github.com/SigNoz/pulse-pod/issues/378
2026-09-30 11:30:33 +00:00
praneeth-signoz
81d024dfc8 chore(channel-receivers): relax channel validations (#13008)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

- Relax all the strict validations like https, host name...for all the
channels. And why this is needed ?

1. Channel URLs were pinned to the vendor's own host —
`chat.googleapis.com`, `*.atlassian.net`— which blocked deployments that
send notifications through a proxy or relay.
2. Provider's contract is not ours to hardcode — so we check the field
is there and let the provider reject what it doesn't accept

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR

closes https://github.com/SigNoz/pulse-pod/issues/374
2026-09-30 10:20:41 +00:00
Vikrant Gupta
8dba9a13ea fix(authz): read every body-derived resource id from the decoded request (#13015)
#### Description

- Follows #13014. Moves the remaining body-derived resource ids (gateway
limits, zeus hosts, cloud integration check-ins, auth domains, query
range) off gjson and onto the decoded request, with the handlers reading
the same value. Part of SigNoz/keystone-pod#37.
- Removes `BodyJSONPath`, `BodyJSONArray`, and
`ExtractorContext.RequestBody`.

#### Issues closed by this PR 

- Closes: https://github.com/SigNoz/keystone-pod/issues/37
2026-09-30 09:34:32 +00:00
Vikrant Gupta
8d80f98710 fix(authz): decode the request body once in the resource middleware (#13014)
Some checks failed
Release Drafter / update_release_draft (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
#### Description

- The resource middleware now decodes the body once into the route's
declared `OpenAPIDef.Request` type, rejects a malformed body before any
check, and carries the decoded value on `ExtractorContext.Body`.
`BodyField` / `BodyFields` read ids off that value, and handlers read
the same value via `coretypes.BodyFromContext`.
- `handler.Handler` exposes `Request()`, and `handler.New` panics when a
route with resource defs declares a non-pointer request, since the
middleware instantiates it.
- Only `POST /api/v1/service_account_roles` is wired to the new
extractors in this PR to keep the review small. The remaining body
routes still use the gjson extractors and decode again in their
handlers.

#### Issues closed by this PR
- Contributes to: https://github.com/SigNoz/keystone-pod/issues/37
2026-09-29 21:32:25 +00:00
Aditya Singh
adfcebf855 feat(explorer): create alert and add to dashboard actions in the explorer views (#12981)
#### Description
- Create alert and Add to dashboard now live in the view that owns the
row.. logs list row, logs / traces time series and table headers, traces
list and trace rows, metrics per chart. Same line as download
everywhere. First slice of pulling the actions out of the bottom bar,
the bar keeps its own two till it goes so they show twice for now.
- new `ExplorerActions` renders the pair.. the view hands over its
export query, same query the bar gets so nothing changes in what reaches
the alert / dashboard. `TimeSeriesView` got a `headerActions` slot for
it.
- metrics one chart per query: each chart carries its own alert /
dashboard / download for that chart's query, icon only in the split
layout. no per query picker needed.
- alert shaping is source agnostic now.. every noop becomes count and
list / trace panels drop `orderBy` whatever the source. bar only checked
the first query and only stripped for logs. neutral today, traces
already sends `orderBy: []` for those views.
- `DownloadOptionsMenu` moved to the design system buttons.. list
download was the antd primary tinted icon, did not match the rest of the
row.
- llm explorer and meter untouched.. llm gets it later, meter never had
these buttons in the bar.

#### Issues closed by this PR

Closes https://github.com/SigNoz/events-pod/issues/56




https://github.com/user-attachments/assets/a3b7f08c-2c62-4243-8cd7-4dd25cb315fd



#### Additional Information
- no flag.. buttons are live from merge, the bar stays till saved views
lands in the sidebar.
- logs controls row is list only now.. everything in it was list gated
once the buttons moved into the view headers, it was an empty strip on
time series / table.
- analytics is one generic event per action with `sourcepage` in the
payload, not the per explorer names the bar used.
- verified bar == button (alert url and dashboard link) in the browser
for all logs / traces views and metrics single, split and unsplit. tests
pin the query pushed to the url per view.
2026-09-29 16:43:05 +00:00
Swapnil Nakade
254758942e fix: using allLogs categoryGroups for azure container apps (#13013)
#### Description

- The Container Apps logs pipeline failed because the definition passed
log category names (`ContainerAppConsoleLogs`, `ContainerAppSystemLogs`)
as `categoryGroups`. Azure accepts only `allLogs` or `audit` there, so
it rejected the diagnostic setting.
- Switched to `allLogs`, matching the other Azure services. The agent
picks this up on its next config sync, so no agent release is needed.

#### Issues closed by this PR

Closes SigNoz/keystone-pod#45

#### Additional Information
- Not tested on live Azure. Microsoft's built-in policy for
`Microsoft.App/managedEnvironments` sends the same `allLogs` setting to
Event Hub.
2026-09-29 14:24:00 +00:00
Aditya Singh
8a5d98f467 chore(logs): remove the old log details drawer (#12938)
Some checks failed
build-staging / js-build (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
#### Description

- `useIsLogDetailsV2` was a route test, not a feature flag.. v2 rendered
on the logs explorer, infra monitoring and dashboards and everything
else fell back to v1. made v2 the only drawer, so the pipelines preview
gets it too. that's the one behaviour change here.
- deleted the v1 code that leaves behind.. the attribute table and its
json processing, the two HOCs, the `ActionItem` component and the
separate JSON tab. `Overview` is down to its DataViewer path, which also
drops monaco from the logs bundle. `DataType` and the two props types
move out first since MetricsExplorer and infra monitoring read them.
- dropped the standalone `/logs/logs-explorer/live` route. nothing
navigated to it, the time picker's Live option is in-page state on the
explorer. the components stay, that in-page mode still renders them.

#### Issues closed by this PR

Part of https://github.com/SigNoz/engineering-pod/issues/5933

#### Additional Information

- `onAddToQuery` stays for now. it is v1-only inside the drawer but five
call sites still thread it through, a couple of them doubling it as
`onClickActionItem`.. untangling that is a refactor rather than a
deletion.
- `useLogAttributeActions` gated group-by and replace-filter on "old
explorer or live logs". with both routes gone the guard is always false,
so it collapses.
2026-09-29 13:30:34 +00:00
praneeth-signoz
47dd1fabf3 chore(channel-specs): Move channel specs to separate files (#12989)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

- Moved channel specs to separate files under alert manager types
- Channel receivers are also moved the same file

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Closes
https://github.com/orgs/SigNoz/projects/34/views/26?pane=issue&itemId=252814150&issue=SigNoz%7Cpulse-pod%7C374
2026-09-28 17:44:35 +00:00
Vikrant Gupta
270988fb48 fix(tokenizer): persist last_observed_at on postgres (#12982)
#### Description

- The flush CTE rendered `last_observed_at` as an untyped literal, which
postgres resolves to `text` and refuses to assign to the `timestamptz`
column. The column never populated, so the idle expiry never applied.
- Build the CTE from the token model with only `id`, `last_observed_at`
and `updated_at`, so bun casts per dialect and no token secrets land in
the statement.
- Flush now applies cached times through `Token.UpdateLastObservedAt`,
which also skips rows with a newer stored value.
- Integration test in `passwordauthn` runs with a short GC interval and
asserts the column populates on both sql stores.
2026-09-28 14:23:01 +00:00
Naman Verma
39badeb591 fix: remove rules types package import from migration #049 (#12998)
Some checks failed
Release Drafter / update_release_draft (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

Migration package ideally should have have things from types package
imported. Given that rules v1->v2 will (most probably) update/remove
some of the types, such as removing `PreferredChannels` from
`PostableRule`, better not to have this type imported in migrations
package.

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR

Part of https://github.com/SigNoz/pulse-pod/issues/225
2026-09-28 11:39:07 +00:00
Nityananda Gohain
ec05bfe755 fix: empty patterns in pricing are rejected (#12995)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
Empty patterns were not rejected because of which corrupt config was
created, rejecting them at the handler layer.

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Part of https://github.com/SigNoz/nerve-pod/issues/282
2026-09-28 08:09:38 +00:00
Aditya Singh
ed1bf7ab89 fix(bottom-strip): size pages from the layout instead of the viewport (#12940)
Some checks failed
build-staging / prepare (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
#### Description

- pages that hardcoded `100vh` minus a guess at what sits above them
came out taller
than the pane they live in, which showed up as scroll that should not be
there. they
  now take what the layout gives them.
- most of the `100vh` in the app turned out to be harmless.. either
flex-shrink absorbs
it or the pane scrolls anyway. those are left alone, only the ones with
a real symptom
  are changed here.
- alert rules and triggered alerts also needed the AlertList tabs chain
to hand height
  down, that page uses antd `Tabs` directly instead of `RouteTab`.
- licenses, status and support pages had `max-height: 100vh` with
`overflow: hidden` and
no inner scroller, so anything past a viewport was clipped with no way
to reach it.
  removed the cap on all three.

#### Issues closed by this PR

Part of https://github.com/SigNoz/engineering-pod/issues/6074


#### Screenshots/ Screen recording

Home page


https://github.com/user-attachments/assets/8ba3e3c9-1959-4393-b503-ddf579e9d139

Without bottom strip


https://github.com/user-attachments/assets/2ee08181-710a-4c34-a4e7-893c4a320453



Status page

<img width="1728" height="1000" alt="status"
src="https://github.com/user-attachments/assets/f44ec7d7-4ee0-4866-9a90-fe25622fe25b"
/>

Without bottom strip

<img width="1728" height="997" alt="status2"
src="https://github.com/user-attachments/assets/be57dce6-65ca-4450-8f0d-0337625a1d64"
/>

Alert rules


https://github.com/user-attachments/assets/7cc25f56-54e4-4489-bdb4-453409151bac

Triggered alerts


https://github.com/user-attachments/assets/2d8e1885-7cad-4659-90f6-59960f4afce8

Without bottom strip



https://github.com/user-attachments/assets/5247f6c0-3675-4910-b1e4-4076bf93c16e



Support
<img width="1728" height="997" alt="support"
src="https://github.com/user-attachments/assets/c2b3c0b2-2abd-4538-bb52-2660e75817b3"
/>

Trace funnel



https://github.com/user-attachments/assets/c4872135-3cb5-4348-b6c6-2d3e4dabdc1b

Without bottom strip


https://github.com/user-attachments/assets/aef94d5d-02e5-4154-995b-76819d55c2d8


Trace details



https://github.com/user-attachments/assets/24d701b0-296f-4fb4-ba9d-615a47b33285

Without bottom strip


https://github.com/user-attachments/assets/23083f20-67bf-4b06-aaec-aba390a6f594



#### Additional Information

- every page here was checked on screen before and after. the ones left
untouched
(infra hosts/k8s, traces + llm explorer list views, llm settings tables,
the k8s logs
  drawer) were checked too and are fine.
2026-09-25 15:14:44 +00:00
Aditya Singh
6e979c8318 feat(bottom-strip): add the layout shell behind a feature flag (#12936)
#### Description

- adds the bottom strip to the app layout behind a localStorage flag.
shows the build
version on the left for now.. right side actions and the per page count
come in the
  next tickets.
- `.app-content` is a column flex now and `LayoutContent` takes the
height left over
instead of `height: 100%`, so the strip has a stable box to sit under.
this is the
  only bit not behind the flag.
- fixed bottom elements read `--bottom-strip-height`. the var only
exists while the
strip is mounted, so with the flag off everything falls back to where it
is today.
- hides nothing. each later ticket hides the piece it replaces.

#### Issues closed by this PR

Part of https://github.com/SigNoz/engineering-pod/issues/6074

<img width="3084" height="1566" alt="image"
src="https://github.com/user-attachments/assets/b1821fda-5c33-40e7-926a-5d91fedb797e"
/>


#### Additional Information

- pages that still hardcode `100vh` (infra hosts/k8s, trace details,
traces and llm
list views) push the strip off screen. that is the next PR on this
ticket.
- pylon chat window offset is not here.. needs a pylon enabled tenant to
verify so it
  goes with the right side actions ticket.
2026-09-25 12:04:21 +00:00
praneeth-signoz
3b6becff7a chore(tests): split alerts test suite as per domain boundaries (#12983)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
Segregated alert-related test suite in to alert manager and ruler as per
their domain boundaries.

---------

Co-authored-by: Praneeth Lingam <praneethlingam@Ollys-MacBook-Pro.local>
2026-09-25 07:30:53 +00:00
Aditya Singh
ab715533b9 feat(saved-views): read saved views from the v2 api on home, noz and column sync (#12970)
#### Description
- moved the home saved views widget, noz open saved view and the saved
view column/format sync (`usePreferenceSync`) from
`/api/v1/explorer/views` to `/api/v2/saved_views`.. generated client and
DTOs used as is, no adapter. labels read `spec.displayName`, columns
`spec.selectedFields`, formatting `spec.display`.
- small `container/SavedViews/utils.ts` for the two things every v2
consumer needs.. shaping the v2 spec for the existing v5 reverse mapper,
and the `DataSource` → api source map. rest of the saved views hooks
come with the sidebar work.
- explorer bottom bar, the `/saved-views` pages and `ExplorerCard` stay
on v1 on purpose.. they get deleted with the bottom strip work, no point
migrating something with a death date. v1 and v2 run in parallel till
then.
- home widget drops the tags badges (nothing ever wrote tags) and the
extra lookup on click. functionalities kept same.

#### Issues closed by this PR

Closes https://github.com/SigNoz/engineering-pod/issues/6095
Part of https://github.com/SigNoz/engineering-pod/issues/5918

#### Additional Information
- traces view with no saved columns now falls back to the typed
`defaultTraceSelectedColumns` (what the loader uses) instead of the
string list from `ListView/configs`.. old one was strings in a
`TelemetryFieldKey[]` hidden by `JSON.parse`.
- `viewName` is still written to the url on open so the old bar shows
the view as selected.. goes away when the bar does.
- noz open view could not be tested locally, covered by unit tests only.
- home storybook mocks regenerated for the v2 endpoint.
2026-09-25 04:37:54 +00:00
Vinicius Lourenço
8e2da68fc6 test(api-monitoring): mock /fields/keys for quick filters settings stories (#12980)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

Add missing mocks for stories on api monitoring after
https://github.com/SigNoz/signoz/pull/12968
2026-09-24 14:24:56 +00:00
Nityananda Gohain
8371a70801 perf(querybuilder): compare materialized exists columns explicitly (#12978)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

Materialized existence checks now render as an explicit comparison
instead of a bare bool column. Results are unchanged; only skip-index
usage improves.

  ```sql
  -- before
  WHERE `attribute_string_gen_ai$$request$$model_exists`
     OR `attribute_string_gen_ai$$provider$$name` = 'anthropic'

  -- after
  WHERE `attribute_string_gen_ai$$request$$model_exists` = true
     OR `attribute_string_gen_ai$$provider$$name` = 'anthropic'
  ```

  <details>
<summary>EXPLAIN indexes = 1 (trace-matching phase, 123M
spans)</summary>

  Before: bare `col_exists`
  ```
  Name: idx_gen_ai_span_exists
  Granules: 15193/15193
  Name: <Combined skip indexes>
  Granules: 15193/15193
  ```

  After: `col_exists = true`
  ```
  Name: idx_gen_ai_span_exists
  Granules: 15193/15193
  Name: <Combined skip indexes>
  Granules: 488/15193
  ```
  </details>

----
- ClickHouse can use a different skip index for each side of an OR and
union the results, but it can't when one side is a bare bool column.
Comparing with `= true` fixes that.
- This shape comes from the AI explorer trace list with a span filter: a
trace qualifies when it has a gen_ai span *and* a span matching the
filter (possibly different spans), so the WHERE is `(gen_ai gate) OR
<filter>` followed by a HAVING.
- Needs the gen_ai materialized columns and `idx_gen_ai_span_exists`
from SigNoz/signoz-otel-collector#929; without them there's no index to
combine.

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Part of https://github.com/SigNoz/nerve-pod/issues/282

<!--Anything reviewers should keep in mind while reviewing -->
#### Additional Information
- Benchmarked the AI trace list filtered on `gen_ai.provider.name`
against a 123M-span table (direct I/O, caches off): from ~30M spans in
the window, latency drops 16–17% and CPU 35–38%, with ~25x fewer rows
read (123M spans: 510 → 427 ms, 1.5 → 0.9 sCPU). The saved time and CPU
keep growing with span count, so larger windows save more.
- Single-condition filters (`gen_ai.request.model EXISTS` in dashboard
panels, the AND-ed gate in AI aggregations) already pruned with the bare
form; no change there.
2026-09-24 13:15:32 +00:00
Naman Verma
9d9b0e194a chore: add ability to mark API stability as beta/alpha (#12957)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

If an API that is already deployed is currently being tested via UI
integration or any other means, we should mark such APIs as under
development so that other external clients know that these APIs aren't
fully stable. This is especially required if we are working on v2
versions of APIs for any entity.

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR

Part of https://github.com/SigNoz/pulse-pod/issues/369

<!--Anything reviewers should keep in mind while reviewing -->
#### Additional Information

This PR adds the development flag on the v2 notification channel APIs

<!--Please delete paragraphs that you did not use before submitting.-->
2026-09-24 12:19:02 +00:00
Aditya Singh
2a7f4fd603 test(quick-filters): add settings-with-banner stories for every filters page (#12968)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
#### Description

- the quick filters settings panel is sized from the filters pane, not
the viewport. the case that broke was a banner shortening the layout,
which pushed the Save changes footer off screen.. so every page with
settings now has a story for exactly that.
- each new story opens settings and removes a filter first, that is what
puts the footer on screen. same play sequence as the existing dirty
story so the two are comparable side by side.
- external apis and cost meter had no settings story at all, they get
the plain and dirty ones too. cost meter's settings live on the explorer
tab so its stories start there.
- `banner` is already a global control on the app shell mocks, so no
mock changes anywhere.. the stories just turn it on.

#### Issues closed by this PR

Part of https://github.com/SigNoz/engineering-pod/issues/5978

#### Additional Information

- covers logs, traces, exceptions, ai observability, external apis and
cost meter.
- the play functions have not been run here, playwright's browser is not
installed on my machine. external apis and cost meter are the ones worth
checking first since they never had a settings story.
- cc. @H4ad
2026-09-24 08:54:54 +00:00
Nikhil Mantri
ee35fc351f feat(alerts): New list API for alert rules (powers filters, sorting, pagination) (#12780)
#### Description

- New `GET /api/v3/rules` list API for alert rules: filter query DSL,
`states` filter, sort, and offset pagination (design discussion:
SigNoz/pulse-pod#324).
- Based on #12806, which extracts the shared list filter SQL compiler;
this PR adds only the rules key-policy resolver
(`sqlrulestore/filterquery_resolver.go`) on top of it.
- Rule state lives only in the rule manager's memory, so state
filtering, total, sort and pagination run in code after the SQL fetch;
total always equals what is pageable.
- Sorting is deterministic on ties: equal rows break on name then id,
always ascending, so pages never overlap or drop rows between requests.
- Response rows carry only list-page fields, deliberately excluding
`condition`, `annotations` and `notificationSettings`. The envelope also
returns the org's distinct label pairs and the reserved filter keys for
suggestions.
- Also guards previously unlocked reads of the rules map
(`ListRuleStates`, `GetRule`, `TriggeredAlerts`).

**Filter keys and operators**

| Key | Operators | Notes |
|---|---|---|
| `name`, `created_by`, `updated_by` | `=`, `!=`, `CONTAINS`, `LIKE`,
`ILIKE`, `IN` and negations | string search |
| `labels.<key>` | string operators plus `EXISTS`, `NOT EXISTS` |
missing label evaluates as empty string; keys are case-sensitive |
| `severity` | same as `labels.<key>` | alias for `labels.severity` |
| `created_at`, `updated_at` | `=`, `!=`, `<`, `<=`, `>`, `>=`,
`BETWEEN`, `NOT BETWEEN` | quoted RFC3339 values |
| `alert_type` | `=`, `!=`, `IN`, `NOT IN` | enum: `METRIC_BASED_ALERT`,
`TRACES_BASED_ALERT`, `LOGS_BASED_ALERT`, `EXCEPTIONS_BASED_ALERT` |
| `rule_type` | `=`, `!=`, `IN`, `NOT IN` | enum: `threshold_rule`,
`promql_rule`, `anomaly_rule` |

- A bare word is free text: a case-insensitive substring match over
name, description and labels.
- `state` is not a DSL key. It is the repeated `states=` query param:
`firing`, `pending`, `recovering`, `inactive`, `nodata`, `disabled`.
- An unknown key or `REGEXP` returns a 400.

#### Issues closed by this PR

Closes SigNoz/pulse-pod#226

#### Additional Information

- A missing label evaluates as the empty string for every value
operator, one uniform rule instead of the querier's per-operator split
([`AddDefaultExistsFilter`](https://github.com/SigNoz/signoz/blob/e0da06f76d/pkg/types/querybuildertypes/querybuildertypesv5/builder_elements.go#L160));
presence is asked with `EXISTS` / `NOT EXISTS`.
- Integration tests
(`tests/integration/tests/alerts/06_list_rules_v3.py`) cover filters,
states, sorting, pagination, totals and the error contract, run against
both sqlite and postgres.
- Found while testing: the stock `create_notification_channel` fixture
teardown silently fails and leaks channels; follow-up fix needed.

---------

Co-authored-by: Naman Verma <naman.verma@signoz.io>
2026-09-24 07:16:12 +00:00
Aditya Singh
720810d424 fix(quick-filters): filter sidebar scrolls the whole page (#12915)
#### Description

- Quick filters sidebar scrolls the whole page instead of scrolling
itself, so the top nav, module tabs and the table scroll away with it.
Happens on traces, llm observability, api monitoring, exceptions and
meter.. logs is the only page behaving today.
- Cause is antd Tabs.. it never passes height down to the tab pane, and
every module page wrapped `RouteTab` in a plain div, so the page inside
was never bounded. Pages that wanted their own scroll each kept a
private copy of the same `.ant-tabs` override, traces and meter never
had one.
- `RouteTab` now owns the height chain and scrolls each pane's content,
so the tab bar stays put on every tabbed page. Module pages pass their
class to `RouteTab` instead of wrapping it, and the six copied overrides
are gone.
- New `QuickFiltersLayout` gives the explorer pages a bounded two pane
layout.. 280px sidebar that scrolls itself, content that scrolls itself.
Traces, llm, api monitoring, exceptions and meter are on it now.
- Logs and infra are unchanged here, both move to the shared layout in
follow ups.
- Also drops the per page viewport heights on the quick filter settings
drawer.. with the pane bounded, `height: 100%` is enough, and the
save/discard footer stays reachable with the banners on.

#### Issues closed by this PR

Closes https://github.com/SigNoz/engineering-pod/issues/6088
Closes https://github.com/SigNoz/engineering-pod/issues/6104
Part of https://github.com/SigNoz/engineering-pod/issues/5946


#### Screenshots/ recordings



Banner fix [BEFORE]


https://github.com/user-attachments/assets/44bc98f8-7ce9-45a7-9c45-e86648c40f69

Banner fix [AFTER]



https://github.com/user-attachments/assets/c1140a2a-f00e-4685-87e4-4a0f5d72623a



Quick Filter Whole Page scroll Fix
[BEFORE]



https://github.com/user-attachments/assets/07bd42a0-db80-4d14-bf8a-bcea01fb70b1




[AFTER]




https://github.com/user-attachments/assets/7bd14951-2595-43cd-8eab-dcb57cdce011





#### Additional Information

- The `RouteTab` change touches every tabbed page, not just the quick
filter ones. Checked traces, logs, exceptions, api monitoring, meter,
infra hosts, metrics summary, funnels, saved views, pipelines, mq, logs
settings, settings (org + members) and alert details, with the trial
banner on and off. llm observability is feature gated on my instance so
it is not checked in the browser.
- Behaviour change to call out: top nav and tab bar are now fixed on all
tabbed pages. Pages that mount `RouteTab` inside a block wrapper (alert
details, the exceptions inner tabs) are unaffected, the scroller is
inert there.
- Sidebar is 280px everywhere now, was a 260/280 mix.
- Pane content that needs a bounded box should size with `height:
100%`.. `flex: 1` does nothing inside the scroller viewport (documented
on `RouteTab`).
- cc. @H4ad
2026-09-24 06:01:23 +00:00
Ashwin Bhatkal
7424885a14 chore(codeowners): add alert code ownership to pulse-frontend (#12977)
#### Description

Paths that belong to alerts and notification channels added to
CODEOWNERS

- `container/FormAlertChannels/`
- `hooks/notificationChannels/`
- `container/RoutingPolicies/`
- `components/AlertBreadcrumb/`
- `container/EditRules/`
- `components/AlertDetailsFilters/`
- `components/Alerts/`
- `hooks/routingPolicies/`
- `types/api/alerts/`
- `providers/Alert.tsx`
- `constants/alerts.ts`

All go to `@SigNoz/pulse-frontend`, matching the rest of those blocks.
2026-09-24 04:29:31 +00:00
Abhi kumar
2c09fedde1 fix(dashboard): panel UX fixes — bar gap, tooltip date, palette, legend search (#12959)
Some checks failed
build-staging / staging (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
#### Description

Four independent panel-UX fixes from the dashboards epic, one commit
each.

- **Bar gap.** The gap between bars was wider than half a bar. The bar
width factor goes 0.6 → 0.85, leaving just enough to separate them.
Shared by bar and histogram panels.
- **Tooltip date.** A tooltip on a point from today now shows only the
time; the date still appears for any other day.
- **Red in the palette.** Roughly one series in six was being coloured
red — 18 of 117 entries in `chartcolors`, 15 of 74 in `lightModeColor` —
which spends the one colour that should mean "something is wrong". Each
red entry is rotated onto a free hue with its original lightness
preserved and saturation clamped, and its key renamed to match. Entries
are replaced, never removed: `generateColor` indexes by `hash %
Object.keys(...).length`, so changing the count would recolour every
existing chart. Pinks and magentas are left alone.
- **Bottom legend search.** A bottom legend that overflows the rows the
panel reserves for it now gets a search box and a "Showing N of M
series" readout, on a single row above the series. Whether that row
exists is the chart layout's call, since it is the layout that reserves
the height — a row nobody reserved would eat a row of series. One
`LegendToolbar` serves both placements, with position driving the layout
only, so the right column is unchanged. The readout counts the rows the
search left listed, against the whole series set.

#### Issues closed by this PR

Closes https://github.com/SigNoz/engineering-pod/issues/3959
Closes https://github.com/SigNoz/engineering-pod/issues/3967
Closes https://github.com/SigNoz/engineering-pod/issues/3976
Closes https://github.com/SigNoz/engineering-pod/issues/3977

#### Additional Information

- The palette replacements are computed (even spread across the non-red
arc), not hand-designed — worth a visual pass across light and dark
before merging.
- Two tests asserted a palette hex for a given series label and are
updated to the new value.
- The search row's 24px height and 4px gap are pinned as
`LEGEND_TOOLBAR_HEIGHT` / `LEGEND_TOOLBAR_GAP` beside the existing row
constants; they must match the stylesheet or the reserved rectangle
clips a row.

<img width="1611" height="634" alt="image"
src="https://github.com/user-attachments/assets/2c21a458-e142-4e4f-baff-5bbcbb072140"
/>
2026-09-23 18:58:55 +00:00
Nityananda Gohain
5a1be60745 fix(ai-o11y): scope overview dashboard to gen_ai spans and move message attributes (#12967)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
cacheci / tests (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
- Top span names and Cost by service use `builder_ai_query`, so non-AI
spans no longer show up.
- LLM cost/token panels filter on `gen_ai.request.model EXISTS`; with
variables on "All" they scanned every span.
- Default span mappers now move (not copy) vendor message keys into
`gen_ai.input.messages` / `gen_ai.output.messages`, as documented.
- Bumped versions: dashboard to 3, `gen_ai.llm` mapper to 3,
`gen_ai.agent` mapper to 2.

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Part of https://github.com/SigNoz/engineering-pod/issues/6107
2026-09-23 14:56:04 +00:00
Gaurav Tewari
cad93a8063 chore: remove beta tag class (#12965)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

Removed beta tag class from AI o11y . 
since it remove margin and breaks alignment. don't see any use of it .
it also shifts the pin icon a bit

before - 
<img width="149" height="160" alt="image"
src="https://github.com/user-attachments/assets/26770802-b5b0-452b-b66a-fecda0d49c38"
/>
 
 
<img width="331" height="152" alt="image"
src="https://github.com/user-attachments/assets/fba73ebe-2655-4de5-8488-eb6bb0bfebca"
/>


 now - 
 
<img width="158" height="192" alt="image"
src="https://github.com/user-attachments/assets/fb0ca483-e8db-4ff0-bb36-e0186c2e9458"
/>

<img width="272" height="63" alt="image"
src="https://github.com/user-attachments/assets/68486c3f-a704-4077-82e5-089452abf773"
/>

 



it was added for long text .
https://github.com/SigNoz/signoz/pull/5801/changes#r1736497688
for now in side nav we don't have any long text. and maybe we could have
handled this better
 

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR

<!--If applicable, include screenshots or screen recordings that clearly
show the behavior before the change and the result after the change. -->
#### Screenshots / Screen Recordings

<!--Anything reviewers should keep in mind while reviewing -->
#### Additional Information

<!--Please delete paragraphs that you did not use before submitting.-->

Co-authored-by: Gaurav Tewari <tewarig@users.noreply.github.com>
2026-09-23 11:45:33 +00:00
Abhi kumar
aed096bf27 refactor(query-builder): compose the panel-type field map instead of listing it (#12781)
#### Description

`panelTypeDataSourceFormValuesMap` — the map deciding which builder
fields survive a panel-type switch — spelled out all 21 panel-type ×
data-source combinations as literal field lists, 435 lines of them.

They reduce to seven distinct sets:

- logs and traces carry **identical** fields for every panel type
- metrics adds its two aggregation steps (`timeAggregation`,
`spaceAggregation`)
- every panel type is one of four query shapes: series, scalar table,
single value, raw rows

Much of the apparent variation was ordering noise — a bar chart and a
table on logs have the *same* field set, listed in a different order.

Composed from those rules it's 84 lines, and the policy is legible at a
glance: charts, table and pie share a surface; table and pie differ only
by `reduceTo` on metrics; a single value has nothing to group, limit or
order; raw rows carry no aggregation. Two asymmetries that were buried
in the literals are now called out where they're decided, rather than
silently reproduced.

**No behaviour change.** Adding a panel type becomes one line — "which
shape is it?"

#### Additional Information

- Equivalence was checked cell by cell against the previous literal
table before it was removed; all 21 cells matched as sets. The old table
is in git history at `main:frontend/src/lib/query/panelQuery.ts` if you
want to re-run that comparison.
- The specs pin the **rules**, not the values, so they fail when a rule
changes — the moment to stop and decide — rather than whenever a field
moves. Two are worth reading:
- *"gives bar / histogram / table / pie the same non-metrics fields as a
time series"* states the hazard composing introduces: the aggregating
types share one field list, so an edit meant for charts reaches table
and pie too. A failure there names the reason.
- *"gives every cell its own array instance"* — the `QueryBuilder`
provider does `propsRequired?.push('dataSource')` on the list it reads
from this map, so cells sharing an instance would leak fields into each
other. My first draft shared one array across 10 cells; this test is
what guards it.
- Order is not asserted anywhere: `handleQueryChange` and the provider
both assign each field independently via `set()`, so sequence carries no
meaning.
- Three consumers, all exercised: `handleQueryChange` (dashboards v2's
kind switcher and V1's `PanelTypeSelector`) and the shared
`QueryBuilder` provider every explorer uses. Verified with `tsgo`,
`oxlint`, and the `lib` / `providers` / `WidgetCard` / Logs+Traces
explorer / `DashboardPage` suites: 243 suites, 2056 tests.
- Pre-existing and deliberately left alone: that `push` mutates module
state, so the arrays grow by one `'dataSource'` entry on every
query-builder change. Harmless today only because the assignment is
idempotent; `[...propsRequired, 'dataSource']` would fix it, but that's
the provider's bug, not this map's.
2026-09-23 11:24:51 +00:00
Nityananda Gohain
6b66ab64c8 fix: add ai-o11y quick filter migration (#12964)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
Added migration to update old instances where quick filters for ai-o11y
is not present.

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
part of https://github.com/SigNoz/engineering-pod/issues/6107
2026-09-23 11:15:42 +00:00
Naman Verma
362d3a4fdf fix: backfill notification channel tuples (#12960)
Some checks failed
build-staging / prepare (push) Has been cancelled
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
cacheci / tests (push) Has been cancelled
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

Same migration logic as number 128. Needed for enterprise servers as
these tuples decide whether a role may create, list, read, update or
delete channels at all. An existing org with zero channels still needs
them, otherwise its admin can't create the first one or even list the
empty page.
2026-09-23 09:48:11 +00:00
Jugal Kishore
ff80758e1c feat(onboarding): add Cursor, Cline, vLLM, SGLang, Karpenter datasources (#12944)
#### Description

- Adds 20 data sources to the onboarding picker: Cursor, Antigravity
CLI, Qwen Code, DeepSeek Harness, Meta Muse Code, Meta Muse Spark,
OpenAI Agents SDK, Cline, E2B Sandbox, Daytona Sandbox, Vercel Sandbox,
Modal, vLLM, SGLang, Karpenter, Podman, EMQX, AWS RDS Aurora, GCP Cloud
Storage, and AWS Lambda MicroVMs.
- Go now asks for an instrumentation method (SDK / compile-time `otelc`
/ eBPF) before the environment question, so the new zero-code guides are
reachable. The card links to the new comparison overview.
- The Lambda → Traces question now asks how the function is packaged
instead of which runtime it uses, and gains a Container Image option.
Layers do not attach to container images, so runtime alone did not pick
the right guide.
- GCP Cloud Storage points at `/integrations/gcp?service=cloudstorage`
rather than a doc, matching the Cloud SQL and Memorystore cards.
`cloudstorage` is a first-class cloud integration with its own
dashboard, so the in-app flow is the one users want.
- New logos: `antigravity`, `aurora`, `cline`, `cursor`, `daytona`,
`e2b`, `emqx`, `karpenter`, `meta`, `modal`, `podman`, `sglang`, `vllm`.
Qwen Code, OpenAI Agents SDK and Lambda MicroVMs reuse existing marks.
- Recolours 15 pre-existing logos that were pure white or near-black and
disappeared against one of the two card backgrounds (`--l2-background`
is `#121317` dark, `#F9F9FB` light): `anthropic-api-monitoring`,
`clickhouse`, `confluent-kafka`, `datadog`, `deno`, `document-load`,
`from-log-file`, `haystack`, `kafka`, `langchain`, `ollama`, `openai`,
`openrouter`, `vercel`, `zap`. Brand hue kept where the brand has one,
adjusted to clear 3:1 against both; black-or-white marks use a neutral
grey.

#### Issues closed by this PR

Closes SigNoz/signoz.io#4205
Closes SigNoz/signoz.io#4197
Closes SigNoz/signoz.io#4178
Closes SigNoz/signoz.io#4171
Closes SigNoz/signoz.io#4167
Closes SigNoz/signoz.io#4153
Closes SigNoz/signoz.io#4144
Closes SigNoz/signoz.io#4133
Closes SigNoz/signoz.io#4131
Closes SigNoz/signoz.io#4129
Closes SigNoz/signoz.io#4125
Closes SigNoz/signoz.io#4108
Closes SigNoz/signoz.io#4092
Closes SigNoz/signoz.io#4088
Closes SigNoz/signoz.io#4082
Closes SigNoz/signoz.io#4074
Closes SigNoz/signoz.io#4063
Closes SigNoz/signoz.io#4032
Closes SigNoz/signoz.io#4024
2026-09-23 07:54:02 +00:00
Vinicius Lourenço
f9d425bf5c fix(storybook): remove timing races from story tests (#12954)
#### Description

A few tweaks to improve the resiliency of the storybook tests under CI
stress.
2026-09-23 07:46:27 +00:00
Abhi kumar
7ce73f3470 fix(dashboard): don't re-run an errored panel query on scroll back into view (#12958)
#### Description

- Lazy-loaded panels toggle `enabled` on viewport visibility.
react-query treats a key with no data as stale regardless of
`staleTime`, so an errored panel refetched (with retries on 5xx) every
time it scrolled back into view.
- `useGetQueryRangeV5` now keeps an errored key enabled, so only a key
change (time, variables, query) or the Retry button re-runs it. A new
key still stays gated while off-screen.
- Adds a `useGetQueryRangeV5` test suite covering the gating paths.
2026-09-23 07:04:51 +00:00
Nityananda Gohain
5aca8b0d3c chore: remove ai-o11y ff (#12947)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
Remove ai-o11y FF and enable it by default

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Part of https://github.com/SigNoz/engineering-pod/issues/6107
2026-09-23 06:39:16 +00:00
Gaurav Tewari
f1c9e0f1d0 feat(llm-observability): add ai o11y analytics events (#12952)
#### Description

- Renames AI Observability explorer events from `Traces Explorer: *` to
`AI Observability Explorer: *`, so they no longer mix with the regular
Traces Explorer events.
- Adds page-visit events for Overview, Attribute Mapping and Model
Pricing.
- Adds action events: attribute mapping saved and test run; model cost
saved and deleted; unpriced model mapped.

---------

Co-authored-by: Gaurav Tewari <tewarig@users.noreply.github.com>
2026-09-23 05:05:06 +00:00
Gaurav Tewari
10c0af327b fix: failing e2e for llm (#12953)
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description

- Attribute-mapping e2e now adds a condition key when creating its
group.
- Since #12809 the backend rejects groups without conditions (`400
condition must list at least one attribute or resource substring`), so
the spec failed on save.

<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR

<!--If applicable, include screenshots or screen recordings that clearly
show the behavior before the change and the result after the change. -->
#### Screenshots / Screen Recordings

<!--Anything reviewers should keep in mind while reviewing -->
#### Additional Information

- Follow-up: we should add check on frontend as well for #12809 ( we
have already decided to add this later )

Co-authored-by: Gaurav Tewari <tewarig@users.noreply.github.com>
2026-09-23 04:43:36 +00:00
1241 changed files with 28975 additions and 18710 deletions

11
.github/CODEOWNERS vendored
View File

@@ -200,6 +200,15 @@ go.mod @therealpandey
/frontend/src/container/ListAlertRules/ @SigNoz/pulse-frontend
/frontend/src/container/TriggeredAlerts/ @SigNoz/pulse-frontend
/frontend/src/container/AnomalyAlertEvaluationView/ @SigNoz/pulse-frontend
/frontend/src/container/RoutingPolicies/ @SigNoz/pulse-frontend
/frontend/src/components/AlertBreadcrumb/ @SigNoz/pulse-frontend
/frontend/src/container/EditRules/ @SigNoz/pulse-frontend
/frontend/src/components/AlertDetailsFilters/ @SigNoz/pulse-frontend
/frontend/src/components/Alerts/ @SigNoz/pulse-frontend
/frontend/src/hooks/routingPolicies/ @SigNoz/pulse-frontend
/frontend/src/types/api/alerts/ @SigNoz/pulse-frontend
/frontend/src/providers/Alert.tsx @SigNoz/pulse-frontend
/frontend/src/constants/alerts.ts @SigNoz/pulse-frontend
## Notification Channels
/frontend/src/pages/ChannelsEdit/ @SigNoz/pulse-frontend
@@ -207,6 +216,8 @@ go.mod @therealpandey
/frontend/src/container/AllAlertChannels/ @SigNoz/pulse-frontend
/frontend/src/container/CreateAlertChannels/ @SigNoz/pulse-frontend
/frontend/src/container/EditAlertChannels/ @SigNoz/pulse-frontend
/frontend/src/container/FormAlertChannels/ @SigNoz/pulse-frontend
/frontend/src/hooks/notificationChannels/ @SigNoz/pulse-frontend
## OpenAPI Schema - Generated
/frontend/src/api/generated/services/ @therealpandey @vikrantgupta25 @srikanthccv

View File

@@ -38,7 +38,6 @@ jobs:
fail-fast: false
matrix:
suite:
- alerts
- alertmanager
- alertmanagerrotation
- basepath
@@ -64,6 +63,7 @@ jobs:
- querierauthz
- role
- rootuser
- ruler
- savedview
- semconvfamilies
- serviceaccount

File diff suppressed because it is too large Load Diff

View File

@@ -121,7 +121,7 @@ The pieces:
- **`ResourceDef`** — declares the resource, verb, audit category, how to extract the instance ID, and how to turn that ID into selectors. ID extractors live in [pkg/types/coretypes/extractor.go](/pkg/types/coretypes/extractor.go): `PathParam("id")`, `BodyJSONPath("data.id")`, `BodyJSONArray("ids")`, and `ResponseJSONPath("data.id")` for IDs only known after the handler runs (e.g. `create`).
- **`SecuritySchemes`** — advertises the required scope (`resource.Scope(verb)`, e.g. `serviceaccount:create`) in the OpenAPI spec.
For routes that link two resources, use `AttachDetachSiblingResourceDef` (both sides are authz-checked, e.g. attaching a role to a service account requires `attach` on **both** the service account and the role). For parent-child routes (e.g. creating an API key under a service account), both sides are checked too, but with different verbs: declare a `BasicResourceDef` checking the child with `create`/`delete`, alongside an `AttachDetachParentChildResourceDef` checking the parent with `attach`/`detach` (within that def the child is only recorded for audit) — see the `/api/v1/service_accounts/{id}/keys` route in [pkg/apiserver/signozapiserver/serviceaccount.go](/pkg/apiserver/signozapiserver/serviceaccount.go).
For routes that link two resources, use `AttachDetachSiblingResourceDef` (both sides are authz-checked, e.g. attaching a role to a service account requires `attach` on **both** the service account and the role). When a side's ids come from a list extractor (`BodyJSONArray` or a custom `ResourceIDsExtractor`) and that list resolves to nothing at request time, there is nothing to link: the def resolves to no resources, so no check runs and no audit event is emitted (e.g. inviting a user with an empty `userRoles`). A single-id side (`OneID`) always resolves to exactly one id and fails closed when it is empty. For parent-child routes (e.g. creating an API key under a service account), both sides are checked too, but with different verbs: declare a `BasicResourceDef` checking the child with `create`/`delete`, alongside an `AttachDetachParentChildResourceDef` checking the parent with `attach`/`detach` (within that def the child is only recorded for audit) — see the `/api/v1/service_accounts/{id}/keys` route in [pkg/apiserver/signozapiserver/serviceaccount.go](/pkg/apiserver/signozapiserver/serviceaccount.go).
Prefer `CheckResources` with a `ResourceDef` for anything resource-shaped. The older coarse gates `ViewAccess`/`EditAccess`/`AdminAccess` only check "does the caller hold one of these roles" and give up per-resource granularity; `OpenAccess` performs no authorization (authentication still applies); `CheckWithoutClaims` serves anonymous routes such as public dashboards.

View File

@@ -179,6 +179,7 @@ The `handler.New` function ties the HTTP handler to OpenAPI metadata via `OpenAP
- **SuccessStatusCode**: The HTTP status for successful responses (for example, `http.StatusOK`, `http.StatusCreated`, `http.StatusNoContent`).
- **ErrorStatusCodes**: Additional error status codes beyond the standard ones automatically added by `handler.New`.
- **SecuritySchemes**: Auth mechanisms and scopes required by the operation.
- **Stability**: Maturity marker (`handler.StabilityDevelopment`, `handler.StabilityAlpha`, `handler.StabilityBeta`, `handler.StabilityStable`, the OpenTelemetry Collector levels) emitted as the `x-signoz-stability` extension on every operation. Unset is emitted as `alpha`.
The generic handler:

View File

@@ -23,4 +23,3 @@ We **recommend** (almost enforce) reviewing these guides before contributing to
- [SQL](sql.md) - Database and SQL patterns
- [DSL Filtering to SQL](dslfilteringtosql.md) - Compiling the list filter DSL to relational-store WHERE clauses
- [Types](types.md) - Domain types, request/response bodies, and storage rows in `pkg/types/`
sdsdcdsc

View File

@@ -183,32 +183,52 @@ func (module *module) AgentCheckIn(ctx context.Context, orgID valuer.UUID, provi
return nil, errors.New(errors.TypeAlreadyExists, cloudintegrationtypes.ErrCodeCloudIntegrationAlreadyConnected, errMessage)
}
account, err := module.store.GetAccountByID(ctx, orgID, req.CloudIntegrationID, provider)
storableAccount, err := module.store.GetAccountByID(ctx, orgID, req.CloudIntegrationID, provider)
if err != nil {
return nil, err
}
account, err := cloudintegrationtypes.NewAccountFromStorable(storableAccount)
if err != nil {
return nil, err
}
syncState := account.NextSyncState(req.SyncedVersion)
// If account has been removed (disconnected), return a minimal response with empty integration config.
// The agent uses this response to clean up resources
if account.RemovedAt != nil {
// Heartbeat stays frozen after removal, only the sync state is updated.
if account.AgentReport != nil && syncState != nil {
account.UpdateSyncState(syncState)
storableAccount, err = cloudintegrationtypes.NewStorableCloudIntegration(account)
if err != nil {
return nil, err
}
err = module.store.UpdateAgentReport(ctx, storableAccount)
if err != nil {
return nil, err
}
}
return cloudintegrationtypes.NewAgentCheckInResponse(
req.ProviderAccountID,
account.ID.StringValue(),
new(cloudintegrationtypes.ProviderIntegrationConfig),
account.RemovedAt,
syncState,
), nil
}
// update account with cloud provider account id and agent report (heartbeat)
account.Update(&req.ProviderAccountID, cloudintegrationtypes.NewAgentReport(req.Data))
account.UpdateAgentReport(&req.ProviderAccountID, cloudintegrationtypes.NewAgentReport(req.Data, syncState))
err = module.store.UpdateAccount(ctx, account)
storableAccount, err = cloudintegrationtypes.NewStorableCloudIntegration(account)
if err != nil {
return nil, err
}
// Get account as domain object for config access (enabled regions, etc.)
domainAccount, err := cloudintegrationtypes.NewAccountFromStorable(account)
err = module.store.UpdateAgentReport(ctx, storableAccount)
if err != nil {
return nil, err
}
@@ -223,8 +243,7 @@ func (module *module) AgentCheckIn(ctx context.Context, orgID valuer.UUID, provi
return nil, err
}
// Delegate integration config building entirely to the provider module
integrationConfig, err := cloudProvider.BuildIntegrationConfig(ctx, domainAccount, storedServices)
integrationConfig, err := cloudProvider.BuildIntegrationConfig(ctx, account, storedServices)
if err != nil {
return nil, err
}
@@ -234,6 +253,7 @@ func (module *module) AgentCheckIn(ctx context.Context, orgID valuer.UUID, provi
account.ID.StringValue(),
integrationConfig,
account.RemovedAt,
syncState,
), nil
}

View File

@@ -80,15 +80,6 @@ func (ah *APIHandler) getFeatureFlags(w http.ResponseWriter, r *http.Request) {
Route: "",
})
aiObservability := ah.Signoz.Flagger.BooleanOrEmpty(ctx, flagger.FeatureEnableAIObservability, evalCtx)
featureSet = append(featureSet, &licensetypes.Feature{
Name: valuer.NewString(flagger.FeatureEnableAIObservability.String()),
Active: aiObservability,
Usage: 0,
UsageLimit: -1,
Route: "",
})
metricsReduction := ah.Signoz.Flagger.BooleanOrEmpty(ctx, flagger.FeatureEnableMetricsReduction, evalCtx)
featureSet = append(featureSet, &licensetypes.Feature{
Name: valuer.NewString(flagger.FeatureEnableMetricsReduction.String()),

View File

@@ -23,6 +23,15 @@ func (f *formatter) JSONExtractString(column, path string) []byte {
return append(f.TextToJsonColumn(column), ops...)
}
func (f *formatter) JSONExtractMapValue(column, mapField, key string) []byte {
sql := f.TextToJsonColumn(column)
sql = append(sql, "->"...)
sql = schema.Append(f.bunf, sql, mapField)
sql = append(sql, "->>"...)
sql = schema.Append(f.bunf, sql, key)
return sql
}
func (f *formatter) JSONType(column, path string) []byte {
var sql []byte
sql = append(sql, "jsonb_typeof("...)

View File

@@ -55,6 +55,67 @@ func TestJSONExtractString(t *testing.T) {
}
}
func TestJSONExtractMapValue(t *testing.T) {
tests := []struct {
name string
column string
mapField string
key string
expected string
}{
{
name: "PlainKey",
column: "data",
mapField: "labels",
key: "team",
expected: `"data"::jsonb->'labels'->>'team'`,
},
{
name: "DottedKey_OneMapEntry",
column: "data",
mapField: "labels",
key: "k8s.cluster",
expected: `"data"::jsonb->'labels'->>'k8s.cluster'`,
},
{
name: "SingleQuoteInKey_Doubled",
column: "data",
mapField: "labels",
key: "o'brien",
expected: `"data"::jsonb->'labels'->>'o''brien'`,
},
{
name: "BackslashInKey_Literal",
column: "data",
mapField: "labels",
key: `a\b`,
expected: `"data"::jsonb->'labels'->>'a\b'`,
},
{
name: "DoubleQuoteInKey_Literal",
column: "data",
mapField: "labels",
key: `a"b`,
expected: `"data"::jsonb->'labels'->>'a"b'`,
},
{
name: "QualifiedColumn",
column: "rule.data",
mapField: "labels",
key: "severity",
expected: `"rule"."data"::jsonb->'labels'->>'severity'`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
f := newFormatter(pgdialect.New())
got := string(f.JSONExtractMapValue(tt.column, tt.mapField, tt.key))
assert.Equal(t, tt.expected, got)
})
}
}
func TestJSONType(t *testing.T) {
tests := []struct {
name string

View File

@@ -70,3 +70,49 @@
Object.defineProperty(window, 'Date', { value: FrozenDate, writable: true });
})();
</script>
<script>
// Storybook has no microphone. Chromium's recognizer asks for one and for
// Google's speech service, and the `not-allowed` or `network` it reports makes
// the assistant hide its mic for the rest of the tab. This one starts
// listening at once and hears only what a story passes to `hear`.
(() => {
class StorySpeechRecognition extends EventTarget {
static listening = null;
lang = 'en-US';
continuous = false;
interimResults = false;
onstart = null;
onresult = null;
onerror = null;
onend = null;
start() {
StorySpeechRecognition.listening = this;
setTimeout(() => this.onstart?.());
}
stop() {
if (StorySpeechRecognition.listening === this) {
StorySpeechRecognition.listening = null;
}
setTimeout(() => this.onend?.());
}
abort() {
this.stop();
}
/** An interim result: the words so far, still listening. */
hear(transcript) {
const result = Object.assign([{ transcript, confidence: 1 }], {
isFinal: false,
});
this.onresult?.({ resultIndex: 0, results: [result] });
}
}
window.SpeechRecognition = StorySpeechRecognition;
window.webkitSpeechRecognition = StorySpeechRecognition;
})();
</script>

View File

@@ -1,6 +1,7 @@
import type { Preview } from '@storybook/react-vite';
import type { SetupWorker } from 'msw';
import { setupWorker } from 'msw';
import { configure } from 'storybook/test';
import { settleForCapture } from '../src/storybook/visual/settleForCapture';
import PageDocs from '../src/storybook/docs/PageDocs';
@@ -83,6 +84,10 @@ const translationsReady = i18n.loadNamespaces(
),
);
// testing-library's 1s default for `findBy*` and `waitFor` is shorter than a
// popup or a query takes to land on a loaded CI runner.
configure({ asyncUtilTimeout: 10_000 });
const preview: Preview = {
parameters: {
layout: 'fullscreen',
@@ -117,7 +122,21 @@ const preview: Preview = {
['List', 'New', 'Edit'],
],
'Dashboards',
['List', 'Detail', 'Panel Editor', 'Public'],
[
'List',
'Detail',
[
'Overview',
'Settings',
'Variables',
'New Variable',
'Edit Variable',
'Authz',
],
'Panel Editor',
['Overview', 'Chart Options', 'Thresholds and Links'],
'Public',
],
'Services',
['List', 'Detail', 'Top Level Operations', 'Service Map'],
'Logs',

View File

@@ -23,6 +23,13 @@ const IGNORED_MESSAGES = [
// (YouTube embeds, the docs pane) so they hit the real network instead of
// an unanswered msw request; the block is the point, not a bug.
/violates the following Content Security Policy directive/,
// The filter editor's ANTLR parser reports every syntax error through
// `console.error` (`line 1:14 missing ...`), so each partial expression
// typed into it logs one; the editor shows the same errors on screen.
/^line \d+:\d+ /,
// Chromium's echo of a 4xx/5xx response, which the `[response]` entry below
// already reports with its URL and the time its request left.
/^Failed to load resource: the server responded with a status of /,
];
interface CapturedMessage {
@@ -30,6 +37,8 @@ interface CapturedMessage {
text: string;
}
const PREPARE_TIMEOUT_MS = 180_000;
const messagesByPage = new WeakMap<Page, CapturedMessage[]>();
/**
@@ -52,6 +61,15 @@ const config: TestRunnerConfig = {
// msw logs every mocked request at `log`; keep it out of the failure dump
// unless the job is re-run with debug logging (GitHub sets RUNNER_DEBUG=1).
logLevel: process.env.RUNNER_DEBUG === '1' ? 'info' : 'warn',
// The runner's default prepare, minus Playwright's 30s navigation timeout: on
// a cold dev server the first load compiles the whole preview, which outlasts
// it on a shared CI runner.
async prepare({ page }): Promise<void> {
await page.goto(new URL('iframe.html', process.env.TARGET_URL).toString(), {
waitUntil: 'load',
timeout: PREPARE_TIMEOUT_MS,
});
},
async preVisit(page): Promise<void> {
const existing = messagesByPage.get(page);
if (existing) {
@@ -75,7 +93,9 @@ const config: TestRunnerConfig = {
page.on('response', (response) => {
if (response.status() >= 400) {
messages.push({
at: Date.now(),
// The browser's clock, when the request left: a busy runner receives
// the outgoing story's responses after the next story has started.
at: response.request().timing().startTime,
text: `[response] ${response.status()} ${response.url()}`,
});
}

View File

@@ -25,6 +25,7 @@ You are operating within a constrained context window and strict system prompts.
- Never create barrel files.
- When writing new css, prefer CSS Modules
- Use ./docs/css-modules-guide.md as reference on how to write good CSS Modules.
- Before styling a `@signozhq/ui` component, check its props in `node_modules/@signozhq/ui/dist/<component>/*.d.ts` for `className`/`style` support; some omit them. Avoid overriding the component's CSS vars unless explicitly needed.
- When writing code that could need authorization checks, read ./src/lib/authz/README.md
3. FORCED VERIFICATION: Your internal tools mark file writes as successful even if the code does not compile. You are FORBIDDEN from reporting a task as complete until you have:

View File

@@ -41,6 +41,20 @@ if (!HTMLElement.prototype.releasePointerCapture) {
HTMLElement.prototype.releasePointerCapture = function (): void {};
}
// jsdom has no PointerEvent; Base UI Switch constructs one on click.
if (typeof window.PointerEvent === 'undefined') {
class PointerEventMock extends MouseEvent {
pointerId: number;
pointerType: string;
constructor(type: string, init: PointerEventInit = {}) {
super(type, init);
this.pointerId = init.pointerId ?? 0;
this.pointerType = init.pointerType ?? '';
}
}
(window as any).PointerEvent = PointerEventMock;
}
if (typeof window.IntersectionObserver === 'undefined') {
class IntersectionObserverMock {
observe(): void {}

View File

@@ -52,9 +52,9 @@
"@monaco-editor/react": "^4.7.0",
"@sentry/react": "10.57.0",
"@sentry/vite-plugin": "5.3.0",
"@signozhq/design-tokens": "2.1.6",
"@signozhq/design-tokens": "2.2.1",
"@signozhq/icons": "0.4.0",
"@signozhq/ui": "0.1.0",
"@signozhq/ui": "0.2.0",
"@tanstack/react-table": "8.21.3",
"@tanstack/react-virtual": "3.13.22",
"@uiw/codemirror-theme-copilot": "4.23.11",

438
frontend/pnpm-lock.yaml generated
View File

@@ -72,14 +72,14 @@ importers:
specifier: 5.3.0
version: 5.3.0
'@signozhq/design-tokens':
specifier: 2.1.6
version: 2.1.6
specifier: 2.2.1
version: 2.2.1
'@signozhq/icons':
specifier: 0.4.0
version: 0.4.0
'@signozhq/ui':
specifier: 0.1.0
version: 0.1.0(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)
specifier: 0.2.0
version: 0.2.0(@date-fns/tz@1.4.1)(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)
'@tanstack/react-table':
specifier: 8.21.3
version: 8.21.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1284,6 +1284,33 @@ packages:
resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==}
engines: {node: '>=6.9.0'}
'@base-ui/react@1.7.0':
resolution: {integrity: sha512-j+8QjX44C32jrXD/qyEAGpFr70FRpGL2CY61mQd9nBPWN737CK0xxD1ceJ055rW4RtdvFDT1e7otzdlfxvsYug==}
engines: {node: '>=14.0.0'}
peerDependencies:
'@date-fns/tz': ^1.2.0
'@types/react': ^17 || ^18 || ^19
date-fns: ^4.0.0
react: ^17 || ^18 || ^19
react-dom: ^17 || ^18 || ^19
peerDependenciesMeta:
'@date-fns/tz':
optional: true
'@types/react':
optional: true
date-fns:
optional: true
'@base-ui/utils@0.3.2':
resolution: {integrity: sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ==}
peerDependencies:
'@types/react': ^17 || ^18 || ^19
react: ^17 || ^18 || ^19
react-dom: ^17 || ^18 || ^19
peerDependenciesMeta:
'@types/react':
optional: true
'@bcoe/v8-coverage@0.2.3':
resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==}
@@ -1726,20 +1753,20 @@ packages:
resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==}
engines: {node: ^20.19.0 || ^22.13.0 || >=24}
'@floating-ui/core@1.5.2':
resolution: {integrity: sha512-Ii3MrfY/GAIN3OhXNzpCKaLxHQfJF9qvwq/kEJYdqDxeIHa01K8sldugal6TmeeXl+WMvhv9cnVzUTaFFJF09A==}
'@floating-ui/core@1.8.0':
resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==}
'@floating-ui/dom@1.5.3':
resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==}
'@floating-ui/dom@1.8.0':
resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==}
'@floating-ui/react-dom@2.0.4':
resolution: {integrity: sha512-CF8k2rgKeh/49UrnIBs4BdxPUV6vize/Db1d/YbCLyp9GiVZ0BEwf5AiDSxJRCr6yOkGqTFHtmrULxkEfYZ7dQ==}
'@floating-ui/react-dom@2.1.9':
resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==}
peerDependencies:
react: '>=16.8.0'
react-dom: '>=16.8.0'
'@floating-ui/utils@0.1.6':
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
'@floating-ui/utils@0.2.12':
resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==}
'@gerrit0/mini-shiki@3.23.0':
resolution: {integrity: sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==}
@@ -2920,19 +2947,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-checkbox@1.3.11':
resolution: {integrity: sha512-Gnptr9pDDQxD3hgq2dtPbtrp/c2qH1mBwIzw3X/ivrMb2e1t0jMTi606fVEqFPaQR1ggXIVQWKj3P2WW9v7zGQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-collection@1.1.15':
resolution: {integrity: sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==}
peerDependencies:
@@ -2946,15 +2960,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-compose-refs@1.1.2':
resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-compose-refs@1.1.5':
resolution: {integrity: sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==}
peerDependencies:
@@ -3008,19 +3013,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-dropdown-menu@2.1.24':
resolution: {integrity: sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-focus-guards@1.1.6':
resolution: {integrity: sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==}
peerDependencies:
@@ -3048,15 +3040,6 @@ packages:
peerDependencies:
react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc
'@radix-ui/react-id@1.1.1':
resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-id@1.1.4':
resolution: {integrity: sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==}
peerDependencies:
@@ -3066,19 +3049,6 @@ packages:
'@types/react':
optional: true
'@radix-ui/react-menu@2.1.24':
resolution: {integrity: sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-popover@1.1.23':
resolution: {integrity: sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ==}
peerDependencies:
@@ -3144,19 +3114,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-primitive@2.1.4':
resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-progress@1.1.16':
resolution: {integrity: sha512-5XnomAsoZZCY+KNTxbIghpGqPruZvKFNlvcAljVAOdDRDsH4/OZQxhtwo5wdtoDM5R6MhJBb2sPnDuRFep3lzg==}
peerDependencies:
@@ -3222,15 +3179,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-slot@1.2.4':
resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-slot@1.3.3':
resolution: {integrity: sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==}
peerDependencies:
@@ -3240,19 +3188,6 @@ packages:
'@types/react':
optional: true
'@radix-ui/react-switch@1.3.7':
resolution: {integrity: sha512-48tB/4dn2UVLBCYhTu9AuR63IHl73l/qLbLgxd86noTUor4/K4LFDAcYjK+isP5313qxaFpjPVogE7+Y0/V3Kw==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-tabs@1.1.21':
resolution: {integrity: sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog==}
peerDependencies:
@@ -3266,45 +3201,6 @@ packages:
'@types/react-dom':
optional: true
'@radix-ui/react-toggle-group@1.1.19':
resolution: {integrity: sha512-OtnwuSVjd1Ofi+AdnvhsjQdyuhCDwYs1w9RyB5BN/OavXOVQo42SYqQjwUnbPnaiPFBpQ9aX70dWeee+v2oBLA==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-toggle@1.1.18':
resolution: {integrity: sha512-7lonPlKfSacd20GlOBx2ltuVKz9oqWYZz+oMQyOltw6t1y2nyftj2ZmwwUHYn49kqfDWcp8dNZm5NgV+5Z+mug==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-tooltip@1.2.16':
resolution: {integrity: sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
'@radix-ui/react-use-callback-ref@1.1.4':
resolution: {integrity: sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==}
peerDependencies:
@@ -3341,15 +3237,6 @@ packages:
'@types/react':
optional: true
'@radix-ui/react-use-layout-effect@1.1.1':
resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==}
peerDependencies:
'@types/react': '*'
react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
peerDependenciesMeta:
'@types/react':
optional: true
'@radix-ui/react-use-layout-effect@1.1.4':
resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==}
peerDependencies:
@@ -3721,14 +3608,14 @@ packages:
'@sideway/pinpoint@2.0.0':
resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==}
'@signozhq/design-tokens@2.1.6':
resolution: {integrity: sha512-n0cH4TRS1Xj7BR38HGiwIBDekIOAnDgl2JyYmAyUvws0L1nlE0txSHO5NiOBJ22Dm8uMva0v5/rOHxpKsGQbsw==}
'@signozhq/design-tokens@2.2.1':
resolution: {integrity: sha512-ulf6lhWUP6qxqsyemQySUMfOIKRvefvZ5rBRv+wlhOpPfYPk3uatPmPkKEhAjISpX8f9g1Gg8wgRZxUCysf20Q==}
'@signozhq/icons@0.4.0':
resolution: {integrity: sha512-QctNvNPlQlsefFdIVmSy/P/7a1IcQ3IryKP0KPMqtoqew3q89FGUmFa5IfEJ7Z3CHhtG1zaXwBKqP72QkLyA3g==}
'@signozhq/ui@0.1.0':
resolution: {integrity: sha512-FjqmQhz+WtpGl29gPGZey5YwNe4p++TCyX4jaGUhAgvlBGRmxmAKW0lFRrSOYTPbgFL5UaDCW0wR62aiGHZ+FA==}
'@signozhq/ui@0.2.0':
resolution: {integrity: sha512-j20ldiOkR150ON0BCDhlq6fXGoPN++7w6e4t2HtM2XMM4buJO7aHzPzNKvDRZ2UUf/LGPULPAW8w6sg6gUVHyw==}
peerDependencies:
'@signozhq/icons': 0.3.0
react: ^18.2.0
@@ -8520,6 +8407,11 @@ packages:
react: ^16.8.5 || ^17.0.0 || ^18.0.0
react-dom: ^16.8.5 || ^17.0.0 || ^18.0.0
react-compiler-runtime@1.0.0:
resolution: {integrity: sha512-rRfjYv66HlG8896yPUDONgKzG5BxZD1nV9U6rkm+7VCuvQc903C4MjcoZR4zPw53IKSOX9wMQVpA1IAbRtzQ7w==}
peerDependencies:
react: ^17.0.0 || ^18.0.0 || ^19.0.0 || ^0.0.0-experimental
react-day-picker@9.9.0:
resolution: {integrity: sha512-NtkJbuX6cl/VaGNb3sVVhmMA6LSMnL5G3xNL+61IyoZj0mUZFWTg4hmj7PHjIQ8MXN9dHWhUHFoJWG6y60DKSg==}
engines: {node: '>=18'}
@@ -8907,6 +8799,9 @@ packages:
requires-port@1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
reselect@5.3.0:
resolution: {integrity: sha512-XGoLeRAVzUTcJ1qkxPQhDJyIZ5d6zzZD9nT7AEZOaaU9UbWclhycElmhO+VD5bFeLuzhPBaOV2oXC8uG35ZSpg==}
reserved-words@0.1.2:
resolution: {integrity: sha512-0S5SrIUJ9LfpbVl4Yzij6VipUdafHrOTzvmfazSw/jeZrZtQK303OPZW+obtkaw7jQlTQppy0UvZWm9872PbRw==}
@@ -11154,6 +11049,31 @@ snapshots:
'@babel/helper-string-parser': 7.29.7
'@babel/helper-validator-identifier': 7.29.7
'@base-ui/react@1.7.0(@date-fns/tz@1.4.1)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.29.2
'@base-ui/utils': 0.3.2(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@floating-ui/react-dom': 2.1.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@floating-ui/utils': 0.2.12
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
use-sync-external-store: 1.6.0(react@18.2.0)
optionalDependencies:
'@date-fns/tz': 1.4.1
'@types/react': 18.0.26
date-fns: 4.1.0
'@base-ui/utils@0.3.2(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.29.2
'@floating-ui/utils': 0.2.12
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
reselect: 5.3.0
use-sync-external-store: 1.6.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@bcoe/v8-coverage@0.2.3': {}
'@braintree/sanitize-url@7.0.1': {}
@@ -11598,22 +11518,22 @@ snapshots:
'@eslint/core': 1.2.1
levn: 0.4.1
'@floating-ui/core@1.5.2':
'@floating-ui/core@1.8.0':
dependencies:
'@floating-ui/utils': 0.1.6
'@floating-ui/utils': 0.2.12
'@floating-ui/dom@1.5.3':
'@floating-ui/dom@1.8.0':
dependencies:
'@floating-ui/core': 1.5.2
'@floating-ui/utils': 0.1.6
'@floating-ui/core': 1.8.0
'@floating-ui/utils': 0.2.12
'@floating-ui/react-dom@2.0.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
'@floating-ui/react-dom@2.1.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@floating-ui/dom': 1.5.3
'@floating-ui/dom': 1.8.0
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@floating-ui/utils@0.1.6': {}
'@floating-ui/utils@0.2.12': {}
'@gerrit0/mini-shiki@3.23.0':
dependencies:
@@ -12763,21 +12683,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-checkbox@1.3.11(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-presence': 1.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-size': 1.1.4(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-collection@1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
@@ -12790,12 +12695,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-compose-refs@1.1.2(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-compose-refs@1.1.5(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
@@ -12850,21 +12749,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-dropdown-menu@2.1.24(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-menu': 2.1.24(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-focus-guards@1.1.6(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
@@ -12886,13 +12770,6 @@ snapshots:
dependencies:
react: 18.2.0
'@radix-ui/react-id@1.1.1(@types/react@18.0.26)(react@18.2.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-id@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
'@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.0.26)(react@18.2.0)
@@ -12900,32 +12777,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-menu@2.1.24(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-collection': 1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-direction': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-focus-guards': 1.1.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-popper': 1.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-portal': 1.1.17(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-presence': 1.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slot': 1.3.3(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.1.4(@types/react@18.0.26)(react@18.2.0)
aria-hidden: 1.2.6
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
react-remove-scroll: 2.7.2(@types/react@18.0.26)(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-popover@1.1.23(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
@@ -12951,7 +12802,7 @@ snapshots:
'@radix-ui/react-popper@1.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@floating-ui/react-dom': 2.0.4(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@floating-ui/react-dom': 2.1.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-arrow': 1.1.15(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
@@ -12995,15 +12846,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-primitive@2.1.4(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/react-slot': 1.2.4(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-progress@1.1.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
@@ -13099,13 +12941,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-slot@1.2.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-slot@1.3.3(@types/react@18.0.26)(react@18.2.0)':
dependencies:
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
@@ -13113,20 +12948,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-switch@1.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-size': 1.1.4(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-tabs@1.1.21(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
@@ -13143,53 +12964,6 @@ snapshots:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-toggle-group@1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-direction': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-toggle': 1.1.18(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-toggle@1.1.18(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-tooltip@1.2.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@radix-ui/primitive': 1.1.7
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-context': 1.2.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-popper': 1.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-portal': 1.1.17(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-presence': 1.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slot': 1.3.3(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.2.6(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
optionalDependencies:
'@types/react': 18.0.26
'@types/react-dom': 18.0.10
'@radix-ui/react-use-callback-ref@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
@@ -13218,12 +12992,6 @@ snapshots:
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
optionalDependencies:
'@types/react': 18.0.26
'@radix-ui/react-use-layout-effect@1.1.4(@types/react@18.0.26)(react@18.2.0)':
dependencies:
react: 18.2.0
@@ -13272,14 +13040,14 @@ snapshots:
'@rc-component/context@1.4.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
'@rc-component/mini-decimal@1.0.1':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
'@rc-component/mutate-observer@1.1.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
@@ -13291,7 +13059,7 @@ snapshots:
'@rc-component/portal@1.1.2(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
classnames: 2.3.2
rc-util: 5.38.1(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
@@ -13559,16 +13327,15 @@ snapshots:
'@sideway/pinpoint@2.0.0': {}
'@signozhq/design-tokens@2.1.6': {}
'@signozhq/design-tokens@2.2.1': {}
'@signozhq/icons@0.4.0': {}
'@signozhq/ui@0.1.0(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)':
'@signozhq/ui@0.2.0(@date-fns/tz@1.4.1)(@emotion/is-prop-valid@1.2.0)(@signozhq/icons@0.4.0)(@types/react-dom@18.0.10)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)':
dependencies:
'@base-ui/react': 1.7.0(@date-fns/tz@1.4.1)(@types/react@18.0.26)(date-fns@4.1.0)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@chenglou/pretext': 0.0.8
'@radix-ui/react-checkbox': 1.3.11(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-dialog': 1.1.23(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-dropdown-menu': 2.1.24(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-icons': 1.3.2(react@18.2.0)
'@radix-ui/react-popover': 1.1.23(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-progress': 1.1.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -13576,11 +13343,7 @@ snapshots:
'@radix-ui/react-select': 2.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slider': 1.4.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-slot': 1.3.3(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-switch': 1.3.7(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-tabs': 1.1.21(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-toggle': 1.1.18(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-toggle-group': 1.1.19(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-tooltip': 1.2.16(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@signozhq/icons': 0.4.0
'@tanstack/react-table': 8.21.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@tanstack/react-virtual': 3.14.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -13594,16 +13357,19 @@ snapshots:
next-themes: 0.4.6(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
nuqs: 2.9.6(react-router-dom@5.3.4(react@18.2.0))(react-router@6.30.6(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-compiler-runtime: 1.0.0(react@18.2.0)
react-day-picker: 9.9.0(react@18.2.0)
react-dom: 18.2.0(react@18.2.0)
react-resizable-panels: 4.12.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
sonner: 2.0.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
transitivePeerDependencies:
- '@date-fns/tz'
- '@emotion/is-prop-valid'
- '@remix-run/react'
- '@tanstack/react-router'
- '@types/react'
- '@types/react-dom'
- date-fns
- next
- react-router
- react-router-dom
@@ -15129,10 +14895,10 @@ snapshots:
cmdk@1.1.1(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
dependencies:
'@radix-ui/react-compose-refs': 1.1.2(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-compose-refs': 1.1.5(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-dialog': 1.1.23(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-id': 1.1.1(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
'@radix-ui/react-id': 1.1.4(@types/react@18.0.26)(react@18.2.0)
'@radix-ui/react-primitive': 2.1.10(@types/react-dom@18.0.10)(@types/react@18.0.26)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
@@ -19277,6 +19043,10 @@ snapshots:
transitivePeerDependencies:
- react-native
react-compiler-runtime@1.0.0(react@18.2.0):
dependencies:
react: 18.2.0
react-day-picker@9.9.0(react@18.2.0):
dependencies:
'@date-fns/tz': 1.4.1
@@ -19762,6 +19532,8 @@ snapshots:
requires-port@1.0.0: {}
reselect@5.3.0: {}
reserved-words@0.1.2: {}
resize-observer-polyfill@1.5.1: {}
@@ -19867,7 +19639,7 @@ snapshots:
rtl-css-js@1.16.1:
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
run-applescript@7.1.0: {}
@@ -20679,7 +20451,7 @@ snapshots:
unload@2.2.0:
dependencies:
'@babel/runtime': 7.28.2
'@babel/runtime': 7.29.2
detect-node: 2.1.0
unplugin@2.3.11:

View File

@@ -33,7 +33,6 @@
"NOT_FOUND": "SigNoz | Page Not Found",
"LOGS": "SigNoz | Logs",
"LOGS_EXPLORER": "SigNoz | Logs Explorer",
"LIVE_LOGS": "SigNoz | Live Logs",
"HOME_PAGE": "Open source Observability Platform | SigNoz",
"PASSWORD_RESET": "SigNoz | Password Reset",
"LIST_LICENSES": "SigNoz | List of Licenses",

View File

@@ -42,7 +42,6 @@
"NOT_FOUND": "SigNoz | Page Not Found",
"LOGS": "SigNoz | Logs",
"LOGS_EXPLORER": "SigNoz | Logs Explorer",
"LIVE_LOGS": "SigNoz | Live Logs",
"LOGS_PIPELINES": "SigNoz | Logs Pipelines",
"HOME_PAGE": "Open source Observability Platform | SigNoz",
"PASSWORD_RESET": "SigNoz | Password Reset",

View File

@@ -8,7 +8,6 @@ import { ORG_PREFERENCES } from 'constants/orgPreferences';
import ROUTES from 'constants/routes';
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
import { useIsAIAssistantEnabled } from 'hooks/useIsAIAssistantEnabled';
import { useIsAIObservabilityEnabled } from 'hooks/useIsAIObservabilityEnabled';
import { isEmpty } from 'lodash-es';
import { useAppContext } from 'providers/App/App';
import { LicensePlatform, LicenseState } from 'types/api/licensesV3/getActive';
@@ -44,7 +43,6 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
const isAdmin = user.role === USER_ROLES.ADMIN;
const isAIAssistantEnabled = useIsAIAssistantEnabled();
const isAIObservabilityEnabled = useIsAIObservabilityEnabled();
const mapRoutes = useMemo(
() =>
new Map(
@@ -135,14 +133,6 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
return <Redirect to={ROUTES.HOME} />;
}
if (
(pathname.startsWith(`${ROUTES.AI_OBSERVABILITY_BASE}/`) ||
pathname === ROUTES.AI_OBSERVABILITY_BASE) &&
!isAIObservabilityEnabled
) {
return <Redirect to={ROUTES.HOME} />;
}
// Check for workspace access restriction (cloud only)
const isCloudPlatform = activeLicense?.platform === LicensePlatform.CLOUD;

View File

@@ -300,14 +300,6 @@ describe('PrivateRoute', () => {
);
});
it('should redirect /logs-explorer/live to /logs/logs-explorer/live', () => {
renderPrivateRoute({ initialRoute: '/logs-explorer/live' });
expect(screen.getByTestId('location-display')).toHaveTextContent(
'/logs/logs-explorer/live',
);
});
it('should redirect /logs-save-views to /logs/saved-views', () => {
renderPrivateRoute({ initialRoute: '/logs-save-views' });
@@ -1596,7 +1588,6 @@ describe('PrivateRoute', () => {
// route definition comes last, and both keys are authz-aware either way.
LOGS: { path: ROUTES.LOGS, deniedRoles: DENIED_ROLES },
LOGS_EXPLORER: { path: ROUTES.LOGS_EXPLORER, deniedRoles: DENIED_ROLES },
LIVE_LOGS: { path: ROUTES.LIVE_LOGS, deniedRoles: DENIED_ROLES },
METRICS_EXPLORER: {
path: ROUTES.METRICS_EXPLORER,
deniedRoles: DENIED_ROLES,

View File

@@ -12,13 +12,14 @@ import { CmdKPalette } from 'components/cmdKPalette/cmdKPalette';
import NotFound from 'components/NotFound';
import { ShiftHoldOverlayController } from 'components/ShiftOverlay/ShiftHoldOverlayController';
import Spinner from 'components/Spinner';
import { FeatureKeys } from 'constants/features';
import { LOCALSTORAGE } from 'constants/localStorage';
import ROUTES from 'constants/routes';
import AppLayout from 'container/AppLayout';
import Hex from 'crypto-js/enc-hex';
import HmacSHA256 from 'crypto-js/hmac-sha256';
import { useIsAIAssistantEnabled } from 'hooks/useIsAIAssistantEnabled';
import { useSavedViewEnabled } from 'hooks/useSavedViewEnabled';
import { ChatSupportState, useChatSupport } from 'hooks/useChatSupport';
import { useIsDarkMode } from 'hooks/useDarkMode';
import { useGetTenantLicense } from 'hooks/useGetTenantLicense';
import { StatusCodes } from 'http-status-codes';
@@ -58,7 +59,6 @@ function App(): JSX.Element {
isFetchingActiveLicense,
activeLicenseFetchError,
userFetchError,
featureFlagsFetchError,
isLoggedIn: isLoggedInState,
featureFlags,
org,
@@ -66,6 +66,8 @@ function App(): JSX.Element {
} = useAppContext();
const [routes, setRoutes] = useState<AppRoutes[]>(defaultRoutes);
const isAIAssistantEnabled = useIsAIAssistantEnabled();
const isSavedViewEnabled = useSavedViewEnabled();
const chatSupport = useChatSupport();
const { hostname } = window.location;
const [pathname, setPathname] = useState(history.location.pathname);
@@ -253,7 +255,9 @@ function App(): JSX.Element {
}, [isDarkMode]);
useEffect(() => {
// The bottom strip carries Support, so the floating bubble goes entirely.
if (
isSavedViewEnabled ||
pathname === ROUTES.ONBOARDING ||
pathname.startsWith('/public/dashboard/') ||
pathname === '/ai-assistant' ||
@@ -263,71 +267,32 @@ function App(): JSX.Element {
} else {
window.Pylon?.('showChatBubble');
}
}, [pathname]);
}, [pathname, isSavedViewEnabled]);
// eslint-disable-next-line sonarjs/cognitive-complexity
// Identity for the Pylon widget. Whether this user gets Pylon at all is
// `useChatSupport`'s call — this only fills in who they are.
useEffect(() => {
// feature flag shouldn't be loading and featureFlags or fetchError any one of this should be true indicating that req is complete
// licenses should also be present. there is no check for licenses for loading and error as that is mandatory if not present then routing
// to something went wrong which would ideally need a reload.
if (
!isFetchingFeatureFlags &&
(featureFlags || featureFlagsFetchError) &&
activeLicense &&
trialInfo
) {
let isChatSupportEnabled = false;
let isPremiumSupportEnabled = false;
if (featureFlags && featureFlags.length > 0) {
isChatSupportEnabled =
featureFlags.find((flag) => flag.name === FeatureKeys.CHAT_SUPPORT)
?.active || false;
isPremiumSupportEnabled =
featureFlags.find((flag) => flag.name === FeatureKeys.PREMIUM_SUPPORT)
?.active || false;
}
const showAddCreditCardModal =
!isPremiumSupportEnabled && !trialInfo?.trialConvertedToSubscription;
if (
isLoggedInState &&
isChatSupportEnabled &&
!showAddCreditCardModal &&
(isCloudUser || isEnterpriseSelfHostedUser) &&
window.signozBootData?.settings?.pylon?.enabled
) {
const email = user.email || '';
const secret = window.signozBootData?.settings?.pylon?.identitySecret || '';
let emailHash = '';
if (email && secret) {
emailHash = HmacSHA256(email, Hex.parse(secret)).toString(Hex);
}
window.pylon = {
chat_settings: {
app_id: window.signozBootData?.settings?.pylon?.appId,
email: user.email,
name: user.displayName || user.email,
email_hash: emailHash,
},
};
}
if (chatSupport !== ChatSupportState.Pylon) {
return;
}
}, [
isLoggedInState,
user,
pathname,
trialInfo?.trialConvertedToSubscription,
featureFlags,
isFetchingFeatureFlags,
featureFlagsFetchError,
activeLicense,
trialInfo,
isCloudUser,
isEnterpriseSelfHostedUser,
]);
const email = user.email || '';
const secret = window.signozBootData?.settings?.pylon?.identitySecret || '';
let emailHash = '';
if (email && secret) {
emailHash = HmacSHA256(email, Hex.parse(secret)).toString(Hex);
}
window.pylon = {
chat_settings: {
app_id: window.signozBootData?.settings?.pylon?.appId,
email: user.email,
name: user.displayName || user.email,
email_hash: emailHash,
},
};
}, [chatSupport, user]);
useEffect(() => {
if (!isFetchingUser && isCloudUser && user && user.email) {

View File

@@ -154,10 +154,6 @@ export const Logs = Loadable(
() => import(/* webpackChunkName: "Logs" */ 'pages/LogsModulePage'),
);
export const LiveLogs = Loadable(
() => import(/* webpackChunkName: "Live Logs" */ 'pages/LiveLogs'),
);
export const PipelinePage = Loadable(
() => import(/* webpackChunkName: "Pipelines" */ 'pages/LogsModulePage'),
);

View File

@@ -23,7 +23,6 @@ import {
LicensePage,
ListAllALertsPage,
LLMObservabilityPage,
LiveLogs,
Login,
Logs,
LogsIndexToFields,
@@ -282,13 +281,6 @@ const routes: AppRoutes[] = [
key: 'LOGS',
isPrivate: true,
},
{
path: ROUTES.LIVE_LOGS,
exact: true,
component: LiveLogs,
key: 'LIVE_LOGS',
isPrivate: true,
},
{
path: ROUTES.LOGS_PIPELINES,
exact: true,
@@ -521,7 +513,6 @@ export const LIST_LICENSES: AppRoutes = {
export const oldNewRoutesMapping: Record<string, string> = {
'/pipelines': '/logs/pipelines',
'/logs-explorer': '/logs/logs-explorer',
'/logs-explorer/live': '/logs/logs-explorer/live',
'/logs-save-views': '/logs/saved-views',
'/traces-save-views': '/traces/saved-views',
'/settings/access-tokens': '/settings/service-accounts',

View File

@@ -41,17 +41,16 @@ export function ErrorResponseHandler(error: AxiosError): ErrorResponse {
message: data?.error,
};
}
// Avoid logging error when the request was just cancelled for whatever reason
if (isCancel(error)) {
return {
statusCode: 500,
payload: null,
error: 'Something went wrong',
message: null,
};
}
if (request) {
// Avoid logging error when the request was just cancelled for whatever reason
if (isCancel(error)) {
return {
statusCode: 500,
payload: null,
error: 'Something went wrong',
message: null,
};
}
// client never received a response, or request never left
console.error('client never received a response, or request never left');

View File

@@ -0,0 +1,22 @@
import { ErrorResponseHandler } from 'api/ErrorResponseHandler';
import { AxiosError, CanceledError } from 'axios';
describe('ErrorResponseHandler', () => {
// axios aborts a request whose signal fired before it was sent without ever
// creating one, so the error carries neither `response` nor `request`.
it('treats a request cancelled before it was sent as a cancellation', () => {
const consoleError = jest
.spyOn(console, 'error')
.mockImplementation(() => undefined);
expect(ErrorResponseHandler(new CanceledError() as AxiosError)).toEqual({
statusCode: 500,
payload: null,
error: 'Something went wrong',
message: null,
});
expect(consoleError).not.toHaveBeenCalled();
consoleError.mockRestore();
});
});

View File

@@ -41,6 +41,8 @@ import type {
GetRuleHistoryTopContributorsParams,
GetRuleHistoryTopContributorsPathParameters,
ListRules200,
ListRulesV3200,
ListRulesV3Params,
PatchRuleByID200,
PatchRuleByIDPathParameters,
RenderErrorResponseDTO,
@@ -73,7 +75,8 @@ const withQueryKey = <T extends object, K>(
};
/**
* This endpoint lists all alert rules with their current evaluation state
* This endpoint lists all alert rules with their current evaluation state. Deprecated: use ListRulesV3, which supports filtering, sorting and pagination.
* @deprecated
* @summary List alert rules
*/
export const listRules = (signal?: AbortSignal) => {
@@ -115,6 +118,7 @@ export type ListRulesQueryResult = NonNullable<
export type ListRulesQueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @deprecated
* @summary List alert rules
*/
@@ -134,6 +138,7 @@ export function useListRules<
}
/**
* @deprecated
* @summary List alert rules
*/
export const invalidateListRules = async (
@@ -1388,3 +1393,97 @@ export const useTestRule = <
> => {
return useMutation(getTestRuleMutationOptions(options));
};
/**
* Returns a page of alert rules with their current evaluation state, trimmed to the fields the list page renders. Supports a filter DSL (`query`), a repeated `states` filter applied after the state overlay, sort (`updated_at`/`created_at`/`name`/`state`/`severity`), order (`asc`/`desc`), and offset-based pagination (`limit`/`offset`). In the filter DSL, a non-reserved key is matched as a rule label directly (`team = infra`); a key that collides with a reserved keyword matches either interpretation (negative operators exclude both), and `labels.<key>` targets only the label. The response also carries the org's label pairs and the reserved filter keys for building filter suggestions.
* @summary List alert rules (v3)
*/
export const listRulesV3 = (
params?: ListRulesV3Params,
signal?: AbortSignal,
) => {
return GeneratedAPIInstance<ListRulesV3200>({
url: `/api/v3/rules`,
method: 'GET',
params,
signal,
});
};
export const getListRulesV3QueryKey = (params?: ListRulesV3Params) => {
return [`/api/v3/rules`, ...(params ? [params] : [])] as const;
};
export const getListRulesV3QueryOptions = <
TData = Awaited<ReturnType<typeof listRulesV3>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListRulesV3Params,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listRulesV3>>,
TError,
TData
>;
},
) => {
const { query: queryOptions } = options ?? {};
const queryKey = queryOptions?.queryKey ?? getListRulesV3QueryKey(params);
const queryFn: QueryFunction<Awaited<ReturnType<typeof listRulesV3>>> = ({
signal,
}) => listRulesV3(params, signal);
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
Awaited<ReturnType<typeof listRulesV3>>,
TError,
TData
> & { queryKey: QueryKey };
};
export type ListRulesV3QueryResult = NonNullable<
Awaited<ReturnType<typeof listRulesV3>>
>;
export type ListRulesV3QueryError = ErrorType<RenderErrorResponseDTO>;
/**
* @summary List alert rules (v3)
*/
export function useListRulesV3<
TData = Awaited<ReturnType<typeof listRulesV3>>,
TError = ErrorType<RenderErrorResponseDTO>,
>(
params?: ListRulesV3Params,
options?: {
query?: UseQueryOptions<
Awaited<ReturnType<typeof listRulesV3>>,
TError,
TData
>;
},
): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
const queryOptions = getListRulesV3QueryOptions(params, options);
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
queryKey: QueryKey;
};
return withQueryKey(query, queryOptions.queryKey);
}
/**
* @summary List alert rules (v3)
*/
export const invalidateListRulesV3 = async (
queryClient: QueryClient,
params?: ListRulesV3Params,
options?: InvalidateOptions,
): Promise<QueryClient> => {
await queryClient.invalidateQueries(
{ queryKey: getListRulesV3QueryKey(params) },
options,
);
return queryClient;
};

View File

@@ -104,9 +104,9 @@ export interface AlertmanagertypesChannelSlackFieldDTO {
export interface AlertmanagertypesChannelSlackConfigDTO {
/**
* @type array
* @type array,null
*/
actions?: AlertmanagertypesChannelSlackActionDTO[];
actions?: AlertmanagertypesChannelSlackActionDTO[] | null;
/**
* @type string
* @format password
@@ -125,9 +125,9 @@ export interface AlertmanagertypesChannelSlackConfigDTO {
*/
fallback?: string;
/**
* @type array
* @type array,null
*/
fields?: AlertmanagertypesChannelSlackFieldDTO[];
fields?: AlertmanagertypesChannelSlackFieldDTO[] | null;
/**
* @type string
*/
@@ -166,13 +166,19 @@ export interface AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTy
export enum AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTypesAlertmanagertypesChannelEmailConfigDTOKind {
email = 'email',
}
export type AlertmanagertypesChannelEmailConfigDTOHeaders = {
export type AlertmanagertypesChannelEmailConfigDTOHeadersAnyOf = {
[key: string]: string;
};
/**
* @nullable
*/
export type AlertmanagertypesChannelEmailConfigDTOHeaders =
AlertmanagertypesChannelEmailConfigDTOHeadersAnyOf | null;
export interface AlertmanagertypesChannelEmailConfigDTO {
/**
* @type object
* @type object,null
*/
headers?: AlertmanagertypesChannelEmailConfigDTOHeaders;
/**
@@ -239,10 +245,16 @@ export interface AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTy
export enum AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTypesAlertmanagertypesChannelPagerdutyConfigDTOKind {
pagerduty = 'pagerduty',
}
export type AlertmanagertypesChannelPagerdutyConfigDTODetails = {
export type AlertmanagertypesChannelPagerdutyConfigDTODetailsAnyOf = {
[key: string]: string;
};
/**
* @nullable
*/
export type AlertmanagertypesChannelPagerdutyConfigDTODetails =
AlertmanagertypesChannelPagerdutyConfigDTODetailsAnyOf | null;
export interface AlertmanagertypesChannelPagerdutyConfigDTO {
/**
* @type string
@@ -265,7 +277,7 @@ export interface AlertmanagertypesChannelPagerdutyConfigDTO {
*/
description?: string;
/**
* @type object
* @type object,null
*/
details?: AlertmanagertypesChannelPagerdutyConfigDTODetails;
/**
@@ -307,10 +319,16 @@ export interface AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTy
export enum AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTypesAlertmanagertypesChannelOpsgenieConfigDTOKind {
opsgenie = 'opsgenie',
}
export type AlertmanagertypesChannelOpsgenieConfigDTODetails = {
export type AlertmanagertypesChannelOpsgenieConfigDTODetailsAnyOf = {
[key: string]: string;
};
/**
* @nullable
*/
export type AlertmanagertypesChannelOpsgenieConfigDTODetails =
AlertmanagertypesChannelOpsgenieConfigDTODetailsAnyOf | null;
export interface AlertmanagertypesChannelOpsgenieConfigDTO {
/**
* @type string
@@ -326,7 +344,7 @@ export interface AlertmanagertypesChannelOpsgenieConfigDTO {
*/
description?: string;
/**
* @type object
* @type object,null
*/
details?: AlertmanagertypesChannelOpsgenieConfigDTODetails;
/**
@@ -423,10 +441,16 @@ export interface AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTy
export enum AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTypesAlertmanagertypesChannelJiraConfigDTOKind {
jira = 'jira',
}
export type AlertmanagertypesChannelJiraConfigDTOCustomFields = {
export type AlertmanagertypesChannelJiraConfigDTOCustomFieldsAnyOf = {
[key: string]: unknown;
};
/**
* @nullable
*/
export type AlertmanagertypesChannelJiraConfigDTOCustomFields =
AlertmanagertypesChannelJiraConfigDTOCustomFieldsAnyOf | null;
export interface AlertmanagertypesChannelJiraConfigDTO {
/**
* @type string
@@ -434,7 +458,7 @@ export interface AlertmanagertypesChannelJiraConfigDTO {
*/
apiToken: string;
/**
* @type object
* @type object,null
*/
customFields?: AlertmanagertypesChannelJiraConfigDTOCustomFields;
/**
@@ -450,9 +474,9 @@ export interface AlertmanagertypesChannelJiraConfigDTO {
*/
issueType: string;
/**
* @type array
* @type array,null
*/
labels?: string[];
labels?: string[] | null;
/**
* @type string
*/
@@ -543,17 +567,23 @@ export interface AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTy
export enum AlertmanagertypesChannelConfigVariantGithubComSigNozSignozPkgTypesAlertmanagertypesChannelIncidentIOConfigDTOKind {
incidentio = 'incidentio',
}
export type AlertmanagertypesChannelIncidentIOConfigDTOMetadata = {
export type AlertmanagertypesChannelIncidentIOConfigDTOMetadataAnyOf = {
[key: string]: string;
};
/**
* @nullable
*/
export type AlertmanagertypesChannelIncidentIOConfigDTOMetadata =
AlertmanagertypesChannelIncidentIOConfigDTOMetadataAnyOf | null;
export interface AlertmanagertypesChannelIncidentIOConfigDTO {
/**
* @type string
*/
description?: string;
/**
* @type object
* @type object,null
*/
metadata?: AlertmanagertypesChannelIncidentIOConfigDTOMetadata;
/**
@@ -3366,6 +3396,37 @@ export interface CloudintegrationtypesAWSServiceConfigDTO {
metrics?: CloudintegrationtypesAWSServiceMetricsConfigDTO;
}
export enum CloudintegrationtypesRegionStateDTO {
enabled = 'enabled',
disabled = 'disabled',
}
export interface CloudintegrationtypesRegionSyncStateDTO {
state: CloudintegrationtypesRegionStateDTO;
}
export type CloudintegrationtypesSyncStateDTORegions = {
[key: string]: CloudintegrationtypesRegionSyncStateDTO;
};
/**
* @nullable
*/
export type CloudintegrationtypesSyncStateDTO = {
/**
* @type boolean
*/
inSync: boolean;
/**
* @type object
*/
regions: CloudintegrationtypesSyncStateDTORegions;
/**
* @type integer
* @format int64
*/
version: number;
} | null;
export type CloudintegrationtypesAgentReportDTODataAnyOf = {
[key: string]: unknown;
};
@@ -3384,6 +3445,7 @@ export type CloudintegrationtypesAgentReportDTO = {
* @type object,null
*/
data: CloudintegrationtypesAgentReportDTOData;
syncState: CloudintegrationtypesSyncStateDTO | null;
/**
* @type integer
* @format int64
@@ -3812,6 +3874,7 @@ export interface CloudintegrationtypesGettableAgentCheckInDTO {
* @format date-time
*/
removedAt: string | null;
syncState: CloudintegrationtypesSyncStateDTO | null;
}
export interface CloudintegrationtypesServiceMetadataDTO {
@@ -3882,6 +3945,10 @@ export interface CloudintegrationtypesPostableAgentCheckInDTO {
* @type string
*/
providerAccountId?: string;
/**
* @type integer,null
*/
syncedVersion?: number | null;
}
export interface CloudintegrationtypesStorableIntegrationDashboardDTO {
@@ -10188,6 +10255,99 @@ export interface RuletypesGettableTestRuleDTO {
message?: string;
}
export interface RuletypesLabelPairDTO {
/**
* @type string
*/
key: string;
/**
* @type string
*/
value: string;
}
export enum RuletypesListOrderDTO {
asc = 'asc',
desc = 'desc',
}
export enum RuletypesListSortDTO {
updated_at = 'updated_at',
created_at = 'created_at',
name = 'name',
state = 'state',
severity = 'severity',
}
export type RuletypesListableRuleDTOLabels = { [key: string]: string };
export enum RuletypesRuleTypeDTO {
threshold_rule = 'threshold_rule',
promql_rule = 'promql_rule',
anomaly_rule = 'anomaly_rule',
}
export interface RuletypesListableRuleDTO {
/**
* @type string
*/
alert: string;
alertType: RuletypesAlertTypeDTO;
/**
* @type string
* @format date-time
*/
createdAt?: string;
/**
* @type string
*/
createdBy?: string;
/**
* @type string
*/
description?: string;
/**
* @type boolean
*/
disabled?: boolean;
/**
* @type string
*/
id: string;
/**
* @type object
*/
labels?: RuletypesListableRuleDTOLabels;
ruleType: RuletypesRuleTypeDTO;
state: RuletypesAlertStateDTO;
/**
* @type string
* @format date-time
*/
updatedAt?: string;
/**
* @type string
*/
updatedBy?: string;
}
export interface RuletypesListableRulesDTO {
/**
* @type array
*/
labels: RuletypesLabelPairDTO[];
/**
* @type array
*/
reservedKeywords: string[];
/**
* @type array
*/
rules: RuletypesListableRuleDTO[];
/**
* @type integer
* @format int64
*/
total: number;
}
export interface RuletypesRenotifyDTO {
/**
* @type array,null
@@ -10284,11 +10444,6 @@ export interface RuletypesRuleConditionDTO {
thresholds?: RuletypesRuleThresholdDataDTO;
}
export enum RuletypesRuleTypeDTO {
threshold_rule = 'threshold_rule',
promql_rule = 'promql_rule',
anomaly_rule = 'anomaly_rule',
}
export interface RuletypesPostableRuleDTO {
/**
* @type string
@@ -14189,6 +14344,45 @@ export type GetMetricDashboardsV2200 = {
status: string;
};
export type ListRulesV3Params = {
/**
* @type string
* @description undefined
*/
query?: string;
/**
* @type array
* @description undefined
*/
states?: string[];
/**
* @description undefined
*/
sort?: RuletypesListSortDTO;
/**
* @description undefined
*/
order?: RuletypesListOrderDTO;
/**
* @type integer
* @description undefined
*/
limit?: number;
/**
* @type integer
* @description undefined
*/
offset?: number;
};
export type ListRulesV3200 = {
data: RuletypesListableRulesDTO;
/**
* @type string
*/
status: string;
};
export type GetFlamegraphPathParameters = {
traceID: string;
};

View File

@@ -1,6 +1,6 @@
<svg version="1.1" id="Layer_1" xmlns:x="ns_extend;" xmlns:i="ns_ai;" xmlns:graph="ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 92.2 65" style="enable-background:new 0 0 92.2 65;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st0{fill:#7A8291;}
</style>
<metadata>
<sfw xmlns="ns_sfw;">

Before

Width:  |  Height:  |  Size: 714 B

After

Width:  |  Height:  |  Size: 714 B

View File

@@ -0,0 +1,3 @@
<svg role="img" viewBox="0 0 16 15" xmlns="http://www.w3.org/2000/svg">
<path d="M14.0777 13.984C14.945 14.6345 16.2458 14.2008 15.0533 13.0084C11.476 9.53949 12.2349 0 7.79033 0C3.34579 0 4.10461 9.53949 0.527295 13.0084C-0.773543 14.3092 0.635692 14.6345 1.50293 13.984C4.86344 11.7076 4.64663 7.69664 7.79033 7.69664C10.934 7.69664 10.7172 11.7076 14.0777 13.984Z" fill="#4285F4" />
</svg>

After

Width:  |  Height:  |  Size: 394 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><g fill="none" fill-rule="evenodd"><path fill="#c925d1" d="M0 0h64v64H0z"/><path fill="#fff" d="M36.213 16.011h-2.016v-2.005h2.016V12h2.017v2.006h2.016v2.005H38.23v2.006h-2.017zm9.074 8.023h-2.016v-2.006h2.016v-2.005h2.016v2.005h2.017v2.006h-2.017v2.006h-2.016v-2.006m-3.434 22.64c-1.495-3.292-4.482-6.263-7.792-7.75 3.31-1.487 6.297-4.459 7.792-7.75 1.494 3.291 4.482 6.263 7.791 7.75-3.31 1.487-6.297 4.458-7.79 7.75m12.139-8.753c-5.202 0-11.13-5.898-11.13-11.071 0-.555-.452-1.003-1.009-1.003s-1.008.448-1.008 1.003c0 5.173-5.93 11.071-11.13 11.071-.558 0-1.009.448-1.009 1.003s.45 1.003 1.008 1.003c5.202 0 11.13 5.898 11.13 11.07 0 .554.452 1.003 1.01 1.003.556 0 1.007-.45 1.007-1.003 0-5.172 5.93-11.07 11.13-11.07.558 0 1.009-.45 1.009-1.003 0-.555-.45-1.003-1.008-1.003m-31.39-19.904c6.85 0 10.587 1.988 10.587 3.008s-3.737 3.009-10.586 3.009-10.587-1.988-10.587-3.009 3.737-3.008 10.587-3.008m-.35 15.15c-5.012 0-8.62-1.063-10.236-2.19v-7.113c2.367 1.433 6.487 2.176 10.587 2.176s8.22-.743 10.586-2.176v6.484c-1.016 1.406-5.247 2.819-10.936 2.819M33.19 45.975c0 1.435-4.126 3.52-10.59 3.52-6.46 0-10.583-2.085-10.583-3.52v-4.407c2.258 1.354 6.014 2.192 10.276 2.192 2.942 0 5.786-.413 8.01-1.166l-.651-1.898c-2.019.682-4.633 1.058-7.359 1.058-5.39 0-9.252-1.402-10.276-2.76v-5.707c2.411 1.176 6.113 1.885 10.237 1.885 3.92 0 8.34-.725 10.936-2.269v2.162h2.016v-14.04c0-3.292-6.34-5.014-12.602-5.014S10 17.733 10 21.025v24.95c0 3.59 6.49 5.526 12.598 5.526 6.112 0 12.607-1.937 12.607-5.526v-2.887h-2.016z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,6 +1,6 @@
<svg version="1.1" id="Layer_1" xmlns:x="ns_extend;" xmlns:i="ns_ai;" xmlns:graph="ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 50.6 50.6" style="enable-background:new 0 0 50.6 50.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st0{fill:#7A8291;}
</style>
<metadata>
<sfw xmlns="ns_sfw;">

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="m23.365 13.556-1.442-2.895V8.994c0-2.764-2.218-5.002-4.954-5.002h-2.464c.178-.367.276-.779.276-1.213A2.77 2.77 0 0 0 12.018 0a2.77 2.77 0 0 0-2.763 2.779c0 .434.098.846.276 1.213H7.067c-2.736 0-4.954 2.238-4.954 5.002v1.667L.64 13.549c-.149.29-.149.636 0 .927l1.472 2.855v1.667C2.113 21.762 4.33 24 7.067 24h9.902c2.736 0 4.954-2.238 4.954-5.002V17.33l1.44-2.865c.143-.286.143-.622.002-.91m-12.854 2.36a2.27 2.27 0 0 1-2.261 2.273 2.27 2.27 0 0 1-2.261-2.273v-4.042A2.27 2.27 0 0 1 8.249 9.6a2.267 2.267 0 0 1 2.262 2.274zm7.285 0a2.27 2.27 0 0 1-2.26 2.273 2.27 2.27 0 0 1-2.262-2.273v-4.042A2.267 2.267 0 0 1 15.535 9.6a2.267 2.267 0 0 1 2.261 2.274z" fill="#7A8291" />
</svg>

After

Width:  |  Height:  |  Size: 761 B

View File

@@ -1,6 +1,6 @@
<svg version="1.1" id="Layer_1" xmlns:x="ns_extend;" xmlns:i="ns_ai;" xmlns:graph="ns_graphs;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 43 43" style="enable-background:new 0 0 43 43;" xml:space="preserve">
<style type="text/css">
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#FFFFFF;}
.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#0074A2;}
</style>
<metadata>
<sfw xmlns="ns_sfw;">

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,3 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M11.503.131 1.891 5.678a.84.84 0 0 0-.42.726v11.188c0 .3.162.575.42.724l9.609 5.55a1 1 0 0 0 .998 0l9.61-5.55a.84.84 0 0 0 .42-.724V6.404a.84.84 0 0 0-.42-.726L12.497.131a1.01 1.01 0 0 0-.996 0M2.657 6.338h18.55c.263 0 .43.287.297.515L12.23 22.918c-.062.107-.229.064-.229-.06V12.335a.59.59 0 0 0-.295-.51l-9.11-5.257c-.109-.063-.064-.23.061-.23" fill="#7A8291" />
</svg>

After

Width:  |  Height:  |  Size: 453 B

View File

@@ -3,7 +3,7 @@
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 800.5 907.77" style="enable-background:new 0 0 800.5 907.77;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st0{fill:#8B5CC7;}
</style>
<path class="st0" d="M303.36,238.61c31.36-21.37,71.76-12.97,65-6.53c-12.89,12.28,4.26,8.65,6.11,31.31
c1.36,16.69-4.09,25.88-8.78,31.11c-9.79,1.28-21.69,3.67-36.02,8.33c-8.48,2.76-15.85,5.82-22.31,8.9

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -0,0 +1,10 @@
<svg role="img" viewBox="0 0 275 287" xmlns="http://www.w3.org/2000/svg">
<path d="M14.5584 193.736H114.275V227.925H14.5584V193.736Z" fill="#7A8291" />
<path d="M148.464 74.076H262.426V108.265H148.464V74.076Z" fill="#7A8291" />
<path d="M88.6338 84.6127L173.246 0L197.422 24.175L112.809 108.788L88.6338 84.6127Z" fill="#7A8291" />
<path d="M89.157 170.084L24.175 105.102L0 129.277L64.9819 194.259L89.157 170.084Z" fill="#7A8291" />
<path d="M174.629 217.911L106.133 286.407L81.9577 262.232L150.454 193.736L174.629 217.911Z" fill="#7A8291" />
<path d="M174.106 132.44L250.66 208.994L274.835 184.819L198.281 108.265L174.106 132.44Z" fill="#7A8291" />
<path d="M88.6338 48.434V131.057H54.4451L54.4451 48.434H88.6338Z" fill="#7A8291" />
<path d="M208.294 168.094V270.66H174.106V168.094H208.294Z" fill="#7A8291" />
</svg>

After

Width:  |  Height:  |  Size: 825 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#fff" viewBox="0 0 24 24"><title>Deno</title><path d="M1.105 18.02A11.9 11.9 0 0 1 0 12.985q0-.698.078-1.376a12 12 0 0 1 .231-1.34A12 12 0 0 1 4.025 4.02a12 12 0 0 1 5.46-2.771 12 12 0 0 1 3.428-.23c1.452.112 2.825.477 4.077 1.05a12 12 0 0 1 2.78 1.774 12.02 12.02 0 0 1 4.053 7.078A12 12 0 0 1 24 12.985q0 .454-.036.914a12 12 0 0 1-.728 3.305 12 12 0 0 1-2.38 3.875c-1.33 1.357-3.02 1.962-4.43 1.936a4.4 4.4 0 0 1-2.724-1.024c-.99-.853-1.391-1.83-1.53-2.919a5 5 0 0 1 .128-1.518c.105-.38.37-1.116.76-1.437-.455-.197-1.04-.624-1.226-.829-.045-.05-.04-.13 0-.183a.155.155 0 0 1 .177-.053c.392.134.869.267 1.372.35.66.111 1.484.25 2.317.292 2.03.1 4.153-.813 4.812-2.627s.403-3.609-1.96-4.685-3.454-2.356-5.363-3.128c-1.247-.505-2.636-.205-4.06.582-3.838 2.121-7.277 8.822-5.69 15.032a.191.191 0 0 1-.315.19 12 12 0 0 1-1.25-1.634 12 12 0 0 1-.769-1.404M11.57 6.087c.649-.051 1.214.501 1.31 1.236.13.979-.228 1.99-1.41 2.013-1.01.02-1.315-.997-1.248-1.614.066-.616.574-1.575 1.35-1.635"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="#7A8291" viewBox="0 0 24 24"><title>Deno</title><path d="M1.105 18.02A11.9 11.9 0 0 1 0 12.985q0-.698.078-1.376a12 12 0 0 1 .231-1.34A12 12 0 0 1 4.025 4.02a12 12 0 0 1 5.46-2.771 12 12 0 0 1 3.428-.23c1.452.112 2.825.477 4.077 1.05a12 12 0 0 1 2.78 1.774 12.02 12.02 0 0 1 4.053 7.078A12 12 0 0 1 24 12.985q0 .454-.036.914a12 12 0 0 1-.728 3.305 12 12 0 0 1-2.38 3.875c-1.33 1.357-3.02 1.962-4.43 1.936a4.4 4.4 0 0 1-2.724-1.024c-.99-.853-1.391-1.83-1.53-2.919a5 5 0 0 1 .128-1.518c.105-.38.37-1.116.76-1.437-.455-.197-1.04-.624-1.226-.829-.045-.05-.04-.13 0-.183a.155.155 0 0 1 .177-.053c.392.134.869.267 1.372.35.66.111 1.484.25 2.317.292 2.03.1 4.153-.813 4.812-2.627s.403-3.609-1.96-4.685-3.454-2.356-5.363-3.128c-1.247-.505-2.636-.205-4.06.582-3.838 2.121-7.277 8.822-5.69 15.032a.191.191 0 0 1-.315.19 12 12 0 0 1-1.25-1.634 12 12 0 0 1-.769-1.404M11.57 6.087c.649-.051 1.214.501 1.31 1.236.13.979-.228 1.99-1.41 2.013-1.01.02-1.315-.997-1.248-1.614.066-.616.574-1.575 1.35-1.635"/></svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="#FFF" viewBox="0 0 50 50"><path d="M7 2v46h36V14.594l-.281-.313-12-12L30.406 2Zm2 2h20v12h12v30H9Zm22 1.438L39.563 14H31ZM15 22v2h20v-2Zm0 6v2h16v-2Zm0 6v2h20v-2Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="#7A8291" viewBox="0 0 50 50"><path d="M7 2v46h36V14.594l-.281-.313-12-12L30.406 2Zm2 2h20v12h12v30H9Zm22 1.438L39.563 14H31ZM15 22v2h20v-2Zm0 6v2h16v-2Zm0 6v2h20v-2Z"/></svg>

Before

Width:  |  Height:  |  Size: 242 B

After

Width:  |  Height:  |  Size: 245 B

View File

@@ -0,0 +1,3 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M9 6h10v12H9a4 4 0 0 1-4-4v-4a4 4 0 0 1 4-4zm1.2 4.6h8.8v.9h-8.8zm0 3.6h8.8v.9h-8.8z" fill="#7A8291" fill-rule="evenodd" />
</svg>

After

Width:  |  Height:  |  Size: 213 B

View File

@@ -0,0 +1,5 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M6.5 5.5h13a1.5 1.5 0 0 1 0 3h-13a1.5 1.5 0 0 1 0-3z" fill="#00B173" />
<path d="M4 10.5h10a1.5 1.5 0 0 1 0 3H4a1.5 1.5 0 0 1 0-3z" fill="#00B173" />
<path d="M6.5 15.5h13a1.5 1.5 0 0 1 0 3h-13a1.5 1.5 0 0 1 0-3z" fill="#00B173" />
</svg>

After

Width:  |  Height:  |  Size: 323 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 115.28 122.88"><path d="M25.38 57h64.88V37.34H69.59c-2.17 0-5.19-1.17-6.62-2.6s-2.3-4.01-2.3-6.17V7.64H8.15c-.18 0-.32.09-.41.18-.15.1-.19.23-.19.42v106.45c0 .14.09.32.18.41.09.14.28.18.41.18h81.51c.18 0 .17-.09.27-.18.14-.09.33-.28.33-.41v-11.16H25.38c-4.14 0-7.56-3.4-7.56-7.56V64.55c0-4.15 3.4-7.55 7.56-7.55m4.11 11.38h7.43v18.15h11.63v5.92H29.49zm20.4 12.05c0-3.93 1.09-6.99 3.28-9.17 2.19-2.19 5.24-3.28 9.15-3.28 4.01 0 7.09 1.08 9.26 3.22 2.17 2.15 3.25 5.16 3.25 9.04 0 2.81-.47 5.11-1.42 6.91q-1.425 2.7-4.11 4.2t-6.69 1.5c-2.71 0-4.96-.43-6.74-1.29-1.78-.87-3.22-2.23-4.32-4.11-1.11-1.87-1.66-4.21-1.66-7.02m7.42.01c0 2.43.45 4.17 1.36 5.23s2.14 1.59 3.7 1.59c1.6 0 2.84-.52 3.71-1.56.88-1.04 1.32-2.9 1.32-5.6 0-2.26-.46-3.92-1.37-4.96-.92-1.05-2.16-1.57-3.73-1.57-1.5 0-2.71.53-3.62 1.59-.91 1.08-1.37 2.83-1.37 5.28m33.11 3.3v-5.01h11.49v10.23c-2.2 1.5-4.15 2.53-5.83 3.07-1.69.54-3.7.81-6.02.81-2.86 0-5.19-.49-6.99-1.46s-3.19-2.42-4.18-4.35c-.99-1.92-1.48-4.13-1.48-6.63 0-2.63.54-4.91 1.62-6.85s2.67-3.41 4.76-4.42c1.63-.78 3.83-1.17 6.58-1.17 2.66 0 4.64.24 5.96.72s2.41 1.23 3.28 2.24 1.52 2.3 1.96 3.85l-7.16 1.29c-.3-.91-.8-1.61-1.5-2.09-.71-.49-1.6-.73-2.7-.73-1.62 0-2.92.57-3.89 1.7s-1.45 2.92-1.45 5.37c0 2.6.49 4.46 1.47 5.57.97 1.11 2.34 1.68 4.09 1.68q1.245 0 2.37-.36c.75-.24 1.61-.65 2.59-1.22v-2.25h-4.97zM97.79 57h9.93c4.16 0 7.56 3.41 7.56 7.56v31.42c0 4.15-3.41 7.56-7.56 7.56h-9.93v13.55c0 1.61-.65 3.04-1.7 4.1a5.74 5.74 0 0 1-4.1 1.7H5.81a5.74 5.74 0 0 1-4.1-1.7 5.74 5.74 0 0 1-1.7-4.1V5.85c0-1.61.65-3.04 1.7-4.1a5.8 5.8 0 0 1 4.1-1.7h58.72c.13-.05.27-.05.41-.05.64 0 1.29.28 1.75.69h.09c.09.05.14.09.23.18L97 31.23c.51.51.88 1.2.88 1.98 0 .23-.05.41-.09.65zM67.52 27.97V8.94l21.43 21.7H70.19c-.74 0-1.38-.32-1.89-.78-.46-.46-.78-1.15-.78-1.89" style="fill:#D1D5DB;fill-rule:evenodd;clip-rule:evenodd"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 115.28 122.88"><path d="M25.38 57h64.88V37.34H69.59c-2.17 0-5.19-1.17-6.62-2.6s-2.3-4.01-2.3-6.17V7.64H8.15c-.18 0-.32.09-.41.18-.15.1-.19.23-.19.42v106.45c0 .14.09.32.18.41.09.14.28.18.41.18h81.51c.18 0 .17-.09.27-.18.14-.09.33-.28.33-.41v-11.16H25.38c-4.14 0-7.56-3.4-7.56-7.56V64.55c0-4.15 3.4-7.55 7.56-7.55m4.11 11.38h7.43v18.15h11.63v5.92H29.49zm20.4 12.05c0-3.93 1.09-6.99 3.28-9.17 2.19-2.19 5.24-3.28 9.15-3.28 4.01 0 7.09 1.08 9.26 3.22 2.17 2.15 3.25 5.16 3.25 9.04 0 2.81-.47 5.11-1.42 6.91q-1.425 2.7-4.11 4.2t-6.69 1.5c-2.71 0-4.96-.43-6.74-1.29-1.78-.87-3.22-2.23-4.32-4.11-1.11-1.87-1.66-4.21-1.66-7.02m7.42.01c0 2.43.45 4.17 1.36 5.23s2.14 1.59 3.7 1.59c1.6 0 2.84-.52 3.71-1.56.88-1.04 1.32-2.9 1.32-5.6 0-2.26-.46-3.92-1.37-4.96-.92-1.05-2.16-1.57-3.73-1.57-1.5 0-2.71.53-3.62 1.59-.91 1.08-1.37 2.83-1.37 5.28m33.11 3.3v-5.01h11.49v10.23c-2.2 1.5-4.15 2.53-5.83 3.07-1.69.54-3.7.81-6.02.81-2.86 0-5.19-.49-6.99-1.46s-3.19-2.42-4.18-4.35c-.99-1.92-1.48-4.13-1.48-6.63 0-2.63.54-4.91 1.62-6.85s2.67-3.41 4.76-4.42c1.63-.78 3.83-1.17 6.58-1.17 2.66 0 4.64.24 5.96.72s2.41 1.23 3.28 2.24 1.52 2.3 1.96 3.85l-7.16 1.29c-.3-.91-.8-1.61-1.5-2.09-.71-.49-1.6-.73-2.7-.73-1.62 0-2.92.57-3.89 1.7s-1.45 2.92-1.45 5.37c0 2.6.49 4.46 1.47 5.57.97 1.11 2.34 1.68 4.09 1.68q1.245 0 2.37-.36c.75-.24 1.61-.65 2.59-1.22v-2.25h-4.97zM97.79 57h9.93c4.16 0 7.56 3.41 7.56 7.56v31.42c0 4.15-3.41 7.56-7.56 7.56h-9.93v13.55c0 1.61-.65 3.04-1.7 4.1a5.74 5.74 0 0 1-4.1 1.7H5.81a5.74 5.74 0 0 1-4.1-1.7 5.74 5.74 0 0 1-1.7-4.1V5.85c0-1.61.65-3.04 1.7-4.1a5.8 5.8 0 0 1 4.1-1.7h58.72c.13-.05.27-.05.41-.05.64 0 1.29.28 1.75.69h.09c.09.05.14.09.23.18L97 31.23c.51.51.88 1.2.88 1.98 0 .23-.05.41-.09.65zM67.52 27.97V8.94l21.43 21.7H70.19c-.74 0-1.38-.32-1.89-.78-.46-.46-.78-1.15-.78-1.89" style="fill:#7A8291;fill-rule:evenodd;clip-rule:evenodd"/></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#fff" viewBox="0 0 24 24"><title>Haystack</title><path d="M2.008 0C.9 0 0 .9 0 2.008v19.984C0 23.1.9 24 2.008 24h19.984C23.1 24 24 23.1 24 21.992V2.008C24 .9 23.1 0 21.992 0Zm9.963 3.84c3.43 0 6.21 2.763 6.21 6.17v6.488a.27.27 0 0 1-.27.268 2.423 2.423 0 0 1-2.43-2.414V10.01c0-1.927-1.572-3.488-3.51-3.488S8.547 8.085 8.547 10.01v1.608a.263.263 0 0 0 .259.268h1.54a.27.27 0 0 0 .275-.263V9.945c0-.74.604-1.341 1.35-1.341s1.35.6 1.35 1.341V20.03a.275.275 0 0 1-.28.268 2.41 2.41 0 0 1-2.42-2.404v-3.23a.275.275 0 0 0-.276-.269H8.811a.264.264 0 0 0-.264.263v1.08c0 1.333-1.175 2.414-2.517 2.414a.27.27 0 0 1-.27-.268v-7.872c0-3.408 2.78-6.171 6.21-6.171"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="#0E9A89" viewBox="0 0 24 24"><title>Haystack</title><path d="M2.008 0C.9 0 0 .9 0 2.008v19.984C0 23.1.9 24 2.008 24h19.984C23.1 24 24 23.1 24 21.992V2.008C24 .9 23.1 0 21.992 0Zm9.963 3.84c3.43 0 6.21 2.763 6.21 6.17v6.488a.27.27 0 0 1-.27.268 2.423 2.423 0 0 1-2.43-2.414V10.01c0-1.927-1.572-3.488-3.51-3.488S8.547 8.085 8.547 10.01v1.608a.263.263 0 0 0 .259.268h1.54a.27.27 0 0 0 .275-.263V9.945c0-.74.604-1.341 1.35-1.341s1.35.6 1.35 1.341V20.03a.275.275 0 0 1-.28.268 2.41 2.41 0 0 1-2.42-2.404v-3.23a.275.275 0 0 0-.276-.269H8.811a.264.264 0 0 0-.264.263v1.08c0 1.333-1.175 2.414-2.517 2.414a.27.27 0 0 1-.27-.268v-7.872c0-3.408 2.78-6.171 6.21-6.171"/></svg>

Before

Width:  |  Height:  |  Size: 707 B

After

Width:  |  Height:  |  Size: 710 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="154" height="250" preserveAspectRatio="xMidYMid" viewBox="0 0 256 416"><path d="M201.816 230.216c-16.186 0-30.697 7.171-40.634 18.461l-25.463-18.026c2.703-7.442 4.255-15.433 4.255-23.797 0-8.219-1.498-16.076-4.112-23.408l25.406-17.835c9.936 11.233 24.409 18.365 40.548 18.365 29.875 0 54.184-24.305 54.184-54.184s-24.309-54.184-54.184-54.184-54.184 24.305-54.184 54.184c0 5.348.808 10.505 2.258 15.389l-25.423 17.844c-10.62-13.175-25.911-22.374-43.333-25.182v-30.64c24.544-5.155 43.037-26.962 43.037-53.019C124.171 24.305 99.862 0 69.987 0S15.803 24.305 15.803 54.184c0 25.708 18.014 47.246 42.067 52.769v31.038C25.044 143.753 0 172.401 0 206.854c0 34.621 25.292 63.374 58.355 68.94v32.774c-24.299 5.341-42.552 27.011-42.552 52.894 0 29.879 24.309 54.184 54.184 54.184s54.184-24.305 54.184-54.184c0-25.883-18.253-47.553-42.552-52.894v-32.775a69.97 69.97 0 0 0 42.6-24.776l25.633 18.143c-1.423 4.84-2.22 9.946-2.22 15.24 0 29.879 24.309 54.184 54.184 54.184S256 314.279 256 284.4s-24.309-54.184-54.184-54.184m0-126.695c14.487 0 26.27 11.788 26.27 26.271s-11.783 26.27-26.27 26.27-26.27-11.787-26.27-26.27 11.783-26.271 26.27-26.271m-158.1-49.337c0-14.483 11.784-26.27 26.271-26.27s26.27 11.787 26.27 26.27-11.783 26.27-26.27 26.27-26.271-11.787-26.271-26.27m52.541 307.278c0 14.483-11.783 26.27-26.27 26.27s-26.271-11.787-26.271-26.27 11.784-26.27 26.271-26.27 26.27 11.787 26.27 26.27m-26.272-117.97c-20.205 0-36.642-16.434-36.642-36.638 0-20.205 16.437-36.642 36.642-36.642 20.204 0 36.641 16.437 36.641 36.642 0 20.204-16.437 36.638-36.641 36.638m131.831 67.179c-14.487 0-26.27-11.788-26.27-26.271s11.783-26.27 26.27-26.27 26.27 11.787 26.27 26.27-11.783 26.271-26.27 26.271" style="fill:#fff"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="154" height="250" preserveAspectRatio="xMidYMid" viewBox="0 0 256 416"><path d="M201.816 230.216c-16.186 0-30.697 7.171-40.634 18.461l-25.463-18.026c2.703-7.442 4.255-15.433 4.255-23.797 0-8.219-1.498-16.076-4.112-23.408l25.406-17.835c9.936 11.233 24.409 18.365 40.548 18.365 29.875 0 54.184-24.305 54.184-54.184s-24.309-54.184-54.184-54.184-54.184 24.305-54.184 54.184c0 5.348.808 10.505 2.258 15.389l-25.423 17.844c-10.62-13.175-25.911-22.374-43.333-25.182v-30.64c24.544-5.155 43.037-26.962 43.037-53.019C124.171 24.305 99.862 0 69.987 0S15.803 24.305 15.803 54.184c0 25.708 18.014 47.246 42.067 52.769v31.038C25.044 143.753 0 172.401 0 206.854c0 34.621 25.292 63.374 58.355 68.94v32.774c-24.299 5.341-42.552 27.011-42.552 52.894 0 29.879 24.309 54.184 54.184 54.184s54.184-24.305 54.184-54.184c0-25.883-18.253-47.553-42.552-52.894v-32.775a69.97 69.97 0 0 0 42.6-24.776l25.633 18.143c-1.423 4.84-2.22 9.946-2.22 15.24 0 29.879 24.309 54.184 54.184 54.184S256 314.279 256 284.4s-24.309-54.184-54.184-54.184m0-126.695c14.487 0 26.27 11.788 26.27 26.271s-11.783 26.27-26.27 26.27-26.27-11.787-26.27-26.27 11.783-26.271 26.27-26.271m-158.1-49.337c0-14.483 11.784-26.27 26.271-26.27s26.27 11.787 26.27 26.27-11.783 26.27-26.27 26.27-26.271-11.787-26.271-26.27m52.541 307.278c0 14.483-11.783 26.27-26.27 26.27s-26.271-11.787-26.271-26.27 11.784-26.27 26.271-26.27 26.27 11.787 26.27 26.27m-26.272-117.97c-20.205 0-36.642-16.434-36.642-36.638 0-20.205 16.437-36.642 36.642-36.642 20.204 0 36.641 16.437 36.641 36.642 0 20.204-16.437 36.638-36.641 36.638m131.831 67.179c-14.487 0-26.27-11.788-26.27-26.271s11.783-26.27 26.27-26.27 26.27 11.787 26.27 26.27-11.783 26.271-26.27 26.271" style="fill:#7A8291"/></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1,5 @@
<svg role="img" viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<g transform="translate(2.1186441,37.661017)">
<path d="m 237.70492,0 c 76.95771,0 139.34426,62.386551 139.34426,139.34426 v 0 l -1.8e-4,197.00774 65.57395,-1.5e-4 c 31.68847,0 57.37705,25.68858 57.37705,57.37705 v 0 V 443 h -7.54607 c -18.22527,0 -33.09496,-14.59276 -33.43754,-32.81482 v 0 -8.22465 l -0.003,-0.40664 c -0.21715,-13.39321 -11.14191,-24.18352 -24.58687,-24.18352 v 0 H 106.55738 C 47.707363,377.37037 0,329.66301 0,270.81299 v 0 -131.46873 C 0,62.386551 62.386551,0 139.34426,0 v 0 z m -8.19672,41.018518 h -81.96722 l -1.76212,0.01428 C 87.741593,41.97378 40.983607,89.314381 40.983607,147.5759 v 0 123.20218 l 0.0088,1.08438 c 0.579068,35.71525 29.711746,64.48939 65.564993,64.48939 v 0 h 163.9344 c 36.2154,0 65.57377,-29.35838 65.57377,-65.57377 v 0 -123.20218 l -0.0143,-1.76213 C 335.11031,87.776505 287.76971,41.018518 229.5082,41.018518 Z m -81.63935,65.629632 c 9.34426,0 16.72131,7.62944 16.72131,17.22778 v 0 49.96055 l 56.80328,-58.57444 c 7.37705,-6.89111 17.45902,-7.38334 24.59017,-0.73834 v 0 0.24611 c 6.88524,6.39889 6.39344,16.98167 -1.22951,23.87278 v 0 l -42.04918,43.31556 48.93442,69.89555 c 5.90164,8.61389 4.18033,19.44278 -3.68852,24.61111 -8.60656,4.92223 -18.44262,2.21501 -24.34426,-6.39888 v 0 l -44.0164,-64.48112 -15,15.75112 v 40.36222 c 0,9.84444 -7.37705,17.22778 -16.72131,17.22778 -9.34426,0 -16.72131,-7.38334 -16.72131,-17.22778 v 0 -137.82222 c 0,-9.59834 7.37705,-17.22778 16.72131,-17.22778 z" fill="#5C62B0" fill-rule="evenodd" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1 +1 @@
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>LangChain</title><path d="M8.373 14.502c.013-.06.024-.118.038-.17l.061.145c.115.28.229.557.506.714-.012.254-.334.357-.552.326-.048-.114-.115-.228-.255-.164-.143.056-.3-.01-.266-.185.333-.012.407-.371.468-.666zM18.385 9.245c-.318 0-.616.122-.839.342l-.902.887c-.243.24-.368.572-.343.913l.006.056c.032.262.149.498.337.682.13.128.273.21.447.266a.866.866 0 01-.247.777l-.056.055a2.022 2.022 0 01-1.355-1.555l-.01-.057-.046.037c-.03.024-.06.05-.088.078l-.902.887a1.156 1.156 0 000 1.65c.231.228.535.342.84.342.304 0 .607-.114.838-.341l.902-.888a1.156 1.156 0 00-.436-1.921.953.953 0 01.276-.842 2.062 2.062 0 011.371 1.57l.01.057.047-.037c.03-.024.06-.05.088-.078l.902-.888a1.155 1.155 0 000-1.65 1.188 1.188 0 00-.84-.342z" fill="#1C3C3C"></path><path clip-rule="evenodd" d="M17.901 6H6.1C2.736 6 0 8.692 0 12s2.736 6 6.099 6H17.9C21.264 18 24 15.308 24 12s-2.736-6-6.099-6zm-5.821 9.407c-.195.04-.414.047-.562-.106-.045.1-.136.077-.221.056a.797.797 0 00-.061-.014c-.01.025-.017.048-.026.073-.329.021-.575-.309-.732-.558a4.991 4.991 0 00-.473-.21c-.172-.07-.345-.14-.509-.23a2.218 2.218 0 00-.004.173c-.002.244-.004.503-.227.651-.007.295.236.292.476.29.207-.003.41-.005.447.184a.485.485 0 01-.05.003c-.046 0-.092 0-.127.034-.117.111-.242.063-.372.013-.12-.046-.243-.094-.367-.02a2.318 2.318 0 00-.262.154.97.97 0 01-.548.194c-.024-.036-.014-.059.006-.08a.562.562 0 00.043-.056c.019-.028.035-.057.051-.084.054-.095.103-.18.242-.22-.185-.029-.344.055-.5.137l-.004.002a4.21 4.21 0 01-.065.034c-.097.04-.154.009-.212-.023-.082-.045-.168-.092-.376.04-.04-.032-.02-.061.002-.086.091-.109.21-.125.345-.119-.351-.193-.604-.056-.81.055-.182.098-.327.176-.471-.012-.065.017-.102.063-.138.108-.015.02-.03.038-.047.055-.035-.039-.027-.083-.018-.128l.005-.026a.242.242 0 00.003-.03l-.027-.01c-.053-.022-.105-.044-.09-.124-.117-.04-.2.03-.286.094-.054-.041-.01-.095.032-.145a.279.279 0 00.045-.065c.038-.065.103-.067.166-.069.054-.001.108-.003.145-.042.133-.075.297-.036.462.003.121.028.242.057.354.042.203.025.454-.18.352-.385-.186-.233-.184-.528-.183-.813v-.143c-.016-.108-.172-.233-.328-.358-.12-.095-.24-.191-.298-.28-.16-.177-.285-.382-.409-.585l-.015-.024c-.212-.404-.297-.86-.382-1.315-.103-.546-.205-1.09-.526-1.54-.266.144-.612.075-.841-.118-.12.107-.13.247-.138.396l-.001.014c-.297-.292-.26-.844-.023-1.17.097-.128.213-.233.342-.326.03-.021.04-.042.039-.074.235-1.04 1.836-.839 2.342-.103.167.206.281.442.395.678.137.283.273.566.5.795.22.237.452.463.684.689.359.35.718.699 1.032 1.089.49.587.839 1.276 1.144 1.97.05.092.08.193.11.293.044.15.089.299.2.417.026.035.084.088.149.148.156.143.357.328.289.409.009.019.027.04.05.06.032.028.074.058.116.088.122.087.25.178.16.25zm7.778-3.545l-.902.887c-.24.237-.537.413-.859.51l-.017.005-.006.015A2.021 2.021 0 0117.6 14l-.902.888c-.393.387-.916.6-1.474.6-.557 0-1.08-.213-1.474-.6a2.03 2.03 0 010-2.9l.902-.888c.242-.238.531-.409.859-.508l.016-.004.006-.016c.105-.272.265-.516.475-.724l.902-.887c.393-.387.917-.6 1.474-.6.558 0 1.08.213 1.474.6.394.387.61.902.61 1.45 0 .549-.216 1.064-.61 1.45v.001z" fill="#1C3C3C" fill-rule="evenodd"></path></svg>
<svg height="1em" style="flex:none;line-height:1" viewBox="0 0 24 24" width="1em" xmlns="http://www.w3.org/2000/svg"><title>LangChain</title><path d="M8.373 14.502c.013-.06.024-.118.038-.17l.061.145c.115.28.229.557.506.714-.012.254-.334.357-.552.326-.048-.114-.115-.228-.255-.164-.143.056-.3-.01-.266-.185.333-.012.407-.371.468-.666zM18.385 9.245c-.318 0-.616.122-.839.342l-.902.887c-.243.24-.368.572-.343.913l.006.056c.032.262.149.498.337.682.13.128.273.21.447.266a.866.866 0 01-.247.777l-.056.055a2.022 2.022 0 01-1.355-1.555l-.01-.057-.046.037c-.03.024-.06.05-.088.078l-.902.887a1.156 1.156 0 000 1.65c.231.228.535.342.84.342.304 0 .607-.114.838-.341l.902-.888a1.156 1.156 0 00-.436-1.921.953.953 0 01.276-.842 2.062 2.062 0 011.371 1.57l.01.057.047-.037c.03-.024.06-.05.088-.078l.902-.888a1.155 1.155 0 000-1.65 1.188 1.188 0 00-.84-.342z" fill="#3B8686"></path><path clip-rule="evenodd" d="M17.901 6H6.1C2.736 6 0 8.692 0 12s2.736 6 6.099 6H17.9C21.264 18 24 15.308 24 12s-2.736-6-6.099-6zm-5.821 9.407c-.195.04-.414.047-.562-.106-.045.1-.136.077-.221.056a.797.797 0 00-.061-.014c-.01.025-.017.048-.026.073-.329.021-.575-.309-.732-.558a4.991 4.991 0 00-.473-.21c-.172-.07-.345-.14-.509-.23a2.218 2.218 0 00-.004.173c-.002.244-.004.503-.227.651-.007.295.236.292.476.29.207-.003.41-.005.447.184a.485.485 0 01-.05.003c-.046 0-.092 0-.127.034-.117.111-.242.063-.372.013-.12-.046-.243-.094-.367-.02a2.318 2.318 0 00-.262.154.97.97 0 01-.548.194c-.024-.036-.014-.059.006-.08a.562.562 0 00.043-.056c.019-.028.035-.057.051-.084.054-.095.103-.18.242-.22-.185-.029-.344.055-.5.137l-.004.002a4.21 4.21 0 01-.065.034c-.097.04-.154.009-.212-.023-.082-.045-.168-.092-.376.04-.04-.032-.02-.061.002-.086.091-.109.21-.125.345-.119-.351-.193-.604-.056-.81.055-.182.098-.327.176-.471-.012-.065.017-.102.063-.138.108-.015.02-.03.038-.047.055-.035-.039-.027-.083-.018-.128l.005-.026a.242.242 0 00.003-.03l-.027-.01c-.053-.022-.105-.044-.09-.124-.117-.04-.2.03-.286.094-.054-.041-.01-.095.032-.145a.279.279 0 00.045-.065c.038-.065.103-.067.166-.069.054-.001.108-.003.145-.042.133-.075.297-.036.462.003.121.028.242.057.354.042.203.025.454-.18.352-.385-.186-.233-.184-.528-.183-.813v-.143c-.016-.108-.172-.233-.328-.358-.12-.095-.24-.191-.298-.28-.16-.177-.285-.382-.409-.585l-.015-.024c-.212-.404-.297-.86-.382-1.315-.103-.546-.205-1.09-.526-1.54-.266.144-.612.075-.841-.118-.12.107-.13.247-.138.396l-.001.014c-.297-.292-.26-.844-.023-1.17.097-.128.213-.233.342-.326.03-.021.04-.042.039-.074.235-1.04 1.836-.839 2.342-.103.167.206.281.442.395.678.137.283.273.566.5.795.22.237.452.463.684.689.359.35.718.699 1.032 1.089.49.587.839 1.276 1.144 1.97.05.092.08.193.11.293.044.15.089.299.2.417.026.035.084.088.149.148.156.143.357.328.289.409.009.019.027.04.05.06.032.028.074.058.116.088.122.087.25.178.16.25zm7.778-3.545l-.902.887c-.24.237-.537.413-.859.51l-.017.005-.006.015A2.021 2.021 0 0117.6 14l-.902.888c-.393.387-.916.6-1.474.6-.557 0-1.08-.213-1.474-.6a2.03 2.03 0 010-2.9l.902-.888c.242-.238.531-.409.859-.508l.016-.004.006-.016c.105-.272.265-.516.475-.724l.902-.887c.393-.387.917-.6 1.474-.6.558 0 1.08.213 1.474.6.394.387.61.902.61 1.45 0 .549-.216 1.064-.61 1.45v.001z" fill="#3B8686" fill-rule="evenodd"></path></svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@@ -0,0 +1,3 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M6.915 4.03c-1.968 0-3.683 1.28-4.871 3.113C.704 9.208 0 11.883 0 14.449c0 .706.07 1.369.21 1.973a6.624 6.624 0 0 0 .265.86 5.297 5.297 0 0 0 .371.761c.696 1.159 1.818 1.927 3.593 1.927 1.497 0 2.633-.671 3.965-2.444.76-1.012 1.144-1.626 2.663-4.32l.756-1.339.186-.325c.061.1.121.196.183.3l2.152 3.595c.724 1.21 1.665 2.556 2.47 3.314 1.046.987 1.992 1.22 3.06 1.22 1.075 0 1.876-.355 2.455-.843a3.743 3.743 0 0 0 .81-.973c.542-.939.861-2.127.861-3.745 0-2.72-.681-5.357-2.084-7.45-1.282-1.912-2.957-2.93-4.716-2.93-1.047 0-2.088.467-3.053 1.308-.652.57-1.257 1.29-1.82 2.05-.69-.875-1.335-1.547-1.958-2.056-1.182-.966-2.315-1.303-3.454-1.303zm10.16 2.053c1.147 0 2.188.758 2.992 1.999 1.132 1.748 1.647 4.195 1.647 6.4 0 1.548-.368 2.9-1.839 2.9-.58 0-1.027-.23-1.664-1.004-.496-.601-1.343-1.878-2.832-4.358l-.617-1.028a44.908 44.908 0 0 0-1.255-1.98c.07-.109.141-.224.211-.327 1.12-1.667 2.118-2.602 3.358-2.602zm-10.201.553c1.265 0 2.058.791 2.675 1.446.307.327.737.871 1.234 1.579l-1.02 1.566c-.757 1.163-1.882 3.017-2.837 4.338-1.191 1.649-1.81 1.817-2.486 1.817-.524 0-1.038-.237-1.383-.794-.263-.426-.464-1.13-.464-2.046 0-2.221.63-4.535 1.66-6.088.454-.687.964-1.226 1.533-1.533a2.264 2.264 0 0 1 1.088-.285z" fill="#0467DF" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,3 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M4.89 5.57 0 14.002l2.521 4.4h5.05l4.396-7.718 4.512 7.709 4.996.037L24 14.057l-4.857-8.452-5.073-.015-2.076 3.598L9.94 5.57Zm.837.729h3.787l1.845 3.252H7.572Zm9.189.021 3.803.012 4.228 7.355-3.736-.027zm-9.82.346L6.94 9.914l-4.209 7.389-1.892-3.3Zm9.187.014 4.297 7.343-1.892 3.282-4.3-7.344zm-6.713 3.6h3.79l-4.212 7.394H3.361Zm11.64 4.109 3.74.027-1.893 3.281-3.74-.027z" fill="#3E9C2A" />
</svg>

After

Width:  |  Height:  |  Size: 482 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#fff" viewBox="0 0 24 24"><title>Ollama</title><path d="M16.361 10.26a.9.9 0 0 0-.558.47l-.072.148.001.207c0 .193.004.217.059.353.076.193.152.312.291.448.24.238.51.3.872.205a.86.86 0 0 0 .517-.436.75.75 0 0 0 .08-.498c-.064-.453-.33-.782-.724-.897a1.1 1.1 0 0 0-.466 0m-9.203.005c-.305.096-.533.32-.65.639a1.2 1.2 0 0 0-.06.52c.057.309.31.59.598.667.362.095.632.033.872-.205.14-.136.215-.255.291-.448.055-.136.059-.16.059-.353l.001-.207-.072-.148a.9.9 0 0 0-.565-.472 1 1 0 0 0-.474.007m4.184 2c-.131.071-.223.25-.195.383.031.143.157.288.353.407.105.063.112.072.117.136.004.038-.01.146-.029.243-.02.094-.036.194-.036.222.002.074.07.195.143.253.064.052.076.054.255.059.164.005.198.001.264-.03.169-.082.212-.234.15-.525-.052-.243-.042-.28.087-.355.137-.08.281-.219.324-.314a.365.365 0 0 0-.175-.48.4.4 0 0 0-.181-.033c-.126 0-.207.03-.355.124l-.085.053-.053-.032c-.219-.13-.259-.145-.391-.143a.4.4 0 0 0-.193.032m.39-2.195c-.373.036-.475.05-.654.086a4.5 4.5 0 0 0-.951.328c-.94.46-1.589 1.226-1.787 2.114-.04.176-.045.234-.045.53 0 .294.005.357.043.524.264 1.16 1.332 2.017 2.714 2.173.3.033 1.596.033 1.896 0 1.11-.125 2.064-.727 2.493-1.571.114-.226.169-.372.22-.602.039-.167.044-.23.044-.523 0-.297-.005-.355-.045-.531-.288-1.29-1.539-2.304-3.072-2.497a7 7 0 0 0-.855-.031zm.645.937a3.3 3.3 0 0 1 1.44.514c.223.148.537.458.671.662.166.251.26.508.303.82.02.143.01.251-.043.482-.08.345-.332.705-.672.957a3 3 0 0 1-.689.348c-.382.122-.632.144-1.525.138-.582-.006-.686-.01-.853-.042q-.856-.16-1.35-.68c-.264-.28-.385-.535-.45-.946-.03-.192.025-.509.137-.776.136-.326.488-.73.836-.963.403-.269.934-.46 1.422-.512.187-.02.586-.02.773-.002m-5.503-11a1.65 1.65 0 0 0-.683.298C5.617.74 5.173 1.666 4.985 2.819c-.07.436-.119 1.04-.119 1.503 0 .544.064 1.24.155 1.721.02.107.031.202.023.208l-.187.152a5.3 5.3 0 0 0-.949 1.02 5.5 5.5 0 0 0-.94 2.339 6.6 6.6 0 0 0-.023 1.357c.091.78.325 1.438.727 2.04l.13.195-.037.064c-.269.452-.498 1.105-.605 1.732-.084.496-.095.629-.095 1.294 0 .67.009.803.088 1.266.095.555.288 1.143.503 1.534.071.128.243.393.264.407.007.003-.014.067-.046.141a7.4 7.4 0 0 0-.548 1.873 5 5 0 0 0-.071.991c0 .56.031.832.148 1.279L3.42 24h1.478l-.05-.091c-.297-.552-.325-1.575-.068-2.597.117-.472.25-.819.498-1.296l.148-.29v-.177c0-.165-.003-.184-.057-.293a.9.9 0 0 0-.194-.25 1.7 1.7 0 0 1-.385-.543c-.424-.92-.506-2.286-.208-3.451.124-.486.329-.918.544-1.154a.8.8 0 0 0 .223-.531c0-.195-.07-.355-.224-.522a3.14 3.14 0 0 1-.817-1.729c-.14-.96.114-2.005.69-2.834.563-.814 1.353-1.336 2.237-1.475.199-.033.57-.028.776.01.226.04.367.028.512-.041.179-.085.268-.19.374-.431.093-.215.165-.333.36-.576.234-.29.46-.489.822-.729.413-.27.884-.467 1.352-.561.17-.035.25-.04.569-.04s.398.005.569.04a4.07 4.07 0 0 1 1.914.997c.117.109.398.457.488.602.034.057.095.177.132.267.105.241.195.346.374.43.14.068.286.082.503.045.343-.058.607-.053.943.016 1.144.23 2.14 1.173 2.581 2.437.385 1.108.276 2.267-.296 3.153-.097.15-.193.27-.333.419-.301.322-.301.722-.001 1.053.493.539.801 1.866.708 3.036-.062.772-.26 1.463-.533 1.854a2 2 0 0 1-.224.258.9.9 0 0 0-.194.25c-.054.109-.057.128-.057.293v.178l.148.29c.248.476.38.823.498 1.295.253 1.008.231 2.01-.059 2.581a1 1 0 0 0-.044.098c0 .006.329.009.732.009h.73l.02-.074.036-.134c.019-.076.057-.3.088-.516a9 9 0 0 0 0-1.258c-.11-.875-.295-1.57-.597-2.226-.032-.074-.053-.138-.046-.141a1.4 1.4 0 0 0 .108-.152c.376-.569.607-1.284.724-2.228.031-.26.031-1.378 0-1.628-.083-.645-.182-1.082-.348-1.525a6 6 0 0 0-.329-.7l-.038-.064.131-.194c.402-.604.636-1.262.727-2.04a6.6 6.6 0 0 0-.024-1.358 5.5 5.5 0 0 0-.939-2.339 5.3 5.3 0 0 0-.95-1.02l-.186-.152a.7.7 0 0 1 .023-.208c.208-1.087.201-2.443-.017-3.503-.19-.924-.535-1.658-.98-2.082-.354-.338-.716-.482-1.15-.455-.996.059-1.8 1.205-2.116 3.01a7 7 0 0 0-.097.726c0 .036-.007.066-.015.066a1 1 0 0 1-.149-.078A4.86 4.86 0 0 0 12 3.03c-.832 0-1.687.243-2.456.698a1 1 0 0 1-.148.078c-.008 0-.015-.03-.015-.066a7 7 0 0 0-.097-.725C8.997 1.392 8.337.319 7.46.048a2 2 0 0 0-.585-.041Zm.293 1.402c.248.197.523.759.682 1.388.03.113.06.244.069.292.007.047.026.152.041.233.067.365.098.76.102 1.24l.002.475-.12.175-.118.178h-.278c-.324 0-.646.041-.954.124l-.238.06c-.033.007-.038-.003-.057-.144a8.4 8.4 0 0 1 .016-2.323c.124-.788.413-1.501.696-1.711.067-.05.079-.049.157.013m9.825-.012c.17.126.358.46.498.888.28.854.36 2.028.212 3.145-.019.14-.024.151-.057.144l-.238-.06a3.7 3.7 0 0 0-.954-.124h-.278l-.119-.178-.119-.175.002-.474c.004-.669.066-1.19.214-1.772.157-.623.434-1.185.68-1.382.078-.062.09-.063.159-.012"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="#7A8291" viewBox="0 0 24 24"><title>Ollama</title><path d="M16.361 10.26a.9.9 0 0 0-.558.47l-.072.148.001.207c0 .193.004.217.059.353.076.193.152.312.291.448.24.238.51.3.872.205a.86.86 0 0 0 .517-.436.75.75 0 0 0 .08-.498c-.064-.453-.33-.782-.724-.897a1.1 1.1 0 0 0-.466 0m-9.203.005c-.305.096-.533.32-.65.639a1.2 1.2 0 0 0-.06.52c.057.309.31.59.598.667.362.095.632.033.872-.205.14-.136.215-.255.291-.448.055-.136.059-.16.059-.353l.001-.207-.072-.148a.9.9 0 0 0-.565-.472 1 1 0 0 0-.474.007m4.184 2c-.131.071-.223.25-.195.383.031.143.157.288.353.407.105.063.112.072.117.136.004.038-.01.146-.029.243-.02.094-.036.194-.036.222.002.074.07.195.143.253.064.052.076.054.255.059.164.005.198.001.264-.03.169-.082.212-.234.15-.525-.052-.243-.042-.28.087-.355.137-.08.281-.219.324-.314a.365.365 0 0 0-.175-.48.4.4 0 0 0-.181-.033c-.126 0-.207.03-.355.124l-.085.053-.053-.032c-.219-.13-.259-.145-.391-.143a.4.4 0 0 0-.193.032m.39-2.195c-.373.036-.475.05-.654.086a4.5 4.5 0 0 0-.951.328c-.94.46-1.589 1.226-1.787 2.114-.04.176-.045.234-.045.53 0 .294.005.357.043.524.264 1.16 1.332 2.017 2.714 2.173.3.033 1.596.033 1.896 0 1.11-.125 2.064-.727 2.493-1.571.114-.226.169-.372.22-.602.039-.167.044-.23.044-.523 0-.297-.005-.355-.045-.531-.288-1.29-1.539-2.304-3.072-2.497a7 7 0 0 0-.855-.031zm.645.937a3.3 3.3 0 0 1 1.44.514c.223.148.537.458.671.662.166.251.26.508.303.82.02.143.01.251-.043.482-.08.345-.332.705-.672.957a3 3 0 0 1-.689.348c-.382.122-.632.144-1.525.138-.582-.006-.686-.01-.853-.042q-.856-.16-1.35-.68c-.264-.28-.385-.535-.45-.946-.03-.192.025-.509.137-.776.136-.326.488-.73.836-.963.403-.269.934-.46 1.422-.512.187-.02.586-.02.773-.002m-5.503-11a1.65 1.65 0 0 0-.683.298C5.617.74 5.173 1.666 4.985 2.819c-.07.436-.119 1.04-.119 1.503 0 .544.064 1.24.155 1.721.02.107.031.202.023.208l-.187.152a5.3 5.3 0 0 0-.949 1.02 5.5 5.5 0 0 0-.94 2.339 6.6 6.6 0 0 0-.023 1.357c.091.78.325 1.438.727 2.04l.13.195-.037.064c-.269.452-.498 1.105-.605 1.732-.084.496-.095.629-.095 1.294 0 .67.009.803.088 1.266.095.555.288 1.143.503 1.534.071.128.243.393.264.407.007.003-.014.067-.046.141a7.4 7.4 0 0 0-.548 1.873 5 5 0 0 0-.071.991c0 .56.031.832.148 1.279L3.42 24h1.478l-.05-.091c-.297-.552-.325-1.575-.068-2.597.117-.472.25-.819.498-1.296l.148-.29v-.177c0-.165-.003-.184-.057-.293a.9.9 0 0 0-.194-.25 1.7 1.7 0 0 1-.385-.543c-.424-.92-.506-2.286-.208-3.451.124-.486.329-.918.544-1.154a.8.8 0 0 0 .223-.531c0-.195-.07-.355-.224-.522a3.14 3.14 0 0 1-.817-1.729c-.14-.96.114-2.005.69-2.834.563-.814 1.353-1.336 2.237-1.475.199-.033.57-.028.776.01.226.04.367.028.512-.041.179-.085.268-.19.374-.431.093-.215.165-.333.36-.576.234-.29.46-.489.822-.729.413-.27.884-.467 1.352-.561.17-.035.25-.04.569-.04s.398.005.569.04a4.07 4.07 0 0 1 1.914.997c.117.109.398.457.488.602.034.057.095.177.132.267.105.241.195.346.374.43.14.068.286.082.503.045.343-.058.607-.053.943.016 1.144.23 2.14 1.173 2.581 2.437.385 1.108.276 2.267-.296 3.153-.097.15-.193.27-.333.419-.301.322-.301.722-.001 1.053.493.539.801 1.866.708 3.036-.062.772-.26 1.463-.533 1.854a2 2 0 0 1-.224.258.9.9 0 0 0-.194.25c-.054.109-.057.128-.057.293v.178l.148.29c.248.476.38.823.498 1.295.253 1.008.231 2.01-.059 2.581a1 1 0 0 0-.044.098c0 .006.329.009.732.009h.73l.02-.074.036-.134c.019-.076.057-.3.088-.516a9 9 0 0 0 0-1.258c-.11-.875-.295-1.57-.597-2.226-.032-.074-.053-.138-.046-.141a1.4 1.4 0 0 0 .108-.152c.376-.569.607-1.284.724-2.228.031-.26.031-1.378 0-1.628-.083-.645-.182-1.082-.348-1.525a6 6 0 0 0-.329-.7l-.038-.064.131-.194c.402-.604.636-1.262.727-2.04a6.6 6.6 0 0 0-.024-1.358 5.5 5.5 0 0 0-.939-2.339 5.3 5.3 0 0 0-.95-1.02l-.186-.152a.7.7 0 0 1 .023-.208c.208-1.087.201-2.443-.017-3.503-.19-.924-.535-1.658-.98-2.082-.354-.338-.716-.482-1.15-.455-.996.059-1.8 1.205-2.116 3.01a7 7 0 0 0-.097.726c0 .036-.007.066-.015.066a1 1 0 0 1-.149-.078A4.86 4.86 0 0 0 12 3.03c-.832 0-1.687.243-2.456.698a1 1 0 0 1-.148.078c-.008 0-.015-.03-.015-.066a7 7 0 0 0-.097-.725C8.997 1.392 8.337.319 7.46.048a2 2 0 0 0-.585-.041Zm.293 1.402c.248.197.523.759.682 1.388.03.113.06.244.069.292.007.047.026.152.041.233.067.365.098.76.102 1.24l.002.475-.12.175-.118.178h-.278c-.324 0-.646.041-.954.124l-.238.06c-.033.007-.038-.003-.057-.144a8.4 8.4 0 0 1 .016-2.323c.124-.788.413-1.501.696-1.711.067-.05.079-.049.157.013m9.825-.012c.17.126.358.46.498.888.28.854.36 2.028.212 3.145-.019.14-.024.151-.057.144l-.238-.06a3.7 3.7 0 0 0-.954-.124h-.278l-.119-.178-.119-.175.002-.474c.004-.669.066-1.19.214-1.772.157-.623.434-1.185.68-1.382.078-.062.09-.063.159-.012"/></svg>

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path fill="#fff" d="M44.559 19.646a11.957 11.957 0 0 0-1.028-9.822 12.094 12.094 0 0 0-13.026-5.802A11.962 11.962 0 0 0 21.485 0 12.097 12.097 0 0 0 9.95 8.373a11.964 11.964 0 0 0-7.997 5.8A12.097 12.097 0 0 0 3.44 28.356a11.957 11.957 0 0 0 1.028 9.822 12.094 12.094 0 0 0 13.026 5.802 11.953 11.953 0 0 0 9.02 4.02 12.096 12.096 0 0 0 11.54-8.379 11.964 11.964 0 0 0 7.997-5.8 12.099 12.099 0 0 0-1.491-14.177zM26.517 44.863a8.966 8.966 0 0 1-5.759-2.082 6.85 6.85 0 0 0 .284-.16L30.6 37.1c.49-.278.79-.799.786-1.361V22.265l4.04 2.332a.141.141 0 0 1 .078.111v11.16a9.006 9.006 0 0 1-8.987 8.995zM7.191 36.608a8.957 8.957 0 0 1-1.073-6.027c.071.042.195.119.284.17l9.558 5.52a1.556 1.556 0 0 0 1.57 0l11.67-6.738v4.665a.15.15 0 0 1-.057.124l-9.662 5.579a9.006 9.006 0 0 1-12.288-3.293zM4.675 15.744a8.966 8.966 0 0 1 4.682-3.943c0 .082-.005.228-.005.33v11.042a1.555 1.555 0 0 0 .785 1.359l11.669 6.736-4.04 2.333a.143.143 0 0 1-.136.012L7.967 28.03a9.006 9.006 0 0 1-3.293-12.284zm33.19 7.724L26.196 16.73l4.04-2.331a.143.143 0 0 1 .136-.012l9.664 5.579c4.302 2.485 5.776 7.989 3.29 12.29a8.991 8.991 0 0 1-4.68 3.943V24.827a1.553 1.553 0 0 0-.78-1.36zm4.02-6.051c-.07-.044-.195-.119-.283-.17l-9.558-5.52a1.556 1.556 0 0 0-1.57 0l-11.67 6.738V13.8a.15.15 0 0 1 .057-.124l9.662-5.574a8.995 8.995 0 0 1 13.36 9.315zm-25.277 8.315-4.04-2.333a.141.141 0 0 1-.079-.11v-11.16a8.997 8.997 0 0 1 14.753-6.91c-.073.04-.2.11-.283.161L17.4 10.9a1.552 1.552 0 0 0-.786 1.36l-.006 13.469zM18.803 21l5.198-3.002 5.197 3V27l-5.197 3-5.198-3z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48"><path fill="#7A8291" d="M44.559 19.646a11.957 11.957 0 0 0-1.028-9.822 12.094 12.094 0 0 0-13.026-5.802A11.962 11.962 0 0 0 21.485 0 12.097 12.097 0 0 0 9.95 8.373a11.964 11.964 0 0 0-7.997 5.8A12.097 12.097 0 0 0 3.44 28.356a11.957 11.957 0 0 0 1.028 9.822 12.094 12.094 0 0 0 13.026 5.802 11.953 11.953 0 0 0 9.02 4.02 12.096 12.096 0 0 0 11.54-8.379 11.964 11.964 0 0 0 7.997-5.8 12.099 12.099 0 0 0-1.491-14.177zM26.517 44.863a8.966 8.966 0 0 1-5.759-2.082 6.85 6.85 0 0 0 .284-.16L30.6 37.1c.49-.278.79-.799.786-1.361V22.265l4.04 2.332a.141.141 0 0 1 .078.111v11.16a9.006 9.006 0 0 1-8.987 8.995zM7.191 36.608a8.957 8.957 0 0 1-1.073-6.027c.071.042.195.119.284.17l9.558 5.52a1.556 1.556 0 0 0 1.57 0l11.67-6.738v4.665a.15.15 0 0 1-.057.124l-9.662 5.579a9.006 9.006 0 0 1-12.288-3.293zM4.675 15.744a8.966 8.966 0 0 1 4.682-3.943c0 .082-.005.228-.005.33v11.042a1.555 1.555 0 0 0 .785 1.359l11.669 6.736-4.04 2.333a.143.143 0 0 1-.136.012L7.967 28.03a9.006 9.006 0 0 1-3.293-12.284zm33.19 7.724L26.196 16.73l4.04-2.331a.143.143 0 0 1 .136-.012l9.664 5.579c4.302 2.485 5.776 7.989 3.29 12.29a8.991 8.991 0 0 1-4.68 3.943V24.827a1.553 1.553 0 0 0-.78-1.36zm4.02-6.051c-.07-.044-.195-.119-.283-.17l-9.558-5.52a1.556 1.556 0 0 0-1.57 0l-11.67 6.738V13.8a.15.15 0 0 1 .057-.124l9.662-5.574a8.995 8.995 0 0 1 13.36 9.315zm-25.277 8.315-4.04-2.333a.141.141 0 0 1-.079-.11v-11.16a8.997 8.997 0 0 1 14.753-6.91c-.073.04-.2.11-.283.161L17.4 10.9a1.552 1.552 0 0 0-.786 1.36l-.006 13.469zM18.803 21l5.198-3.002 5.197 3V27l-5.197 3-5.198-3z"/></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="#fff" viewBox="0 0 24 24"><title>OpenRouter</title><path d="M16.778 1.844v1.919q-.569-.026-1.138-.032-.708-.008-1.415.037c-1.93.126-4.023.728-6.149 2.237-2.911 2.066-2.731 1.95-4.14 2.75-.396.223-1.342.574-2.185.798-.841.225-1.753.333-1.751.333v4.229s.768.108 1.61.333c.842.224 1.789.575 2.185.799 1.41.798 1.228.683 4.14 2.75 2.126 1.509 4.22 2.11 6.148 2.236.88.058 1.716.041 2.555.005v1.918l7.222-4.168-7.222-4.17v2.176c-.86.038-1.611.065-2.278.021-1.364-.09-2.417-.357-3.979-1.465-2.244-1.593-2.866-2.027-3.68-2.508.889-.518 1.449-.906 3.822-2.59 1.56-1.109 2.614-1.377 3.978-1.466.667-.044 1.418-.017 2.278.02v2.176L24 6.014Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="#7A8291" viewBox="0 0 24 24"><title>OpenRouter</title><path d="M16.778 1.844v1.919q-.569-.026-1.138-.032-.708-.008-1.415.037c-1.93.126-4.023.728-6.149 2.237-2.911 2.066-2.731 1.95-4.14 2.75-.396.223-1.342.574-2.185.798-.841.225-1.753.333-1.751.333v4.229s.768.108 1.61.333c.842.224 1.789.575 2.185.799 1.41.798 1.228.683 4.14 2.75 2.126 1.509 4.22 2.11 6.148 2.236.88.058 1.716.041 2.555.005v1.918l7.222-4.168-7.222-4.17v2.176c-.86.038-1.611.065-2.278.021-1.364-.09-2.417-.357-3.979-1.465-2.244-1.593-2.866-2.027-3.68-2.508.889-.518 1.449-.906 3.822-2.59 1.56-1.109 2.614-1.377 3.978-1.466.667-.044 1.418-.017 2.278.02v2.176L24 6.014Z"/></svg>

Before

Width:  |  Height:  |  Size: 685 B

After

Width:  |  Height:  |  Size: 688 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.7 KiB

View File

@@ -0,0 +1,10 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<g fill="none" stroke="#A5300F" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round">
<path d="M17.4 7.7c0 4.6-4.7 4.9-4.7 8.6" />
<path d="M8 10.7c3.3 0 4.2 2.4 4.2 5.6" />
<circle cx="17.4" cy="4.6" r="3.1" fill="#FADDCD" />
<circle cx="4.9" cy="10.7" r="3.1" fill="#FADDCD" />
<rect x="7.9" y="16.3" width="9.6" height="6.6" rx="1.6" fill="#FADDCD" />
<path d="M11.3 18.6 9.9 19.9l1.4 1.3M14.1 18.6l1.4 1.3-1.4 1.3M13.1 18.3l-1.2 3.3" stroke-width="1.1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 571 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 1155 1000"><path fill="#fff" d="m577.3 0 577.4 1000H0z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 1155 1000"><path fill="#7A8291" d="m577.3 0 577.4 1000H0z"/></svg>

Before

Width:  |  Height:  |  Size: 128 B

After

Width:  |  Height:  |  Size: 131 B

View File

@@ -0,0 +1,4 @@
<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="m23.6 0-8.721 4.59L9.829 24h7.41z" fill="#30A2FF" />
<path d="M9.83 24V5.142H.4z" fill="#FDB515" />
</svg>

After

Width:  |  Height:  |  Size: 190 B

View File

@@ -1 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" fill="#fff" stroke="#fff" viewBox="0 0 24 24"><path d="M20.98 11.802a1 1 0 0 0-.738-.771l-6.86-1.716 2.537-5.921a1 1 0 0 0-.317-1.192.996.996 0 0 0-1.234.024l-11 9a1 1 0 0 0 .39 1.744l6.719 1.681-3.345 5.854A1 1 0 0 0 8 22a1 1 0 0 0 .6-.2l12-9a1 1 0 0 0 .38-.998z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" width="800" height="800" fill="#7A8291" stroke="#7A8291" viewBox="0 0 24 24"><path d="M20.98 11.802a1 1 0 0 0-.738-.771l-6.86-1.716 2.537-5.921a1 1 0 0 0-.317-1.192.996.996 0 0 0-1.234.024l-11 9a1 1 0 0 0 .39 1.744l6.719 1.681-3.345 5.854A1 1 0 0 0 8 22a1 1 0 0 0 .6-.2l12-9a1 1 0 0 0 .38-.998z"/></svg>

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 343 B

View File

@@ -0,0 +1,103 @@
import { useMutation } from 'react-query';
import { Button, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { createSubscription } from 'api/generated/services/subscriptions';
import type { CreateSubscription201 } from 'api/generated/services/sigNoz.schemas';
import { useNotifications } from 'hooks/useNotifications';
import AuthZTooltip from 'lib/authz/components/AuthZTooltip/AuthZTooltip';
import { SubscriptionCreatePermission } from 'lib/authz/hooks/useAuthZ/permissions/subscription.permissions';
import { CreditCard, X } from '@signozhq/icons';
import APIError from 'types/api/error';
import { getBaseUrl } from 'utils/basePath';
interface AddCreditCardModalProps {
open: boolean;
onClose: () => void;
onAddCreditCard?: () => void;
}
/**
* Shown to trial users who have not added a card, in place of chat support.
* Submitting creates the subscription and opens the returned billing URL.
*/
function AddCreditCardModal({
open,
onClose,
onAddCreditCard,
}: AddCreditCardModalProps): JSX.Element {
const { notifications } = useNotifications();
const handleBillingOnSuccess = (data: CreateSubscription201): void => {
if (data?.data?.redirectURL) {
const newTab = document.createElement('a');
newTab.href = data.data.redirectURL;
newTab.target = '_blank';
newTab.rel = 'noopener noreferrer';
newTab.click();
}
};
const handleBillingOnError = (error: APIError): void => {
notifications.error({
message: error.getErrorCode(),
description: error.getErrorMessage(),
});
};
const { mutate: updateCreditCard, isLoading: isLoadingBilling } = useMutation(
createSubscription,
{ onSuccess: handleBillingOnSuccess, onError: handleBillingOnError },
);
const handleAddCreditCard = (): void => {
onAddCreditCard?.();
updateCreditCard({ url: getBaseUrl() });
};
return (
<Modal
className="add-credit-card-modal"
title={<span className="title">Add Credit Card for Chat Support</span>}
open={open}
closable
onCancel={onClose}
destroyOnClose
footer={[
<Button
key="cancel"
onClick={onClose}
className="cancel-btn"
icon={<X size={16} />}
>
Cancel
</Button>,
<AuthZTooltip
key="submit"
checks={[SubscriptionCreatePermission]}
withPortal={false}
>
<Button
type="primary"
icon={<CreditCard size={16} />}
size="middle"
loading={isLoadingBilling}
disabled={isLoadingBilling}
onClick={handleAddCreditCard}
className="add-credit-card-btn"
>
Add Credit Card
</Button>
</AuthZTooltip>,
]}
>
<Typography.Text className="add-credit-card-text">
You&apos;re currently on <span className="highlight-text">Trial plan</span>.
Add a credit card to access SigNoz chat support to your workspace.
</Typography.Text>
</Modal>
);
}
AddCreditCardModal.defaultProps = { onAddCreditCard: undefined };
export default AddCreditCardModal;

View File

@@ -0,0 +1,9 @@
import { rest } from 'msw';
const SUBSCRIPTIONS = 'http://localhost/api/v1/subscriptions';
export const createSubscriptionHandlers = [
rest.post(SUBSCRIPTIONS, (_req, res, ctx) =>
res(ctx.status(200), ctx.json({ data: { redirectURL: '' } })),
),
];

View File

@@ -0,0 +1,57 @@
import { useState } from 'react';
import type { Meta, StoryObj } from '@storybook/react-vite';
import { Button } from '@signozhq/ui/button';
import { screen, userEvent, within } from 'storybook/test';
import { withCanvas } from '@/storybook/decorators/withCanvas';
import { createSubscriptionHandlers } from './AddCreditCardModal.stories.mocks';
import AddCreditCardModal from '../AddCreditCardModal';
/** Stands in for the surfaces that open it: the strip's Support button, and
* `LaunchChatSupport` in the custom domain and onboarding flows. */
function ModalFixture(): JSX.Element {
const [open, setOpen] = useState(false);
return (
<>
<Button
variant="solid"
color="primary"
size="md"
testId="open-add-credit-card"
onClick={(): void => setOpen(true)}
>
Contact support
</Button>
<AddCreditCardModal open={open} onClose={(): void => setOpen(false)} />
</>
);
}
const meta = {
title: 'Components/Add Credit Card Modal',
component: ModalFixture,
tags: ['play'],
decorators: [withCanvas({ maxWidth: 400 })],
parameters: {
msw: { handlers: createSubscriptionHandlers },
},
} satisfies Meta<typeof ModalFixture>;
export default meta;
type Story = StoryObj<typeof meta>;
/** What a trial user without a card sees in place of chat support. */
export const Default: Story = {
play: async ({ canvasElement }): Promise<void> => {
await userEvent.click(
within(canvasElement).getByTestId('open-add-credit-card'),
);
await screen.findByRole('dialog', {
name: /Add Credit Card for Chat Support/i,
});
},
};

View File

@@ -8,6 +8,10 @@
:global(.ant-breadcrumb-separator) {
color: var(--muted-foreground);
}
[data-slot='button'] {
padding: 0px;
}
}
.divider {

View File

@@ -1,9 +1,5 @@
.item {
--button-padding: 0;
--button-font-size: var(--periscope-font-size-base);
}
.itemLast {
color: var(--muted-foreground);
font-size: var(--periscope-font-size-base);
color: var(--button-secondary-label);
font-size: var(--button-font-size, var(--periscope-font-size-base));
line-height: var(--button-size-line-height, 16px);
}

View File

@@ -26,9 +26,9 @@ function BreadcrumbItem({
return (
<Button
variant="ghost"
size="md"
variant="link"
color="secondary"
className={styles.item}
onClick={(e: React.MouseEvent): void => {
if (!('route' in props) || !props.route) {
return;

View File

@@ -34,21 +34,23 @@ function ErrorEmptyState({
</div>
<div className={styles.actions}>
<Button
size="md"
variant="solid"
color="secondary"
prefix={<LifeBuoy size={14} />}
onClick={onContactSupport}
data-testid="error-contact-support-button"
testId="error-contact-support-button"
>
Contact Support
</Button>
{onRefresh && (
<Button
size="md"
variant="outlined"
color="secondary"
prefix={<RefreshCw size={14} />}
onClick={onRefresh}
data-testid="error-refresh-button"
testId="error-refresh-button"
>
Refresh
</Button>

View File

@@ -1,20 +1,32 @@
.labelColumn {
// Badges fill their wrapper; the wrapper, as the flex item, owns the cap.
--badge-max-width: 100%;
position: relative;
display: flex;
gap: 4px;
align-items: center;
overflow: hidden;
max-width: 100%;
width: 100%;
> * {
flex-shrink: 0;
max-width: 180px;
}
}
.labelBadge {
cursor: default;
font-size: 12px;
// Kept mounted so its width can still be measured.
.overflowed {
position: absolute;
visibility: hidden;
pointer-events: none;
}
--badge-display: inline;
max-width: 180px;
text-overflow: ellipsis;
// The only visible label truncates instead of pushing `+N` out of view.
.labelColumn > .shrinkable {
flex-shrink: 1;
min-width: 0;
}
.overflowTrigger {
@@ -22,11 +34,6 @@
cursor: pointer;
}
.overflowBadge {
cursor: pointer;
font-size: 12px;
}
.labelPopover {
display: flex;
flex-direction: column;

View File

@@ -1,13 +1,14 @@
import { TooltipProvider } from '@signozhq/ui/tooltip';
import { act, render, screen } from '@testing-library/react';
import LabelColumn from './LabelColumn';
let resizeCallback: ResizeObserverCallback | null = null;
const BADGE_WIDTH = 60;
let resizeCallbacks: ResizeObserverCallback[] = [];
class MockResizeObserver {
constructor(callback: ResizeObserverCallback) {
resizeCallback = callback;
resizeCallbacks.push(callback);
}
observe = jest.fn();
@@ -15,15 +16,23 @@ class MockResizeObserver {
disconnect = jest.fn();
}
function triggerResize(width: number): void {
if (resizeCallback) {
act(() => {
resizeCallback?.(
[{ contentRect: { width } } as ResizeObserverEntry],
{} as ResizeObserver,
);
// jsdom has no layout: every badge measures BADGE_WIDTH, the column `containerWidth`.
function mockLayout(containerWidth: number): void {
jest
.spyOn(HTMLElement.prototype, 'clientWidth', 'get')
.mockImplementation(function getClientWidth(this: HTMLElement) {
return this.dataset.testid === 'label-column' ? containerWidth : 0;
});
}
jest
.spyOn(HTMLElement.prototype, 'getBoundingClientRect')
.mockReturnValue({ width: BADGE_WIDTH } as DOMRect);
}
function triggerResize(containerWidth: number): void {
mockLayout(containerWidth);
act(() => {
resizeCallbacks.forEach((callback) => callback([], {} as ResizeObserver));
});
}
beforeAll(() => {
@@ -31,13 +40,14 @@ beforeAll(() => {
});
afterEach(() => {
resizeCallback = null;
resizeCallbacks = [];
jest.restoreAllMocks();
});
function renderWithProviders(
ui: React.ReactElement,
): ReturnType<typeof render> {
return render(<TooltipProvider>{ui}</TooltipProvider>);
return render(ui);
}
describe('LabelColumn', () => {
@@ -54,13 +64,10 @@ describe('LabelColumn', () => {
it('should truncate labels and show +N badge when container is narrow', () => {
const labels = ['env', 'service', 'region', 'team', 'owner', 'version'];
// 3 badges (180px) + overflow reserve (40px)
mockLayout(220);
renderWithProviders(<LabelColumn labels={labels} />);
// Simulate narrow container that fits ~3 badges
// Badge widths: env=37, service=65, region=58, team=44, owner=51, version=65
// 220px available = 3 badges (160px) + gaps (8px) + overflow (44px)
triggerResize(220);
// First 3 visible
expect(screen.getByTestId('label-tag-env')).toBeInTheDocument();
expect(screen.getByTestId('label-tag-service')).toBeInTheDocument();
@@ -93,19 +100,37 @@ describe('LabelColumn', () => {
expect(screen.getByTestId('label-tag-service')).toHaveTextContent('service');
});
it('should show overflow badge with remaining count when container is narrow', () => {
it('should update the overflow count when the container resizes', () => {
const labels = ['env', 'service', 'region', 'team', 'owner', 'version'];
mockLayout(220);
renderWithProviders(<LabelColumn labels={labels} />);
expect(screen.getByTestId('label-overflow-badge')).toHaveTextContent('+3');
// 2 badges (120px) + overflow reserve (40px)
triggerResize(160);
expect(screen.getByTestId('label-overflow-badge')).toHaveTextContent('+4');
triggerResize(1000);
expect(screen.queryByTestId('label-overflow-badge')).not.toBeInTheDocument();
});
it('should skip the overflow reserve when every label fits', () => {
const labels = ['env', 'service', 'region', 'team', 'owner', 'version'];
mockLayout(labels.length * BADGE_WIDTH);
renderWithProviders(<LabelColumn labels={labels} />);
// Simulate narrow container to trigger overflow (shows 3 labels)
// 220px fits first 3 badges before overflow
triggerResize(220);
expect(screen.queryByTestId('label-overflow-badge')).not.toBeInTheDocument();
});
// Overflow badge shows +3 (remaining labels)
const overflowBadge = screen.getByTestId('label-overflow-badge');
expect(overflowBadge).toBeInTheDocument();
expect(overflowBadge).toHaveTextContent('+3');
it('should keep one label visible when even that one does not fit', () => {
const labels = ['env', 'service'];
mockLayout(50);
renderWithProviders(<LabelColumn labels={labels} />);
expect(screen.getByTestId('label-overflow-badge')).toHaveTextContent('+1');
});
it('should render empty when no labels provided', () => {
@@ -126,11 +151,9 @@ describe('LabelColumn', () => {
it('should show all labels when container is wide enough', () => {
const labels = ['env', 'service', 'region', 'team', 'owner', 'version'];
mockLayout(1000);
renderWithProviders(<LabelColumn labels={labels} />);
// Simulate wide container
triggerResize(1000);
// All labels visible
labels.forEach((label) => {
expect(screen.getByTestId(`label-tag-${label}`)).toBeInTheDocument();

View File

@@ -1,35 +1,19 @@
import { Copy } from '@signozhq/icons';
import { Badge } from '@signozhq/ui/badge';
import { Badge, type BadgeColorType } from '@signozhq/ui/badge';
import { toast } from '@signozhq/ui/sonner';
import {
TooltipContent,
TooltipRoot,
TooltipTrigger,
} from '@signozhq/ui/tooltip';
import { useCallback, useEffect, useRef, useState } from 'react';
import { Tooltip } from '@signozhq/ui/tooltip';
import cx from 'classnames';
import { useLayoutEffect, useRef, useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import LabelTag from './LabelTag';
import styles from './LabelColumn.module.scss';
import { BADGE_GAP, estimateBadgeWidth, OVERFLOW_BADGE_WIDTH } from './utils';
import { getVisibleCount } from './utils';
export interface LabelColumnProps {
labels: string[];
color?:
| 'primary'
| 'secondary'
| 'success'
| 'error'
| 'warning'
| 'robin'
| 'forest'
| 'amber'
| 'sienna'
| 'cherry'
| 'sakura'
| 'aqua'
| 'vanilla';
color?: BadgeColorType;
value?: { [key: string]: string };
}
@@ -39,60 +23,37 @@ function LabelColumn({
color = 'primary',
}: LabelColumnProps): JSX.Element {
const containerRef = useRef<HTMLDivElement>(null);
const [maxVisibleCount, setMaxVisibleCount] = useState(labels.length);
const [visibleCount, setVisibleCount] = useState(labels.length);
const [, copyToClipboard] = useCopyToClipboard();
const calculateMaxVisible = useCallback(
(width: number): number => {
if (width <= 0) {
return 1;
}
const availableWidth = width - OVERFLOW_BADGE_WIDTH - BADGE_GAP;
let usedWidth = 0;
let count = 0;
for (const label of labels) {
const badgeWidth = estimateBadgeWidth(label, value?.[label]) + BADGE_GAP;
if (usedWidth + badgeWidth > availableWidth && count > 0) {
break;
}
usedWidth += badgeWidth;
count++;
}
return Math.max(1, count);
},
[labels, value],
);
useEffect(() => {
useLayoutEffect(() => {
const container = containerRef.current;
if (!container) {
return;
}
const observer = new ResizeObserver((entries) => {
const entry = entries[0];
if (entry && entry.contentRect.width > 0) {
setMaxVisibleCount(calculateMaxVisible(entry.contentRect.width));
const measure = (): void => {
const available = container.clientWidth;
if (available <= 0) {
return;
}
});
const widths = Array.from(container.children)
.slice(0, labels.length)
.map((item) => item.getBoundingClientRect().width);
const gap = parseFloat(getComputedStyle(container).columnGap) || 0;
setVisibleCount(getVisibleCount(widths, available, gap));
};
const observer = new ResizeObserver(measure);
observer.observe(container);
if (container.clientWidth > 0) {
setMaxVisibleCount(calculateMaxVisible(container.clientWidth));
}
measure();
return (): void => observer.disconnect();
}, [calculateMaxVisible]);
}, [labels, value]);
const needsOverflow = labels.length > maxVisibleCount;
const visibleLabels = needsOverflow
? labels.slice(0, maxVisibleCount)
: labels;
const remainingLabels = needsOverflow ? labels.slice(maxVisibleCount) : [];
const remainingLabels = labels.slice(visibleCount);
return (
<div
@@ -100,24 +61,23 @@ function LabelColumn({
className={styles.labelColumn}
data-testid="label-column"
>
{visibleLabels.map((label) => (
<LabelTag key={label} label={label} color={color} value={value?.[label]} />
{labels.map((label, index) => (
<LabelTag
key={label}
label={label}
color={color}
value={value?.[label]}
className={cx({
[styles.overflowed]: index >= visibleCount,
[styles.shrinkable]: index === 0 && visibleCount === 1,
})}
/>
))}
{remainingLabels.length > 0 && (
<TooltipRoot>
<TooltipTrigger asChild>
<span>
<Badge
color={color}
className={styles.overflowBadge}
variant="outline"
data-testid="label-overflow-badge"
>
+{remainingLabels.length}
</Badge>
</span>
</TooltipTrigger>
<TooltipContent side="bottom" align="end">
<Tooltip
side="bottom"
align="end"
title={
<div className={styles.tooltipContent}>
<span>
{remainingLabels
@@ -140,8 +100,14 @@ function LabelColumn({
<Copy size={12} />
</button>
</div>
</TooltipContent>
</TooltipRoot>
}
>
<span>
<Badge color={color} variant="outlined" testId="label-overflow-badge">
+{remainingLabels.length}
</Badge>
</span>
</Tooltip>
)}
</div>
);

View File

@@ -1,11 +1,3 @@
.labelBadge {
cursor: default;
font-size: 12px;
max-width: 180px;
text-overflow: ellipsis;
}
.labelValue {
text-overflow: ellipsis;
overflow: hidden;

View File

@@ -1,35 +1,24 @@
import { Copy } from '@signozhq/icons';
import { Badge } from '@signozhq/ui/badge';
import { Badge, type BadgeColorType } from '@signozhq/ui/badge';
import { toast } from '@signozhq/ui/sonner';
import {
TooltipContent,
TooltipRoot,
TooltipTrigger,
} from '@signozhq/ui/tooltip';
import { Tooltip } from '@signozhq/ui/tooltip';
import { useCopyToClipboard } from 'react-use';
import styles from './LabelTag.module.scss';
export interface LabelTagProps {
label: string;
color?:
| 'primary'
| 'secondary'
| 'success'
| 'error'
| 'warning'
| 'robin'
| 'forest'
| 'amber'
| 'sienna'
| 'cherry'
| 'sakura'
| 'aqua'
| 'vanilla';
color?: BadgeColorType;
value?: string;
className?: string;
}
function LabelTag({ label, value, color }: LabelTagProps): JSX.Element {
function LabelTag({
label,
value,
color,
className,
}: LabelTagProps): JSX.Element {
const [, copyToClipboard] = useCopyToClipboard();
const displayText = value ? `${label}: ${value}` : label;
const searchFormat = value ? `${label} ${value}` : label;
@@ -41,20 +30,8 @@ function LabelTag({ label, value, color }: LabelTagProps): JSX.Element {
};
return (
<TooltipRoot>
<TooltipTrigger asChild>
<span>
<Badge
color={color}
className={styles.labelBadge}
variant="outline"
data-testid={`label-tag-${label}`}
>
<span className={styles.labelValue}>{displayText}</span>
</Badge>
</span>
</TooltipTrigger>
<TooltipContent>
<Tooltip
title={
<div className={styles.tooltipContent}>
<span>{displayText}</span>
<button
@@ -66,8 +43,19 @@ function LabelTag({ label, value, color }: LabelTagProps): JSX.Element {
<Copy size={12} />
</button>
</div>
</TooltipContent>
</TooltipRoot>
}
>
<span className={className}>
<Badge
textTransform="none"
color={color ?? 'secondary'}
variant="outlined"
testId={`label-tag-${label}`}
>
<span className={styles.labelValue}>{displayText}</span>
</Badge>
</span>
</Tooltip>
);
}

View File

@@ -1,14 +1,33 @@
export const BADGE_GAP = 4;
export const OVERFLOW_BADGE_WIDTH = 40;
export const BADGE_MAX_WIDTH = 180;
export const BADGE_PADDING = 16;
export const CHAR_WIDTH = 7;
export function estimateBadgeWidth(label: string, value?: string): number {
const displayText = value ? `${label}: ${value}` : label;
return Math.min(
displayText.length * CHAR_WIDTH + BADGE_PADDING,
BADGE_MAX_WIDTH,
/**
* How many leading labels fit in `available` px, reserving room for the `+N` badge
* whenever some are left out. At least one label is always shown.
*/
export function getVisibleCount(
widths: number[],
available: number,
gap: number,
): number {
const total = widths.reduce(
(sum, width, index) => sum + width + (index > 0 ? gap : 0),
0,
);
if (total <= available) {
return widths.length;
}
const limit = available - OVERFLOW_BADGE_WIDTH - gap;
let used = 0;
let count = 0;
for (const width of widths) {
used += width + (count > 0 ? gap : 0);
if (used > limit) {
break;
}
count++;
}
return Math.max(1, count);
}

View File

@@ -30,21 +30,23 @@ function NoResultsEmptyState({
<div className={styles.actions}>
{onClear && (
<Button
size="md"
variant="outlined"
color="secondary"
onClick={onClear}
data-testid="no-results-clear-button"
testId="no-results-clear-button"
>
{clearButtonText}
</Button>
)}
{onRefresh && (
<Button
size="md"
variant="outlined"
color="secondary"
prefix={<RefreshCw size={14} />}
onClick={onRefresh}
data-testid="no-results-refresh-button"
testId="no-results-refresh-button"
>
Refresh
</Button>

View File

@@ -1,4 +1,4 @@
import type { BadgeColor } from '@signozhq/ui/badge';
import type { BadgeColorType } from '@signozhq/ui/badge';
export const STATE_ORDER = ['firing', 'pending', 'inactive', 'disabled'];
export const SEVERITY_ORDER = ['critical', 'error', 'warning', 'info'];
@@ -24,9 +24,9 @@ export const SEVERITY_COLORS: Record<string, string> = {
info: 'var(--bg-robin-500)',
};
export const SEVERITY_BADGE_COLORS: Record<string, BadgeColor> = {
critical: 'error',
error: 'error',
export const SEVERITY_BADGE_COLORS: Record<string, BadgeColorType> = {
critical: 'danger',
error: 'danger',
warning: 'warning',
info: 'primary',
};

View File

@@ -33,36 +33,3 @@
color: var(--l1-foreground);
white-space: nowrap;
}
.auth-header-help-button {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
height: 32px;
padding: 10px 16px;
background: var(--l2-background);
color: var(--l2-foreground);
border: none;
border-radius: 2px;
cursor: pointer;
transition: opacity 0.2s ease;
span {
font-family: var(--font-family-inter, Inter, sans-serif);
font-size: 11px;
font-weight: 500;
line-height: 1;
color: var(--l2-foreground);
text-align: center;
}
svg {
flex-shrink: 0;
color: var(--l2-foreground);
}
&:hover {
opacity: 0.8;
}
}

View File

@@ -22,11 +22,11 @@ function AuthHeader(): JSX.Element {
<span className="auth-header-logo-text">SigNoz</span>
</div>
<Button
className="auth-header-help-button"
size="md"
prefix={<LifeBuoy size={12} />}
onClick={handleGetHelp}
variant="solid"
color="none"
color="secondary"
>
Get Help
</Button>

View File

@@ -1,7 +1,7 @@
import React, { Dispatch, SetStateAction, useState } from 'react';
import { Check, Plus, X } from '@signozhq/icons';
import { Button, Flex } from 'antd';
import { Badge } from '@signozhq/ui/badge';
import { Pill } from '@signozhq/ui/pill';
import Input from 'components/Input';
import './Badges.styles.scss';
@@ -47,18 +47,13 @@ function Badges({ tags, setTags }: AddTagsProps): JSX.Element {
return (
<div className="tags-container">
{tags.map<React.ReactNode>((tag) => (
<Badge
<Pill.Closeable
textTransform="none"
key={tag}
color="vanilla"
style={{ userSelect: 'none' }}
closable
onClose={(e): void => {
e.preventDefault();
handleClose(tag);
}}
onClose={() => handleClose(tag)}
>
{tag}
</Badge>
</Pill.Closeable>
))}
{inputVisible && (

View File

@@ -1,63 +1,15 @@
import { useState } from 'react';
import { useMutation } from 'react-query';
import { useLocation } from 'react-router-dom';
import { Button, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { Button } from 'antd';
import AddCreditCardModal from 'components/AddCreditCardModal/AddCreditCardModal';
import logEvent from 'api/common/logEvent';
import { createSubscription } from 'api/generated/services/subscriptions';
import type { CreateSubscription201 } from 'api/generated/services/sigNoz.schemas';
import { useNotifications } from 'hooks/useNotifications';
import AuthZTooltip from 'lib/authz/components/AuthZTooltip/AuthZTooltip';
import { SubscriptionCreatePermission } from 'lib/authz/hooks/useAuthZ/permissions/subscription.permissions';
import { CreditCard, MessageSquareText, X } from '@signozhq/icons';
import APIError from 'types/api/error';
import { getBaseUrl } from 'utils/basePath';
import { MessageSquareText } from '@signozhq/icons';
export default function ChatSupportGateway(): JSX.Element {
const { notifications } = useNotifications();
const [isAddCreditCardModalOpen, setIsAddCreditCardModalOpen] =
useState(false);
const handleBillingOnSuccess = (data: CreateSubscription201): void => {
if (data?.data?.redirectURL) {
const newTab = document.createElement('a');
newTab.href = data.data.redirectURL;
newTab.target = '_blank';
newTab.rel = 'noopener noreferrer';
newTab.click();
}
};
const handleBillingOnError = (error: APIError): void => {
notifications.error({
message: error.getErrorCode(),
description: error.getErrorMessage(),
});
};
const { mutate: updateCreditCard, isLoading: isLoadingBilling } = useMutation(
createSubscription,
{
onSuccess: (data) => {
handleBillingOnSuccess(data);
},
onError: handleBillingOnError,
},
);
const { pathname } = useLocation();
const handleAddCreditCard = (): void => {
logEvent('Add Credit card modal: Clicked', {
source: `chat support icon`,
page: pathname,
});
updateCreditCard({
url: getBaseUrl(),
});
};
return (
<>
<div className="chat-support-gateway">
@@ -76,47 +28,16 @@ export default function ChatSupportGateway(): JSX.Element {
</Button>
</div>
{/* Add Credit Card Modal */}
<Modal
className="add-credit-card-modal"
title={<span className="title">Add Credit Card for Chat Support</span>}
<AddCreditCardModal
open={isAddCreditCardModalOpen}
closable
onCancel={(): void => setIsAddCreditCardModalOpen(false)}
destroyOnClose
footer={[
<Button
key="cancel"
onClick={(): void => setIsAddCreditCardModalOpen(false)}
className="cancel-btn"
icon={<X size={16} />}
>
Cancel
</Button>,
<AuthZTooltip
key="submit"
checks={[SubscriptionCreatePermission]}
withPortal={false}
>
<Button
type="primary"
icon={<CreditCard size={16} />}
size="middle"
loading={isLoadingBilling}
disabled={isLoadingBilling}
onClick={handleAddCreditCard}
className="add-credit-card-btn"
>
Add Credit Card
</Button>
</AuthZTooltip>,
]}
>
<Typography.Text className="add-credit-card-text">
You&apos;re currently on <span className="highlight-text">Trial plan</span>
. Add a credit card to access SigNoz chat support to your workspace.
</Typography.Text>
</Modal>
onClose={(): void => setIsAddCreditCardModalOpen(false)}
onAddCreditCard={(): void => {
logEvent('Add Credit card modal: Clicked', {
source: `chat support icon`,
page: pathname,
});
}}
/>
</>
);
}

View File

@@ -39,9 +39,3 @@
}
}
}
.cloud-service-data-collected-table-tooltip {
max-width: 280px;
white-space: normal;
word-break: break-word;
}

View File

@@ -4,7 +4,7 @@ import {
CloudintegrationtypesCollectedMetricDTO,
} from 'api/generated/services/sigNoz.schemas';
import { BarChart, Info, ScrollText } from '@signozhq/icons';
import { TooltipProvider, TooltipSimple } from '@signozhq/ui/tooltip';
import { Tooltip } from '@signozhq/ui/tooltip';
import './CloudServiceDataCollected.styles.scss';
@@ -88,23 +88,15 @@ function CloudServiceDataCollected({
<BarChart size={14} />
Metrics
{metricsInfoTooltip && (
<TooltipProvider>
<TooltipSimple
title={metricsInfoTooltip}
side="top"
tooltipContentProps={{
className: 'cloud-service-data-collected-table-tooltip',
}}
<Tooltip title={metricsInfoTooltip} side="top">
<span
className="cloud-service-data-collected-table-heading-info"
aria-label="About the metrics listed below"
data-testid="data-collected-metrics-info"
>
<span
className="cloud-service-data-collected-table-heading-info"
aria-label="About the metrics listed below"
data-testid="data-collected-metrics-info"
>
<Info size={12} />
</span>
</TooltipSimple>
</TooltipProvider>
<Info size={12} />
</span>
</Tooltip>
)}
</div>
<Table

View File

@@ -2,6 +2,13 @@
position: relative;
}
.copyButton {
position: absolute;
right: 8px;
top: 8px;
z-index: 1;
}
.codeBlockSyntaxHighlighter {
background-color: var(--l2-background) !important;
border-radius: 4px !important;

View File

@@ -2,6 +2,7 @@ import { useMemo, useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import { Check, Copy } from '@signozhq/icons';
import { Button } from '@signozhq/ui/button';
import { Tooltip } from '@signozhq/ui/tooltip';
import SyntaxHighlighter, {
a11yDark,
} from 'components/MarkdownRenderer/syntaxHighlighter';
@@ -52,16 +53,20 @@ function CodeBlock({
data-testid="code-block-container"
>
{showCopyButton ? (
<Button
variant="ghost"
color="secondary"
size="sm"
onClick={handleCopy}
prefix={isCopied ? <Check size={14} /> : <Copy size={14} />}
aria-label="Copy code"
title={isCopied ? 'Copied' : 'Copy'}
style={{ position: 'absolute', right: 8, top: 8, zIndex: 1 }}
/>
<div className={styles.copyButton}>
<Tooltip title={isCopied ? 'Copied' : 'Copy'}>
<Button
variant="ghost"
color="secondary"
size="sm"
icon
onClick={handleCopy}
aria-label="Copy code"
>
{isCopied ? <Check size={14} /> : <Copy size={14} />}
</Button>
</Tooltip>
</div>
) : null}
<SyntaxHighlighter
style={a11yDark}

View File

@@ -134,26 +134,27 @@ function CreateServiceAccountModal(): JSX.Element {
<DialogFooter className="create-sa-modal__footer">
<Button
size="md"
type="button"
variant="solid"
color="secondary"
onClick={handleClose}
data-testid="create-sa-cancel-btn"
testId="create-sa-cancel-btn"
prefix={<X size={12} />}
>
<X size={12} />
Cancel
</Button>
<AuthZButton
size="md"
checks={[SACreatePermission]}
withPortal={false}
type="submit"
form="create-sa-form"
variant="solid"
color="primary"
loading={isSubmitting}
disabled={!isValid}
data-testid="create-sa-submit-btn"
testId="create-sa-submit-btn"
>
Create Service Account
</AuthZButton>

View File

@@ -5,6 +5,7 @@ import {
} from 'lib/authz/utils/authz-test-utils';
import { rest, server } from 'mocks-server/server';
import { NuqsTestingAdapter } from 'nuqs/adapters/testing';
import { submitImplicitly } from 'tests/submitImplicitly';
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import CreateServiceAccountModal from '../CreateServiceAccountModal';
@@ -60,7 +61,10 @@ describe('CreateServiceAccountModal', () => {
await screen.findByTestId('create-sa-name-input');
await waitFor(() =>
expect(screen.getByTestId('create-sa-submit-btn')).toBeDisabled(),
expect(screen.getByTestId('create-sa-submit-btn')).toHaveAttribute(
'aria-disabled',
'true',
),
);
});
@@ -72,10 +76,14 @@ describe('CreateServiceAccountModal', () => {
const submitBtn = await screen.findByTestId('create-sa-submit-btn');
await user.type(nameInput, 'test');
await waitFor(() => expect(submitBtn).not.toBeDisabled());
await waitFor(() =>
expect(submitBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.clear(nameInput);
await waitFor(() => expect(submitBtn).toBeDisabled());
await waitFor(() =>
expect(submitBtn).toHaveAttribute('aria-disabled', 'true'),
);
});
it('successful submit shows toast.success and closes modal', async () => {
@@ -86,7 +94,9 @@ describe('CreateServiceAccountModal', () => {
await user.type(nameInput, 'Deploy Bot');
const submitBtn = screen.getByTestId('create-sa-submit-btn');
await waitFor(() => expect(submitBtn).not.toBeDisabled());
await waitFor(() =>
expect(submitBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(submitBtn);
await waitFor(() => {
@@ -102,6 +112,40 @@ describe('CreateServiceAccountModal', () => {
});
});
it('pressing Enter again while creating sends one request', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
let requests = 0;
server.use(
rest.post(SERVICE_ACCOUNTS_ENDPOINT, (_, res, ctx) => {
requests += 1;
return res(
ctx.delay(100),
ctx.status(201),
ctx.json({ status: 'success', data: {} }),
);
}),
);
renderModal();
const nameInput = await screen.findByTestId<HTMLInputElement>(
'create-sa-name-input',
);
await user.type(nameInput, 'Deploy Bot');
const submitBtn = screen.getByTestId('create-sa-submit-btn');
await waitFor(() =>
expect(submitBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
submitImplicitly(nameInput);
await waitFor(() => expect(submitBtn).toHaveAttribute('aria-busy', 'true'));
submitImplicitly(nameInput);
await waitFor(() => {
expect(mockToast.success).toHaveBeenCalled();
});
expect(requests).toBe(1);
});
it('shows toast.error on API error and keeps modal open', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
@@ -120,7 +164,9 @@ describe('CreateServiceAccountModal', () => {
await user.type(nameInput, 'Dupe Bot');
const submitBtn = screen.getByTestId('create-sa-submit-btn');
await waitFor(() => expect(submitBtn).not.toBeDisabled());
await waitFor(() =>
expect(submitBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(submitBtn);
await waitFor(() => {
@@ -180,7 +226,10 @@ describe('CreateServiceAccountModal', () => {
).resolves.toBeInTheDocument();
// The footer lives outside the guard: submit is gated, Cancel still works.
expect(screen.getByTestId('create-sa-submit-btn')).toBeDisabled();
expect(screen.getByTestId('create-sa-submit-btn')).toHaveAttribute(
'aria-disabled',
'true',
);
await user.click(screen.getByTestId('create-sa-cancel-btn'));

View File

@@ -4,30 +4,6 @@
align-items: center;
gap: 4px;
.zoom-out-btn {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--secondary-foreground);
background-color: var(--secondary-background);
border: 1px solid var(--secondary-border);
border-radius: 2px;
box-shadow: none;
padding: 10px;
height: 33px;
&:hover:not(:disabled) {
color: var(--primary-foreground);
background: var(--primary-background);
}
&:disabled {
opacity: 0.5;
cursor: not-allowed;
}
}
.timeSelection-input {
&:hover {
border-color: var(--l1-border) !important;

View File

@@ -650,20 +650,20 @@ function CustomTimePicker({
</Popover>
</Tooltip>
{!showLiveLogs && !isModalTimeSelection && (
<Tooltip
title={
zoomOutDisabled ? 'Zoom out time range is limited to 1 month' : 'Zoom out'
}
>
<Tooltip title={zoomOutDisabled ? undefined : 'Zoom out'}>
<Button
className="zoom-out-btn"
disabledTooltip="Zoom out time range is limited to 1 month"
size="md"
onClick={handleZoomOut}
disabled={zoomOutDisabled}
data-testid="zoom-out-btn"
prefix={<ZoomOut size={14} />}
testId="zoom-out-btn"
icon
aria-label="Zoom out"
variant="solid"
color="none"
/>
color="secondary"
>
<ZoomOut size={14} />
</Button>
</Tooltip>
)}
</div>

View File

@@ -164,6 +164,6 @@ describe('CustomTimePicker - zoom out button', () => {
);
const zoomOutBtn = screen.getByTestId('zoom-out-btn');
expect(zoomOutBtn).toBeDisabled();
expect(zoomOutBtn).toHaveAttribute('aria-disabled', 'true');
});
});

View File

@@ -27,12 +27,14 @@ function DetailsHeader({
const closeButton = (
<Button
variant="ghost"
size="icon"
size="sm"
icon
color="secondary"
onClick={onClose}
aria-label="Close"
prefix={<X size={14} />}
></Button>
>
<X size={14} />
</Button>
);
return (

View File

@@ -42,12 +42,5 @@
height: 1px;
background: var(--l1-border);
}
.export-button {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
}

View File

@@ -106,7 +106,7 @@ describe.each([
renderWithStore(dataSource);
const button = screen.getByTestId(testId);
expect(button).toBeInTheDocument();
expect(button).toHaveClass('periscope-btn', 'ghost');
expect(button).toHaveAccessibleName('Download');
});
it('shows popover with export options when download button is clicked', () => {
@@ -308,13 +308,16 @@ describe.each([
fireEvent.click(screen.getByText('Export'));
expect(screen.getByTestId(testId)).toBeDisabled();
expect(screen.getByTestId(testId)).toHaveAttribute('aria-disabled', 'true');
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
resolveDownload!();
await waitFor(() => {
expect(screen.getByTestId(testId)).not.toBeDisabled();
expect(screen.getByTestId(testId)).not.toHaveAttribute(
'aria-disabled',
'true',
);
});
});
});

View File

@@ -1,11 +1,12 @@
import { useCallback, useMemo, useState } from 'react';
import { Button, Popover, Tooltip } from 'antd';
import { RadioGroup, RadioGroupItem } from '@signozhq/ui/radio-group';
import { Popover, Tooltip } from 'antd';
import { Button } from '@signozhq/ui/button';
import { RadioGroup } from '@signozhq/ui/radio-group';
import { Typography } from '@signozhq/ui/typography';
import { TelemetryFieldKey } from 'api/v5/v5';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { useExportRawData } from 'hooks/useExportData/useServerExport';
import { Download, LoaderCircle } from '@signozhq/icons';
import { Download } from '@signozhq/icons';
import { DataSource } from 'types/common/queryBuilder';
import {
@@ -68,10 +69,15 @@ export default function DownloadOptionsMenu({
>
<div className="export-format">
<Typography.Text className="title">FORMAT</Typography.Text>
<RadioGroup value={exportFormat} onChange={setExportFormat}>
<RadioGroupItem value={DownloadFormats.CSV}>csv</RadioGroupItem>
<RadioGroupItem value={DownloadFormats.JSONL}>jsonl</RadioGroupItem>
</RadioGroup>
<RadioGroup
color="primary"
value={exportFormat}
onChange={setExportFormat}
items={[
{ value: DownloadFormats.CSV, label: 'csv' },
{ value: DownloadFormats.JSONL, label: 'jsonl' },
]}
/>
</div>
<div className="horizontal-line" />
@@ -79,19 +85,15 @@ export default function DownloadOptionsMenu({
<div className="row-limit">
<Typography.Text className="title">Number of Rows</Typography.Text>
<RadioGroup
color="primary"
value={String(rowLimit)}
onChange={(value): void => setRowLimit(Number(value))}
>
<RadioGroupItem value={String(DownloadRowCounts.TEN_K)}>
10k
</RadioGroupItem>
<RadioGroupItem value={String(DownloadRowCounts.THIRTY_K)}>
30k
</RadioGroupItem>
<RadioGroupItem value={String(DownloadRowCounts.FIFTY_K)}>
50k
</RadioGroupItem>
</RadioGroup>
items={[
{ value: String(DownloadRowCounts.TEN_K), label: '10k' },
{ value: String(DownloadRowCounts.THIRTY_K), label: '30k' },
{ value: String(DownloadRowCounts.FIFTY_K), label: '50k' },
]}
/>
</div>
{dataSource !== DataSource.TRACES && (
@@ -100,22 +102,26 @@ export default function DownloadOptionsMenu({
<div className="columns-scope">
<Typography.Text className="title">Columns</Typography.Text>
<RadioGroup value={columnsScope} onChange={setColumnsScope}>
<RadioGroupItem value={DownloadColumnsScopes.ALL}>All</RadioGroupItem>
<RadioGroupItem value={DownloadColumnsScopes.SELECTED}>
Selected
</RadioGroupItem>
</RadioGroup>
<RadioGroup
color="primary"
value={columnsScope}
onChange={setColumnsScope}
items={[
{ value: DownloadColumnsScopes.ALL, label: 'All' },
{ value: DownloadColumnsScopes.SELECTED, label: 'Selected' },
]}
/>
</div>
</>
)}
<Button
type="primary"
icon={<Download size={16} />}
variant="solid"
color="primary"
prefix={<Download size={16} />}
size="md"
width="100%"
onClick={handleExport}
className="export-button"
disabled={isDownloading}
loading={isDownloading}
>
Export
@@ -144,17 +150,16 @@ export default function DownloadOptionsMenu({
>
<Tooltip title="Download" placement="top">
<Button
className="periscope-btn ghost"
icon={
isDownloading ? (
<LoaderCircle size={14} className="animate-spin" />
) : (
<Download size={14} />
)
}
data-testid={`periscope-btn-download-${dataSource}`}
disabled={isDownloading}
/>
variant="ghost"
color="secondary"
size="sm"
icon
aria-label="Download"
testId={`periscope-btn-download-${dataSource}`}
loading={isDownloading}
>
<Download size={14} />
</Button>
</Tooltip>
</Popover>
);

View File

@@ -38,18 +38,23 @@ function DeleteMemberDialog({
const footer = (
<>
<Button variant="solid" color="secondary" onClick={onClose}>
<X size={12} />
<Button
size="md"
variant="solid"
color="secondary"
onClick={onClose}
prefix={<X size={12} />}
>
Cancel
</Button>
<Button
size="md"
variant="solid"
color="destructive"
disabled={isDeleting}
color="danger"
onClick={onConfirm}
loading={isDeleting}
prefix={<Trash2 size={12} />}
>
<Trash2 size={12} />
{isDeleting ? 'Processing...' : title}
</Button>
</>

View File

@@ -90,7 +90,6 @@
font-weight: var(--uppercase-small-500-font-weight);
line-height: 100%;
letter-spacing: 0.44px;
text-transform: uppercase;
}
}
@@ -113,6 +112,7 @@
&__footer-left {
display: flex;
align-items: center;
gap: var(--spacing-4);
}
&__footer-right {
@@ -128,10 +128,6 @@
flex-shrink: 0;
}
&__tooltip-wrapper {
display: inline-flex;
}
&__footer-btn {
display: inline-flex;
align-items: center;
@@ -200,6 +196,7 @@
background: var(--l2-background);
border: 1px solid var(--l1-border);
border-radius: 2px;
padding-right: var(--spacing-4);
}
&__link-text-wrap {
@@ -220,8 +217,4 @@
line-height: var(--line-height-18);
letter-spacing: -0.07px;
}
&__copy-btn {
border-left: 1px solid var(--l1-border);
}
}

View File

@@ -519,7 +519,12 @@ function EditMemberDrawer({
localRoles.map((roleId) => {
const role = availableRoles.find((r) => r.id === roleId);
return (
<Badge key={roleId} color="vanilla">
<Badge
textTransform="none"
variant="solid"
key={roleId}
color="secondary"
>
{role?.name ?? roleId}
</Badge>
);
@@ -559,15 +564,15 @@ function EditMemberDrawer({
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">Status</span>
{member?.status === MemberStatus.Active ? (
<Badge color="forest" variant="outline">
<Badge color="success" variant="outlined">
ACTIVE
</Badge>
) : member?.status === MemberStatus.Deleted ? (
<Badge color="cherry" variant="outline">
<Badge color="danger" variant="outlined">
DELETED
</Badge>
) : (
<Badge color="amber" variant="outline">
<Badge color="warning" variant="outlined">
INVITED
</Badge>
)}
@@ -575,12 +580,16 @@ function EditMemberDrawer({
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">{joinedOnLabel}</span>
<Badge color="vanilla">{formatTimestamp(member?.joinedOn)}</Badge>
<Badge textTransform="none" variant="solid" color="secondary">
{formatTimestamp(member?.joinedOn)}
</Badge>
</div>
{!isInvited && (
<div className="edit-member-drawer__meta-item">
<span className="edit-member-drawer__meta-label">Last Modified</span>
<Badge color="vanilla">{formatTimestamp(member?.updatedAt)}</Badge>
<Badge textTransform="none" variant="solid" color="secondary">
{formatTimestamp(member?.updatedAt)}
</Badge>
</div>
)}
</div>
@@ -611,55 +620,59 @@ function EditMemberDrawer({
{!isDeleted && (
<>
<div className="edit-member-drawer__footer-left">
<Tooltip title={getDeleteTooltip(isRootUser, isSelf)}>
<span className="edit-member-drawer__tooltip-wrapper">
<Button
onClick={(): void => setShowDeleteConfirm(true)}
disabled={isRootUser || isSelf}
variant="link"
color="destructive"
>
<Trash2 size={12} />
{isInvited ? 'Revoke Invite' : 'Delete Member'}
</Button>
</span>
</Tooltip>
<Button
disabledTooltip={getDeleteTooltip(isRootUser, isSelf)}
size="md"
onClick={(): void => setShowDeleteConfirm(true)}
disabled={isRootUser || isSelf}
variant="link"
color="danger"
prefix={<Trash2 size={12} />}
>
{isInvited ? 'Revoke Invite' : 'Delete Member'}
</Button>
<div className="edit-member-drawer__footer-divider" />
<Tooltip title={isRootUser ? ROOT_USER_TOOLTIP : undefined}>
<span className="edit-member-drawer__tooltip-wrapper">
<Button
onClick={handleGenerateResetLink}
disabled={isGeneratingLink || isRootUser || isLoadingTokenStatus}
variant="link"
color="warning"
>
<RefreshCw size={12} />
{isGeneratingLink
? 'Generating...'
: isInvited
? getInviteButtonLabel(
isLoadingTokenStatus,
existingToken,
isTokenExpired,
tokenNotFound,
)
: 'Generate Password Reset Link'}
</Button>
</span>
</Tooltip>
<Button
disabledTooltip={ROOT_USER_TOOLTIP}
size="md"
onClick={handleGenerateResetLink}
disabled={isRootUser}
loading={isGeneratingLink || isLoadingTokenStatus}
variant="link"
color="warning"
prefix={<RefreshCw size={12} />}
>
{isGeneratingLink
? 'Generating...'
: isInvited
? getInviteButtonLabel(
isLoadingTokenStatus,
existingToken,
isTokenExpired,
tokenNotFound,
)
: 'Generate Password Reset Link'}
</Button>
</div>
<div className="edit-member-drawer__footer-right">
<Button variant="outlined" color="secondary" onClick={handleClose}>
<X size={14} />
<Button
size="md"
variant="outlined"
color="secondary"
onClick={handleClose}
prefix={<X size={14} />}
>
Cancel
</Button>
<Button
disabledTooltip={isRootUser ? ROOT_USER_TOOLTIP : 'No changes to save'}
size="md"
variant="solid"
color="primary"
disabled={!isDirty || isSaving || isRootUser}
disabled={!isDirty || isRootUser}
onClick={handleSave}
loading={isSaving}
>

View File

@@ -45,11 +45,11 @@ function ResetLinkDialog({
<span className="reset-link-dialog__link-text">{resetLink}</span>
</div>
<Button
size="md"
variant="link"
color="secondary"
onClick={onCopy}
prefix={hasCopied ? <Check size={12} /> : <Copy size={12} />}
className="reset-link-dialog__copy-btn"
>
{hasCopied ? 'Copied!' : 'Copy'}
</Button>

View File

@@ -251,7 +251,7 @@ describe('EditMemberDrawer', () => {
expect(screen.getByText('ACTIVE')).toBeInTheDocument();
expect(
screen.getByRole('button', { name: /save member details/i }),
).toBeDisabled();
).toHaveAttribute('aria-disabled', 'true');
});
it('enables Save after editing name and calls updateUser on confirm', async () => {
@@ -271,7 +271,9 @@ describe('EditMemberDrawer', () => {
await user.type(nameInput, 'Alice Updated');
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await waitFor(() =>
expect(saveBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(saveBtn);
@@ -295,7 +297,9 @@ describe('EditMemberDrawer', () => {
await user.type(nameInput, 'Alice Updated');
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await waitFor(() =>
expect(saveBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(saveBtn);
await waitFor(() => {
@@ -323,7 +327,9 @@ describe('EditMemberDrawer', () => {
await user.click(await screen.findByTitle('signoz-editor'));
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await waitFor(() =>
expect(saveBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(saveBtn);
await waitFor(() => {
@@ -349,7 +355,9 @@ describe('EditMemberDrawer', () => {
await user.click(removeBtn);
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await waitFor(() =>
expect(saveBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(saveBtn);
await waitFor(() => {
@@ -505,7 +513,9 @@ describe('EditMemberDrawer', () => {
await user.type(nameInput, 'Bob Updated');
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await waitFor(() =>
expect(saveBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(saveBtn);
await waitFor(() => {
@@ -541,7 +551,9 @@ describe('EditMemberDrawer', () => {
await user.type(nameInput, 'Alice Updated');
const saveBtn = screen.getByRole('button', { name: /save member details/i });
await waitFor(() => expect(saveBtn).not.toBeDisabled());
await waitFor(() =>
expect(saveBtn).not.toHaveAttribute('aria-disabled', 'true'),
);
await user.click(saveBtn);
await waitFor(() => {
@@ -619,7 +631,7 @@ describe('EditMemberDrawer', () => {
renderDrawer({ member: selfMember });
expect(
screen.getByRole('button', { name: /delete member/i }),
).toBeDisabled();
).toHaveAttribute('aria-disabled', 'true');
});
it('does not open delete confirm dialog when Delete is clicked while disabled (isSelf)', async () => {
@@ -642,7 +654,7 @@ describe('EditMemberDrawer', () => {
renderDrawer({ member: selfMember });
expect(
screen.getByRole('button', { name: /generate password reset link/i }),
).not.toBeDisabled();
).not.toHaveAttribute('aria-disabled', 'true');
});
});
@@ -664,21 +676,21 @@ describe('EditMemberDrawer', () => {
renderDrawer();
expect(
screen.getByRole('button', { name: /delete member/i }),
).toBeDisabled();
).toHaveAttribute('aria-disabled', 'true');
});
it('disables Reset Link button for root user', () => {
renderDrawer();
expect(
screen.getByRole('button', { name: /generate password reset link/i }),
).toBeDisabled();
).toHaveAttribute('aria-disabled', 'true');
});
it('disables Save button for root user', () => {
renderDrawer();
expect(
screen.getByRole('button', { name: /save member details/i }),
).toBeDisabled();
).toHaveAttribute('aria-disabled', 'true');
});
it('does not open delete confirm dialog when Delete is clicked while disabled (root)', async () => {

View File

@@ -53,7 +53,7 @@ function ErrorModal({
onClick={(): void => setVisible(true)}
onKeyDown={undefined}
>
<Badge color="error">
<Badge variant="solid" color="danger">
<CircleAlert size={14} color={Color.BG_CHERRY_500} /> error
</Badge>
</span>

View File

@@ -1,7 +1,7 @@
import { useState } from 'react';
import { useCopyToClipboard } from 'react-use';
import { Button, Col, Popover, Row, Select, Space } from 'antd';
import { DropdownMenuSimple, type MenuProps } from '@signozhq/ui/dropdown-menu';
import { Dropdown, type DropdownItemType } from '@signozhq/ui/dropdown';
import { Typography } from '@signozhq/ui/typography';
import axios from 'axios';
import TextToolTip from 'components/TextToolTip';
@@ -137,16 +137,15 @@ function ExplorerCard({
);
};
const moreOptionMenu: MenuProps = {
items: [
{
key: 'delete',
label: <Typography.Text strong>Delete</Typography.Text>,
onClick: onDeleteHandler,
icon: <Trash2 size="md" />,
},
],
};
const moreOptionItems: DropdownItemType[] = [
{
type: 'item',
value: 'delete',
label: <Typography.Text strong>Delete</Typography.Text>,
onClick: onDeleteHandler,
prefix: <Trash2 size="md" />,
},
];
const saveButtonType = isQueryUpdated ? 'default' : 'primary';
const saveButtonIcon = isQueryUpdated ? null : <Save size="md" />;
@@ -230,9 +229,14 @@ function ExplorerCard({
</Popover>
<Share2 onClick={onCopyUrlHandler} size="md" />
{viewKey && (
<DropdownMenuSimple menu={moreOptionMenu}>
<Dropdown
items={moreOptionItems}
nativeButton
align="end"
side="bottom"
>
<Button type="text" size="small" icon={<Ellipsis size="md" />} />
</DropdownMenuSimple>
</Dropdown>
)}
</Space>
</OffSetCol>

View File

@@ -26,8 +26,4 @@
font-size: var(--periscope-font-size-base);
}
}
.export-button {
width: 100%;
}
}

View File

@@ -1,8 +1,8 @@
import { Download } from '@signozhq/icons';
import { Button } from '@signozhq/ui/button';
import { Popover, PopoverContent, PopoverTrigger } from '@signozhq/ui/popover';
import { RadioGroup, RadioGroupItem } from '@signozhq/ui/radio-group';
import { TooltipSimple } from '@signozhq/ui/tooltip';
import { RadioGroup } from '@signozhq/ui/radio-group';
import { Tooltip } from '@signozhq/ui/tooltip';
import { Typography } from '@signozhq/ui/typography';
import {
ClientExportData,
@@ -51,36 +51,41 @@ export default function ExportMenu({
return (
<Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
<TooltipSimple title="Download">
<Tooltip title="Download">
<PopoverTrigger asChild>
<Button
variant="ghost"
color="secondary"
size="icon"
size="sm"
icon
aria-label="Download"
data-testid={`export-menu-${dataSource}`}
disabled={isExporting}
testId={`export-menu-${dataSource}`}
loading={isExporting}
>
<Download size={14} />
</Button>
</PopoverTrigger>
</TooltipSimple>
</Tooltip>
<PopoverContent align="end" className="export-menu-popover">
<div className="export-format">
<Typography.Text className="title">FORMAT</Typography.Text>
<RadioGroup value={exportFormat} onChange={setExportFormat}>
<RadioGroupItem value={ExportFormat.Csv}>csv</RadioGroupItem>
<RadioGroupItem value={ExportFormat.Jsonl}>jsonl</RadioGroupItem>
</RadioGroup>
<RadioGroup
color="primary"
value={exportFormat}
onChange={setExportFormat}
items={[
{ value: ExportFormat.Csv, label: 'csv' },
{ value: ExportFormat.Jsonl, label: 'jsonl' },
]}
/>
</div>
<Button
size="md"
variant="solid"
color="primary"
className="export-button"
width="100%"
onClick={handleExport}
disabled={isExporting}
loading={isExporting}
prefix={<Download size={16} />}
>

View File

@@ -80,6 +80,6 @@ describe('ExportMenu', () => {
mockIsExporting = true;
renderMenu();
expect(screen.getByTestId(TEST_ID)).toBeDisabled();
expect(screen.getByTestId(TEST_ID)).toHaveAttribute('aria-disabled', 'true');
});
});

View File

@@ -57,9 +57,8 @@ function SortableField({
</div>
{!isRequired && (
<Button
className={cx(styles.removeBtn, 'periscope-btn')}
variant="outlined"
color="destructive"
variant="solid"
color="danger"
size="sm"
onClick={(): void => onRemove(field)}
>

View File

@@ -98,11 +98,15 @@
user-select: none;
font-size: 13px;
> [data-slot='button'] {
opacity: 0;
transition: opacity 0.15s ease-in-out;
}
&:hover {
background-color: var(--l2-background);
.removeBtn,
.addBtn {
> [data-slot='button'] {
opacity: 1;
}
}
@@ -137,14 +141,6 @@
height: 32px;
}
.removeBtn,
.addBtn {
padding: 4px 10px;
opacity: 0;
transition: opacity 0.15s ease-in-out;
flex-shrink: 0;
}
.footer {
display: flex;
gap: 12px;

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