Compare commits

..

4 Commits

Author SHA1 Message Date
Yunus M
3b37b67222 test: adapt checkbox assertions to SigNoz UI Checkbox DOM
The SigNoz UI Checkbox renders <button role="checkbox" data-state="…">
via Radix instead of antd's <input type="checkbox">. Four test suites
queried the old DOM and broke after the migration.

- TracesExplorer.test.tsx — getByTestId returns the wrapper div now (the
  SigNoz UI Checkbox exposes testId on the wrapper, not the button).
  Querying the inner [role="checkbox"] and asserting data-state.
- DynamicVariableDefaultBehavior.test.tsx, PanelManagement.test.tsx,
  getChartManagerColumns.test.tsx — replace querySelector(
  'input[type="checkbox"]') with [role="checkbox"], and .checked /
  toBeChecked() with toHaveAttribute('data-state', 'checked').

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:57:29 +05:30
Yunus M
5e57a55358 refactor: migrate complex antd Checkbox callsites to @signozhq/ui (batch 3)
Handles the four callsites that needed shape changes, not just renames:

- RegionSelector — collapses separate `checked` + `indeterminate` props
  into a single `value: true | false | 'indeterminate'` (SigNoz UI uses
  CheckedState, not two props).
- InteractiveQuestion — replaces `<Checkbox.Group>` (no SigNoz UI
  equivalent) with a plain `<div>` of individual `<Checkbox>`s that
  push/pull from the existing `selected: string[]` state on each toggle.
- GridCardLayout/types.ts + CustomCheckBox — drops the antd-only
  `CheckboxChangeEvent` type from the `checkBoxOnChangeHandler`
  signature and removes the `ConfigProvider` theme override that
  previously colored each chart-legend checkbox to match its series.
  The dynamic per-series color is now injected via the SigNoz UI
  Checkbox's exposed CSS variables
  (`--checkbox-checked-background`, `--checkbox-border-color`)
  applied through a wrapper `<span style={…}>`.

After this commit `grep -rE "from 'antd'.*Checkbox" frontend/src` and
`grep -rE "CheckboxChangeEvent" frontend/src` both return zero matches.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 19:27:50 +05:30
Yunus M
28274b826c refactor: drop antd CheckboxChangeEvent in checkbox callsites (batch 2)
Two callsites that read e.target.checked via antd's CheckboxChangeEvent
type now receive the CheckedState (boolean | 'indeterminate') directly
from @signozhq/ui Checkbox's onChange.

- TopNav/AutoRefreshV2/index.tsx — onChangeAutoRefreshHandler signature
  changes; derives boolean checked from CheckedState.
- TracesExplorer/Filter/SectionContent.tsx — onCheckHandler likewise;
  also swap data-testid -> testId since SigNoz UI Checkbox wraps the
  input in a div that exposes testId.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 17:20:24 +05:30
Yunus M
dc656f08be refactor: replace antd Checkbox with @signozhq/ui Checkbox (batch 1)
Migrates mechanical checkbox callsites from antd to @signozhq/ui/checkbox:

- Trace/Filters/Panel/.../Common/Checkbox.tsx
- NewWidget/LeftContainer/ExplorerAttributeColumns.tsx
- AnomalyAlertEvaluationView.tsx
- QuickFilters/FilterRenderers/Checkbox/Checkbox.tsx
- NewSelect/CustomMultiSelect.tsx
- RolesSelect/RolesSelect.tsx
- TraceDetailsV3/.../SpanPercentilePanel.tsx

API mapping: checked -> value, defaultChecked -> defaultValue, onChange(e)
where e.target.checked is read -> onChange(checked) where checked is
CheckedState. Dropped antd-only props (type="checkbox", rootClassName ->
className, form-value `value=` semantics). RolesSelect wraps the checkbox
in a div to host pointerEvents:none since style is not in CheckboxProps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 17:17:18 +05:30
144 changed files with 261 additions and 2210 deletions

View File

@@ -1,315 +0,0 @@
# antd `Input` → `@signozhq/ui/input` Migration — Affected Files & Verification
## What changed
For each file listed below, the import was rewritten:
```diff
- import { Input, ...rest } from 'antd';
+ import { Input } from '@signozhq/ui/input';
+ import { ...rest } from 'antd';
```
Only the plain antd `<Input>` component was migrated. The following are **not** migrated and continue to use antd:
- `Input.TextArea` / `Input.Password` / `Input.Search` / `Input.Group`
- `InputNumber`
- `<Input>` with `addonBefore`, `addonAfter`, `allowClear`, `bordered`, `status="error"`, or `size="small|middle|large"` props
- `InputRef` (typed refs)
No JSX usages of `<Input>` were touched — only the import source was swapped. The component contract (`value`, `onChange`, `placeholder`, `disabled`, `type`, `prefix`, `suffix`, etc.) matches between the two libraries for the cases migrated here.
---
## Reverted after TypeScript errors — 4 files (kept on antd, marked with TODO)
These files were initially migrated, then reverted because `@signozhq/ui` `Input` does not expose the props they need. Each one carries a `TODO(@signozhq/ui-input)` comment above the antd import.
| File | Blocker |
|---|---|
| `frontend/src/container/MetricsExplorer/Inspect/MetricTimeAggregation.tsx` | Uses `onWheel` on `<Input type="number">` to blur on scroll. Not exposed on `@signozhq/ui/input`. |
| `frontend/src/container/NewWidget/RightContainer/ContextLinks/UpdateContextLinks.tsx` | URL `<Input>` uses `spellCheck="false"` (along with `autoCorrect`, `autoCapitalize`). `spellCheck` not exposed. |
| `frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/CSVInput.tsx` | Spreads antd `InputProps` (`{...otherProps}`) onto `<Input>`. `size: SizeType` clashes with `@signozhq/ui` Input's numeric `size`. |
| `frontend/src/container/Trace/Filters/Panel/PanelBody/Duration/styles.ts` | The `styled(Input)` wrapper is consumed in `Duration/index.tsx` with `addonAfter="ms"`. Not exposed. |
---
## Migrated files — 51 total
Grouped by the route/page that renders them. Visit each route after the migration and confirm the input still:
1. Renders with the expected layout/spacing
2. Accepts keyboard input and reflects controlled `value`
3. Fires `onChange` correctly (search filters, form submissions still work)
4. Shows placeholder text
5. Disables/enables as expected
6. Form validation (`Form.Item rules`) still shows errors
### Alerts — Create / Edit Alert (`/alerts/new`, `/alerts/edit`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/CreateAlertV2/AlertCondition/ThresholdItem.tsx` | Threshold name + threshold value + recovery threshold inputs in the Alert Condition card |
| `frontend/src/container/CreateAlertV2/EvaluationSettings/AdvancedOptions.tsx` | Advanced Options collapse inside Evaluation Settings |
| `frontend/src/container/CreateAlertV2/EvaluationSettings/EvaluationWindowPopover/EvaluationWindowDetails.tsx` | Evaluation Window popover (numeric value + unit) |
| `frontend/src/container/CreateAlertV2/EvaluationSettings/TimeInput/TimeInput.tsx` | HH:MM:SS time input shared in Evaluation Settings |
| `frontend/src/container/CreateAlertV2/NotificationSettings/NotificationSettings.tsx` | Re-notification interval input |
### Alert Channels (`/settings/channels/new`, `/settings/channels/edit/:channelId`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/FormAlertChannels/index.tsx` | Channel name + send-resolved / common fields |
| `frontend/src/container/FormAlertChannels/Settings/Email.tsx` | "To" email field of the Email channel form |
| `frontend/src/container/FormAlertChannels/Settings/Webhook.tsx` | Webhook URL / username / password fields |
### Routing Policies (`/settings/channels` → routing policies tab)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/RoutingPolicies/RoutingPolicies.tsx` | Search box on the routing policies list |
### Organization Settings (`/settings/org-settings`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/OrganizationSettings/InviteTeamMembers/index.tsx` | Email + name fields in the "Invite team members" form (used by the invite-members flow) |
### Members (`/settings/members`)
_None directly migrated this round_ — already on `@signozhq/ui/input`.
### Planned Downtime (`/settings/channels` → Planned Downtime, or `/planned-downtime` depending on plan)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/PlannedDowntime/PlannedDowntime.tsx` | "Search downtime" text input above the list |
### Licenses (`/licenses`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/Licenses/ApplyLicenseForm.tsx` | License key text input on the apply-license form |
### Dashboards — list, detail, widget editor
| File | Where the input shows up | Route |
|---|---|---|
| `frontend/src/container/ListOfDashboard/DashboardsList.tsx` | Main "Search by name, description, or tags…" input on the dashboards list | `/dashboard` |
| `frontend/src/container/ListOfDashboard/RequestDashboardBtn.tsx` | "Request dashboard" modal input | `/dashboard` |
| `frontend/src/container/ListOfDashboard/DashboardTemplates/DashboardTemplatesModal.tsx` | Templates modal search input | `/dashboard` (open templates) |
| `frontend/src/container/DashboardContainer/DashboardDescription/index.tsx` | Dashboard description editor name field | `/dashboard/:dashboardId` |
| `frontend/src/container/GridCardLayout/GridCardLayout.tsx` | Section / row name inline edit | `/dashboard/:dashboardId` |
| `frontend/src/container/DashboardContainer/visualization/components/ChartManager/ChartManager.tsx` | Chart manager search input | `/dashboard/:dashboardId` |
| `frontend/src/container/NewWidget/LeftContainer/ExplorerColumnsRenderer.tsx` | Column-config inputs in the widget editor's left panel | `/dashboard/:dashboardId/:widgetId` |
### Logs (`/logs/logs-explorer`, `/logs/pipelines`)
| File | Where the input shows up | Route |
|---|---|---|
| `frontend/src/container/LogsFilters/index.tsx` | Logs filter sidebar search input | `/logs/logs-explorer` |
| `frontend/src/container/LogsSearchFilter/SearchFields/QueryBuilder/QueryBuilder.tsx` | Query-builder field value inputs in the legacy logs search | `/logs/logs-explorer` |
| `frontend/src/container/LogDetailedView/Overview.tsx` | Log details drawer Overview tab inputs (severity / body filters) | `/logs/logs-explorer` (open a log) |
| `frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/ProcessorForm.tsx` | Add-new-processor form fields | `/logs/pipelines` |
| `frontend/src/container/PipelinePage/PipelineListsView/AddNewProcessor/FormFields/JsonFlattening.tsx` | JSON-flattening processor form | `/logs/pipelines` |
| `frontend/src/container/PipelinePage/PipelineListsView/AddNewPipeline/FormFields/NameInput.tsx` | "Pipeline name" field in the new-pipeline form | `/logs/pipelines` |
### Traces (`/traces-explorer`, trace details, funnels)
| File | Where the input shows up | Route |
|---|---|---|
| `frontend/src/container/Trace/Search/AllTags/Tag/TagKey.tsx` | Tag-key autocomplete input in the legacy trace search | `/trace` |
| `frontend/src/container/Trace/TraceGraphFilter/index.tsx` | Trace-graph filter search/value input | `/trace` |
| `frontend/src/container/SpanDetailsDrawer/SpanDetailsDrawer.tsx` | "Search resource attributes" input in the span details drawer | `/traces-explorer` → open span |
| `frontend/src/container/SpanDetailsDrawer/Attributes/Attributes.tsx` | Span details drawer → Attributes search | `/traces-explorer` → open span |
| `frontend/src/container/SpanDetailsDrawer/Events/Events.tsx` | Span details drawer → Events search | `/traces-explorer` → open span |
| `frontend/src/container/TraceWaterfall/AddSpanToFunnelModal/AddSpanToFunnelModal.tsx` | "Add span to funnel" modal name input (legacy waterfall) | `/trace/:id` |
| `frontend/src/pages/TraceDetailsV3/SpanDetailsPanel/SpanPercentile/SpanPercentilePanel.tsx` | Percentile filter input in span details v3 | `/trace/:id` (v3) |
| `frontend/src/pages/TraceDetailsV3/TraceWaterfall/AddSpanToFunnelModal/AddSpanToFunnelModal.tsx` | "Add span to funnel" modal in v3 waterfall | `/trace/:id` (v3) |
| `frontend/src/pages/TracesFunnels/components/SearchBar/SearchBar.tsx` | Search box on the funnels list page | `/traces/funnels` |
| `frontend/src/pages/TracesFunnels/components/RenameFunnel/RenameFunnel.tsx` | Rename-funnel modal input | `/traces/funnels` |
### Saved Views (`/logs/saved-views`, `/traces/saved-views`)
| File | Where the input shows up |
|---|---|
| `frontend/src/components/ExplorerCard/SaveViewWithName.tsx` | "Save view with name" inline input on the explorer save flow |
| `frontend/src/container/ExplorerOptions/ExplorerOptions.tsx` | "e.g. External http method view" — name input in the Save View modal across explorers |
| `frontend/src/pages/SaveView/index.tsx` | Rename saved view input on the saved-views list |
### Metrics Explorer (`/metrics-explorer`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/MetricsExplorer/MetricDetails/Metadata.tsx` | Metadata edit inputs in metric details |
### Messaging Queues (`/messaging-queues`)
| File | Where the input shows up |
|---|---|
| `frontend/src/pages/MessagingQueues/MQDetails/DropRateView/EvaluationTimeSelector.tsx` | Evaluation time selector inside Drop Rate view |
### Integrations (`/integrations`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/RegionForm/RenderConnectionParams.tsx` | Connection-params text fields in AWS cloud integration setup |
### Ingestion Settings (`/settings/ingestion-settings`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/IngestionSettings/MultiIngestionSettings.tsx` | "Search for ingestion key…" + add/edit ingestion-key name fields. `<InputNumber>` usages in this file still come from antd. |
### Onboarding (`/get-started/*`, `/onboarding`)
| File | Where the input shows up |
|---|---|
| `frontend/src/container/OnboardingContainer/Steps/DataSource/DataSource.tsx` | Custom data source name input |
| `frontend/src/container/OnboardingContainer/Steps/EnvironmentDetails/EnvironmentDetails.tsx` | Environment details (env name / app name) inputs |
### Other shared components (rendered on multiple routes)
| File | Where it shows up |
|---|---|
| `frontend/src/components/CustomTimePicker/TimezonePicker.tsx` | Timezone search input inside the global custom time picker — visible on dashboards, logs, traces, alerts header |
| `frontend/src/components/InputWithLabel/InputWithLabel.tsx` | Generic labeled-input wrapper — used in invite flows, threshold editing, etc. |
| `frontend/src/components/QuickFilters/QuickFiltersSettings/QuickFiltersSettings.tsx` | "Search filters" input inside the Quick Filters settings drawer (logs/traces/infra/metrics quick-filters) |
| `frontend/src/components/QuickFilters/FilterRenderers/Checkbox/Checkbox.tsx` | Search box at the top of each checkbox-style quick filter |
| `frontend/src/container/QueryTable/Drilldown/BreakoutOptions.tsx` | "Breakout by" attribute search input in the query-table drilldown menu (dashboards, alerts) |
| `frontend/src/components/LogsFormatOptionsMenu/LogsFormatOptionsMenu.tsx` | "Search…" input inside the "Add column" picker in the logs format options menu (rendered on `/logs/logs-explorer`). `<InputNumber>` for max-line config still comes from antd. |
### `styled(Input)` wrappers — `.ts` style files
These wrap the now-`@signozhq/ui` `Input` with styled-components. CSS selectors target the descendant `<input>` element so behavior should be unchanged, but visually re-verify on the routes below.
| File | Verification route |
|---|---|
| `frontend/src/container/Version/styles.ts` | Status page `/status` — confirm input width = 183px |
> `Trace/Filters/Panel/PanelBody/Duration/styles.ts` was attempted and reverted — see the "Reverted" section at the top.
---
## Smoke-test checklist
A short loop that covers the bulk of what changed:
1. **Alerts → New alert** (`/alerts/new`) — add a threshold, type a name + value, switch evaluation window unit, expand Advanced Options, set time input, save.
2. **Channels → New channel** (`/settings/channels/new`) — pick Email, fill the "to" field; pick Webhook, fill URL.
3. **Dashboards** — open a dashboard, edit a panel (`/dashboard/:dashboardId/:widgetId`) → set context-link label/URL/params, edit explorer columns. Then on the list page (`/dashboard`) open the Templates modal and the "Request dashboard" modal.
4. **Logs Explorer** (`/logs/logs-explorer`) — type into the sidebar filter search, open a log row → Overview tab.
5. **Logs Pipelines** (`/logs/pipelines`) — open "Add new pipeline" and "Add new processor", switch processor type to JSON Flattening / CSV.
6. **Traces Explorer** (`/traces-explorer`) — open a span, search inside Attributes + Events tabs.
7. **Trace details V3** (`/trace/:id`) — open the percentile panel, open "Add span to funnel".
8. **Funnels list** (`/traces/funnels`) — type in the search bar, rename a funnel.
9. **Saved Views** (`/logs/saved-views`, `/traces/saved-views`) — rename a view; from an explorer, "Save view as…".
10. **Metrics Explorer** (`/metrics-explorer/explorer`) — open Inspect → time aggregation; open metric details → Metadata tab.
11. **Integrations → AWS** — open AWS cloud integration → Region form.
12. **Onboarding** (`/get-started`) — pick "Custom" data source, fill env/app names.
13. **Custom time picker** — open the global time picker anywhere, switch to "Custom" → type in the timezone search.
14. **Quick filters** — on `/logs/logs-explorer` or `/traces-explorer`, open the quick-filter settings drawer and search inside.
15. **Org settings → Invite members** (`/settings/org-settings`) — open invite flow, fill email + name.
16. **Planned downtime** — search the list.
17. **Licenses** (`/licenses`) — paste a license key in the input.
For each: confirm typing, controlled value, placeholder, disabled state, and form-validation error display all behave the same as before.
---
## Skipped (still on antd) — 61 files
After the migration, 61 files still import `Input` from antd. None of them use a plain `<Input>` that can be migrated — each one is kept on antd for one of the reasons below.
Kept on antd because they use features the `@signozhq/ui` `Input` does not expose. No action required unless these are migrated separately later.
**Use `Input.TextArea` / `Input.Password` / `Input.Search` / `Input.Group`:**
`CreateAlertV2/EvaluationSettings/EvaluationCadence/EvaluationCadence.tsx`,
`CreateAlertV2/EvaluationSettings/EvaluationCadence/EvaluationCadenceDetails.tsx`,
`CreateAlertV2/NotificationSettings/NotificationMessage.tsx`,
`QueryBuilder/components/Formula/Formula.tsx`,
`OptionsMenu/AddColumnField/index.tsx`,
`LogsSearchFilter/index.tsx`,
`RoutingPolicies/RoutingPolicyDetails.tsx`,
`DashboardContainer/DashboardSettings/DashboardVariableSettings/VariableItem/VariableItem.tsx`,
`DashboardContainer/DashboardSettings/General/index.tsx`,
`FormAlertChannels/Settings/MsTeams.tsx`,
`MySettings/UserInfo/index.tsx`,
`Login/index.tsx`,
`PipelinePage/PipelineListsView/AddNewPipeline/FormFields/DescriptionTextArea.tsx`,
`components/HeaderRightSection/FeedbackModal.tsx`,
`pages/TracesFunnelDetails/components/FunnelConfiguration/AddFunnelStepDetailsModal.tsx`,
`pages/TracesFunnelDetails/components/FunnelConfiguration/AddFunnelDescriptionModal.tsx`,
`pages/TracesExplorer/Filter/SectionContent.tsx`.
**Destructure `const { TextArea/Search } = Input`:**
`Trace/Filters/Panel/PanelBody/CommonCheckBox/index.tsx`,
`Trace/Filters/Panel/PanelBody/SearchTraceID/index.tsx`,
`Trace/Search/styles.ts`,
`ListAlertRules/ListAlert.tsx`,
`FormAlertRules/styles.ts`,
`FormAlertChannels/Settings/Opsgenie.tsx`,
`FormAlertChannels/Settings/Pager.tsx`,
`FormAlertChannels/Settings/Slack.tsx`,
`NewWidget/RightContainer/SettingSections/GeneralSettingsSection/GeneralSettingsSection.tsx`,
`AnomalyAlertEvaluationView/AnomalyAlertEvaluationView.tsx`.
**`InputNumber` co-used:**
`NewWidget/RightContainer/Threshold/Threshold.tsx`,
`components/LogsFormatOptionsMenu/LogsFormatOptionsMenu.tsx`.
**Typed `InputRef`:**
`DashboardContainer/DashboardVariablesSelection/TextboxVariableInput.tsx`,
`NewWidget/RightContainer/SettingSections/GeneralSettingsSection/GeneralSettingsSection.tsx`,
`PipelinePage/components/TagInput.tsx`,
`components/OverflowInputToolTip/OverflowInputToolTip.tsx`,
`components/CustomTimePicker/CustomTimePicker.tsx`,
`components/Input/index.tsx`,
`pages/AlertDetails/AlertHeader/ActionButtons/RenameModal.tsx`,
`LogsSearchFilter/index.tsx`.
**Use `addonBefore` / `addonAfter`:**
`QueryBuilder/components/Query/Query.tsx`,
`QueryBuilder/components/Formula/Formula.tsx`,
`GridCardLayout/GridCard/FullView/index.tsx`,
`GridCardLayout/WidgetHeader/index.tsx`,
`OnboardingV2Container/InviteTeamMembers/InviteTeamMembers.tsx`,
`NewWidget/LeftContainer/QuerySection/QueryBuilder/ClickHouse/query.tsx`,
`NewWidget/LeftContainer/QuerySection/QueryBuilder/promQL/query.tsx`,
`components/Input/index.tsx`,
`pages/TracesExplorer/Filter/DurationSection.tsx`.
**Use `allowClear`:**
`Trace/Search/AllTags/Tag/TagKey.tsx` _(migrated — `allowClear` was only used elsewhere)_,
`ServiceTable/Filter/FilterDropdown.tsx`,
`ServiceApplication/Filter/FilterDropdown.tsx`,
`LogsSearchFilter/index.tsx`,
`MetricsExplorer/MetricDetails/AllAttributesValue.tsx`,
`GridCardLayout/GridCard/FullView/index.tsx`,
`NewWidget/RightContainer/SettingSections/GeneralSettingsSection/GeneralSettingsSection.tsx`,
`AnomalyAlertEvaluationView/AnomalyAlertEvaluationView.tsx`,
`AllError/index.tsx`,
`PipelinePage/Layouts/Pipeline/PipelinesSearchSection.tsx`,
`lib/uPlotV2/components/Legend/Legend.tsx`.
**Use `bordered`, `status`, or `size="small|middle|large"`:**
`OrganizationSettings/DisplayName/index.tsx` (size, status),
`FormAlertRules/labels/index.tsx` (bordered),
`DashboardContainer/DashboardVariablesSelection/TextboxVariableInput.tsx` (bordered),
`MetricsExplorer/MetricDetails/AllAttributes.tsx` (size),
`MetricsExplorer/MetricDetails/AllAttributesValue.tsx` (size),
`AllError/index.tsx` (size),
`components/CustomTimePicker/CustomTimePicker.tsx` (status),
`QueryBuilder/components/Query/Query.tsx` (size),
`QueryBuilder/components/Formula/Formula.tsx` (size),
`NewWidget/LeftContainer/QuerySection/QueryBuilder/ClickHouse/query.tsx` (size),
`NewWidget/LeftContainer/QuerySection/QueryBuilder/promQL/query.tsx` (size).
**`styled(Input)` in `.ts` style files (DOM structure differs):**
`Trace/Filters/Panel/PanelBody/Duration/styles.ts`,
`Version/styles.ts`.
**Aliased-only `Input as X` (no plain `<Input>`):**
`ResetPassword/index.tsx`.
**Already on `@signozhq/ui/input`** (no diff this round): Retention, AuthnOIDC/SAML/Google + their helper sections (ClaimMapping, RoleMapping, AttributeMapping, DomainMapping), ForgotPassword, IntegrationsHeader, OnboardingQuestionaire (Invite + AboutSigNoz), AIAssistant/ChatInput, ServiceAccountsSettings, MembersSettings, ServiceAccountDrawer (EditKey + AddKey), InviteMembersModal, EditMemberDrawer, RolesSettings + CreateRoleModal, SignUp, plus the rest of the `@signozhq/ui/input` adopters listed in `git grep "@signozhq/ui/input"`.

View File

@@ -6,7 +6,7 @@ import {
useState,
} from 'react';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import { Input } from 'antd';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';
import { TimezonePickerShortcuts } from 'constants/shortcuts/TimezonePickerShortcuts';

View File

@@ -1,6 +1,5 @@
import { useTranslation } from 'react-i18next';
import { Input } from '@signozhq/ui/input';
import { Card, Form } from 'antd';
import { Card, Form, Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { PANEL_TYPES } from 'constants/queryBuilder';
import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder';

View File

@@ -1,6 +1,5 @@
import { useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Button } from 'antd';
import { Button, Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import { X } from '@signozhq/icons';

View File

@@ -1,6 +1,5 @@
import { useCallback, useEffect, useRef, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Button, InputNumber, Popover, Tooltip } from 'antd';
import { Button, Input, InputNumber, Popover, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import type { DefaultOptionType } from 'antd/es/select';
import cx from 'classnames';

View File

@@ -18,7 +18,8 @@ import {
RefreshCw,
} from '@signozhq/icons';
import { Color } from '@signozhq/design-tokens';
import { Button, Checkbox, Select } from 'antd';
import { Button, Select } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import TextToolTip from 'components/TextToolTip/TextToolTip';
@@ -749,7 +750,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
tabIndex={isActive ? 0 : -1}
>
<Checkbox
checked={isSelected}
value={isSelected}
className="option-checkbox"
onClick={(e): void => {
e.stopPropagation();
@@ -1584,7 +1585,7 @@ const CustomMultiSelect: React.FC<CustomMultiSelectProps> = ({
}}
>
<div style={{ display: 'flex', alignItems: 'center', width: '100%' }}>
<Checkbox checked={allOptionsSelected} className="option-checkbox">
<Checkbox value={allOptionsSelected} className="option-checkbox">
<div className="option-content">
<div className="all-option-text">ALL</div>
</div>

View File

@@ -1,7 +1,7 @@
/* eslint-disable sonarjs/no-identical-functions */
import { Fragment, useMemo, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Button, Checkbox, Skeleton } from 'antd';
import { Button, Input, Skeleton } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import { removeKeysFromExpression } from 'components/QueryBuilderV2/utils';
@@ -635,10 +635,12 @@ export default function CheckboxFilter(props: ICheckboxProps): JSX.Element {
)}
<div className="value">
<Checkbox
onChange={(e): void => onChange(value, e.target.checked, false)}
checked={currentFilterState[value]}
onChange={(checked): void =>
onChange(value, checked === true, false)
}
value={currentFilterState[value]}
disabled={isFilterDisabled}
rootClassName="check-box"
className="check-box"
/>
<div

View File

@@ -1,6 +1,5 @@
import { useMemo } from 'react';
import { Input } from '@signozhq/ui/input';
import { Button } from 'antd';
import { Button, Input } from 'antd';
import { Check, TableColumnsSplit, X } from '@signozhq/icons';
import { Filter as FilterType } from 'types/api/quickFilters/getCustomFilters';

View File

@@ -1,5 +1,6 @@
import { CircleAlert, RefreshCw } from '@signozhq/icons';
import { Checkbox, Select } from 'antd';
import { Select } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { convertToApiError } from 'api/ErrorResponseHandlerForGeneratedAPIs';
import { useListRoles } from 'api/generated/services/role';
import type { AuthtypesRoleDTO } from 'api/generated/services/sigNoz.schemas';
@@ -146,12 +147,11 @@ function RolesSelect(props: RolesSelectProps): JSX.Element {
options={options}
optionFilterProp="label"
optionRender={(option): JSX.Element => (
<Checkbox
checked={value.includes(option.value as string)}
style={{ pointerEvents: 'none' }}
>
{option.label}
</Checkbox>
<div style={{ pointerEvents: 'none' }}>
<Checkbox value={value.includes(option.value as string)}>
{option.label}
</Checkbox>
</div>
)}
getPopupContainer={getPopupContainer}
disabled={disabled}

View File

@@ -2,7 +2,8 @@ import { useState } from 'react';
import cx from 'classnames';
import { Button } from '@signozhq/ui/button';
import logEvent from 'api/common/logEvent';
import { Checkbox, Radio } from 'antd';
import { Radio } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { AIAssistantEvents } from '../../../events';
import { useAIAssistantAnalyticsContext } from '../../../hooks/useAIAssistantAnalyticsContext';
@@ -96,16 +97,24 @@ export default function InteractiveQuestion({
</Radio.Group>
) : (
<>
<Checkbox.Group
className={cx(styles.options, styles.checkbox)}
onChange={(vals): void => setSelected(vals as string[])}
>
<div className={cx(styles.options, styles.checkbox)}>
{normalized.map((opt) => (
<Checkbox key={opt.value} value={opt.value} className={styles.option}>
<Checkbox
key={opt.value}
value={selected.includes(opt.value)}
onChange={(checked): void => {
setSelected((prev) =>
checked === true
? [...prev, opt.value]
: prev.filter((v) => v !== opt.value),
);
}}
className={styles.option}
>
{opt.label}
</Checkbox>
))}
</Checkbox.Group>
</div>
<Button
variant="solid"
size="sm"

View File

@@ -1,5 +1,6 @@
import { useEffect, useRef, useState } from 'react';
import { Checkbox, Input } from 'antd';
import { Input } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Typography } from '@signozhq/ui/typography';
import { useIsDarkMode } from 'hooks/useDarkMode';
import useDebouncedFn from 'hooks/useDebouncedFunction';
@@ -320,10 +321,8 @@ function AnomalyAlertEvaluationView({
{filteredSeriesKeys.length > 0 && (
<Checkbox
className="anomaly-alert-evaluation-view-series-list-item"
type="checkbox"
name="series"
value="all"
checked={selectedSeries === null}
value={selectedSeries === null}
onChange={(): void => handleSeriesChange(null)}
>
Show All
@@ -335,10 +334,8 @@ function AnomalyAlertEvaluationView({
<Checkbox
className="anomaly-alert-evaluation-view-series-list-item"
key={seriesKey}
type="checkbox"
name="series"
value={seriesKey}
checked={selectedSeries === seriesKey}
value={selectedSeries === seriesKey}
onChange={(): void => handleSeriesChange(seriesKey)}
>
<div

View File

@@ -1,6 +1,5 @@
import { useMemo, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Button, Select, Tooltip } from 'antd';
import { Button, Input, Select, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { CircleX, Trash } from '@signozhq/icons';
import { useAppContext } from 'providers/App/App';

View File

@@ -1,5 +1,4 @@
import { Input } from '@signozhq/ui/input';
import { Collapse } from 'antd';
import { Collapse, Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { useCreateAlertState } from '../context';

View File

@@ -1,6 +1,5 @@
import { useMemo } from 'react';
import { Input } from '@signozhq/ui/input';
import { Select } from 'antd';
import { Input, Select } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { ADVANCED_OPTIONS_TIME_UNIT_OPTIONS } from '../../context/constants';

View File

@@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Input } from 'antd';
import './TimeInput.scss';
export interface TimeInputProps {

View File

@@ -1,5 +1,4 @@
import { Input } from '@signozhq/ui/input';
import { Select } from 'antd';
import { Input, Select } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { useCreateAlertState } from '../context';

View File

@@ -16,8 +16,7 @@ import {
Plus,
X,
} from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Button, Card, Modal, Popover, Tag, Tooltip } from 'antd';
import { Button, Card, Input, Modal, Popover, Tag, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import ConfigureIcon from 'assets/Integrations/ConfigureIcon';

View File

@@ -395,8 +395,8 @@ describe('Dynamic Variable Default Behavior', () => {
// Check if the checkbox exists (it should be unchecked initially)
const checkbox = allOptionContainer?.querySelector(
'input[type="checkbox"]',
) as HTMLInputElement;
'[role="checkbox"]',
) as HTMLElement;
expect(checkbox).toBeInTheDocument();
// Should call onValueUpdate with all values (ALL selection)
@@ -516,10 +516,10 @@ describe('Dynamic Variable Default Behavior', () => {
// Check if the checkbox for ALL option is checked
const checkbox = dropdownAllOption.querySelector(
'input[type="checkbox"]',
) as HTMLInputElement;
'[role="checkbox"]',
) as HTMLElement;
expect(checkbox).toBeInTheDocument();
expect(checkbox.checked).toBe(true);
expect(checkbox).toHaveAttribute('data-state', 'checked');
});
});
});

View File

@@ -196,10 +196,10 @@ describe('Panel Management Tests', () => {
expect(allOption).toHaveClass('selected');
const allCheckbox = allOption.querySelector(
'input[type="checkbox"]',
) as HTMLInputElement;
'[role="checkbox"]',
) as HTMLElement;
expect(allCheckbox).toBeInTheDocument();
expect(allCheckbox.checked).toBe(true);
expect(allCheckbox).toHaveAttribute('data-state', 'checked');
});
});

View File

@@ -1,6 +1,5 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Button } from 'antd';
import { Button, Input } from 'antd';
import { PrecisionOption, PrecisionOptionsEnum } from 'components/Graph/types';
import { ResizeTable } from 'components/ResizeTable';
import { useNotifications } from 'hooks/useNotifications';

View File

@@ -160,8 +160,8 @@ describe('getChartManagerColumns', () => {
expect(renderFn).toBeDefined();
const { container } = render(renderFn!(null, tableDataSet[1], 1));
const checkbox = container.querySelector('input[type="checkbox"]');
const checkbox = container.querySelector('[role="checkbox"]');
expect(checkbox).toBeInTheDocument();
expect(checkbox).toBeChecked(); // graphVisibilityState[1] is true
expect(checkbox).toHaveAttribute('data-state', 'checked'); // graphVisibilityState[1] is true
});
});

View File

@@ -1,147 +0,0 @@
import { renderHook } from '@testing-library/react';
import { UseQueryResult } from 'react-query';
import { SuccessResponse } from 'types/api';
import { Widgets } from 'types/api/dashboard/getAll';
import { MetricRangePayloadProps } from 'types/api/metrics/getQueryRange';
import { usePanelContextMenu } from '../usePanelContextMenu';
// The hook composes `useCoordinates` (popover state) and `useGraphContextMenu`
// (menu items). We mock both so the test focuses on the `enableDrillDown` gate
// rather than the implementation of the menu wiring itself.
const onClickMock = jest.fn();
jest.mock('periscope/components/ContextMenu', () => ({
useCoordinates: (): unknown => ({
coordinates: null,
popoverPosition: null,
clickedData: null,
onClose: jest.fn(),
subMenu: null,
onClick: onClickMock,
setSubMenu: jest.fn(),
}),
}));
jest.mock('container/QueryTable/Drilldown/useGraphContextMenu', () => ({
__esModule: true,
default: (): { menuItemsConfig: { header: string; items: string } } => ({
menuItemsConfig: { header: 'menu-header', items: 'menu-items' },
}),
}));
jest.mock('container/QueryTable/Drilldown/drilldownUtils', () => ({
getUplotClickData: jest.fn(() => ({
coord: { x: 1, y: 2 },
record: { queryName: 'A', filters: [] },
label: 'lbl',
seriesColor: '#abc',
})),
}));
jest.mock('container/PanelWrapper/utils', () => ({
isApmMetric: jest.fn(() => false),
getTimeRangeFromStepInterval: jest.fn(() => ({ start: 0, end: 0 })),
}));
const mockWidget = { id: 'w-1', query: {} } as unknown as Widgets;
const mockQueryResponse = {
data: undefined,
isLoading: false,
} as unknown as UseQueryResult<
SuccessResponse<MetricRangePayloadProps, unknown>,
Error
>;
describe('usePanelContextMenu', () => {
beforeEach(() => {
onClickMock.mockClear();
});
it('returns empty menuItemsConfig when enableDrillDown is false', () => {
const { result } = renderHook(() =>
usePanelContextMenu({
widget: mockWidget,
queryResponse: mockQueryResponse,
enableDrillDown: false,
}),
);
expect(result.current.menuItemsConfig).toStrictEqual({});
});
it('returns wired menuItemsConfig when enableDrillDown is true', () => {
const { result } = renderHook(() =>
usePanelContextMenu({
widget: mockWidget,
queryResponse: mockQueryResponse,
enableDrillDown: true,
}),
);
expect(result.current.menuItemsConfig).toStrictEqual({
header: 'menu-header',
items: 'menu-items',
});
});
it('clickHandlerWithContextMenu is a no-op when enableDrillDown is false', () => {
const { result } = renderHook(() =>
usePanelContextMenu({
widget: mockWidget,
queryResponse: mockQueryResponse,
enableDrillDown: false,
}),
);
result.current.clickHandlerWithContextMenu(
100, // xValue
200, // yValue
0, // mouseX
0, // mouseY
{ serviceName: 'svc' }, // metric
{ queryName: 'A', inFocusOrNot: true }, // queryData
10, // absoluteMouseX
20, // absoluteMouseY
{}, // axesData
{ seriesIndex: 0, seriesName: 'A', value: 1, color: '#abc' }, // focusedSeries
);
expect(onClickMock).not.toHaveBeenCalled();
});
it('clickHandlerWithContextMenu opens popover when enableDrillDown is true', () => {
const { result } = renderHook(() =>
usePanelContextMenu({
widget: mockWidget,
queryResponse: mockQueryResponse,
enableDrillDown: true,
}),
);
result.current.clickHandlerWithContextMenu(
100,
200,
0,
0,
{ serviceName: 'svc' },
{ queryName: 'A', inFocusOrNot: true },
10,
20,
{},
{ seriesIndex: 0, seriesName: 'A', value: 1, color: '#abc' },
);
expect(onClickMock).toHaveBeenCalledTimes(1);
});
it('defaults to disabled when enableDrillDown is not provided', () => {
const { result } = renderHook(() =>
usePanelContextMenu({
widget: mockWidget,
queryResponse: mockQueryResponse,
}),
);
expect(result.current.menuItemsConfig).toStrictEqual({});
});
});

View File

@@ -21,13 +21,11 @@ interface UseTimeSeriesContextMenuParams {
SuccessResponse<MetricRangePayloadProps, unknown>,
Error
>;
enableDrillDown?: boolean;
}
export const usePanelContextMenu = ({
widget,
queryResponse,
enableDrillDown = false,
}: UseTimeSeriesContextMenuParams): {
coordinates: { x: number; y: number } | null;
popoverPosition: PopoverPosition | null;
@@ -63,9 +61,6 @@ export const usePanelContextMenu = ({
const clickHandlerWithContextMenu = useCallback(
(...args: any[]) => {
if (!enableDrillDown) {
return;
}
const [
xValue,
_yvalue,
@@ -117,14 +112,14 @@ export const usePanelContextMenu = ({
});
}
},
[enableDrillDown, onClick, queryResponse],
[onClick, queryResponse],
);
return {
coordinates,
popoverPosition,
onClose,
menuItemsConfig: enableDrillDown ? menuItemsConfig : {},
menuItemsConfig,
clickHandlerWithContextMenu,
};
};

View File

@@ -31,7 +31,6 @@ function BarPanel(props: PanelWrapperProps): JSX.Element {
isFullViewMode,
onToggleModelHandler,
groupByPerQuery,
enableDrillDown = false,
} = props;
const uPlotRef = useRef<uPlot | null>(null);
const graphRef = useRef<HTMLDivElement>(null);
@@ -62,7 +61,6 @@ function BarPanel(props: PanelWrapperProps): JSX.Element {
} = usePanelContextMenu({
widget,
queryResponse,
enableDrillDown,
});
const config = useMemo(() => {

View File

@@ -31,7 +31,6 @@ function TimeSeriesPanel(props: PanelWrapperProps): JSX.Element {
isFullViewMode,
onToggleModelHandler,
groupByPerQuery,
enableDrillDown = false,
} = props;
const graphRef = useRef<HTMLDivElement>(null);
const [minTimeScale, setMinTimeScale] = useState<number>();
@@ -61,7 +60,6 @@ function TimeSeriesPanel(props: PanelWrapperProps): JSX.Element {
} = usePanelContextMenu({
widget,
queryResponse,
enableDrillDown,
});
const chartData = useMemo(() => {

View File

@@ -19,11 +19,11 @@ import {
Info,
} from '@signozhq/icons';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import {
Button,
ColorPicker,
Divider,
Input,
Modal,
RefSelectProps,
Select,

View File

@@ -1,7 +1,7 @@
import { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { Form, Input } from 'antd';
import { EmailChannel } from '../../CreateAlertChannels/config';
function EmailForm({ setSelectedConfig }: EmailFormProps): JSX.Element {

View File

@@ -1,7 +1,6 @@
import { Dispatch, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { Form, Input } from 'antd';
import { MarkdownRenderer } from 'components/MarkdownRenderer/MarkdownRenderer';
import { WebhookChannel } from '../../CreateAlertChannels/config';

View File

@@ -1,7 +1,6 @@
import { Dispatch, ReactElement, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { Input } from '@signozhq/ui/input';
import { Form, FormInstance, Select, Switch } from 'antd';
import { Form, FormInstance, Input, Select, Switch } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import type { Store } from 'antd/lib/form/interface';
import ROUTES from 'constants/routes';

View File

@@ -1,6 +1,6 @@
import { grey } from '@ant-design/colors';
import { Checkbox, ConfigProvider } from 'antd';
import type { CheckboxChangeEvent } from 'antd/es/checkbox';
import { Checkbox } from '@signozhq/ui/checkbox';
import { CSSProperties } from 'react';
import { CheckBoxProps } from '../types';
@@ -11,30 +11,22 @@ function CustomCheckBox({
checkBoxOnChangeHandler,
disabled = false,
}: CheckBoxProps): JSX.Element {
const onChangeHandler = (e: CheckboxChangeEvent): void => {
checkBoxOnChangeHandler(e, index);
};
const color = data[index]?.stroke?.toString() || grey[0];
const isChecked = graphVisibilityState[index] || false;
const colorStyle = {
'--checkbox-checked-background': color,
'--checkbox-border-color': color,
} as CSSProperties;
return (
<ConfigProvider
theme={{
token: {
colorPrimary: color,
colorBorder: color,
colorBgContainer: color,
},
}}
>
<span style={colorStyle}>
<Checkbox
onChange={onChangeHandler}
checked={isChecked}
onChange={(checked): void => checkBoxOnChangeHandler(checked, index)}
value={isChecked}
disabled={disabled}
/>
</ConfigProvider>
</span>
);
}

View File

@@ -292,8 +292,6 @@ function FullView({
return <Spinner height="100%" size="large" tip="Loading..." />;
}
const showEditBtn = editWidget && dashboardEditView;
return (
<div className="full-view-container">
<OverlayScrollbar>
@@ -308,7 +306,7 @@ function FullView({
Reset Query
</Button>
)}
{showEditBtn && (
{editWidget && (
<Button
className="switch-edit-btn"
disabled={response.isFetching || response.isLoading}

View File

@@ -1,5 +1,4 @@
import { Dispatch, MutableRefObject, RefObject, SetStateAction } from 'react';
import type { CheckboxChangeEvent } from 'antd/es/checkbox';
import { ToggleGraphProps } from 'components/Graph/types';
import { UplotProps } from 'components/Uplot/Uplot';
import { PANEL_TYPES } from 'constants/queryBuilder';
@@ -77,7 +76,10 @@ export interface CheckBoxProps {
data: ExtendedChartDataset[];
index: number;
graphVisibilityState: boolean[];
checkBoxOnChangeHandler: (e: CheckboxChangeEvent, index: number) => void;
checkBoxOnChangeHandler: (
checked: boolean | 'indeterminate',
index: number,
) => void;
disabled?: boolean;
}

View File

@@ -6,8 +6,7 @@ import { useIsFetching } from 'react-query';
import { useDispatch } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import { Button, Form, Modal } from 'antd';
import { Button, Form, Input, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';

View File

@@ -5,12 +5,12 @@ import { useCopyToClipboard } from 'react-use';
import { Color } from '@signozhq/design-tokens';
import { Badge } from '@signozhq/ui/badge';
import { Button } from '@signozhq/ui/button';
import { Input } from '@signozhq/ui/input';
import {
Col,
Collapse,
DatePicker,
Form,
Input,
InputNumber,
Modal,
Row,

View File

@@ -1,5 +1,5 @@
import { Dispatch, SetStateAction } from 'react';
import { Checkbox } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { useRegionSelection } from 'hooks/integration/aws/useRegionSelection';
import { regions } from 'utils/regions';
@@ -21,18 +21,18 @@ export function RegionSelector({
setIncludeAllRegions,
});
const allSelected =
allRegionIds.length > 0 &&
allRegionIds.every((regionId) => selectedRegions.includes(regionId));
const someSelected =
selectedRegions.length > 0 && selectedRegions.length < allRegionIds.length;
return (
<div className="region-selector">
<div className="select-all">
<Checkbox
checked={
allRegionIds.length > 0 &&
allRegionIds.every((regionId) => selectedRegions.includes(regionId))
}
indeterminate={
selectedRegions.length > 0 && selectedRegions.length < allRegionIds.length
}
onChange={(e): void => handleSelectAll(e.target.checked)}
value={allSelected ? true : someSelected ? 'indeterminate' : false}
onChange={(checked): void => handleSelectAll(checked === true)}
>
Select All Regions
</Checkbox>
@@ -45,7 +45,7 @@ export function RegionSelector({
{region.subRegions.map((subRegion) => (
<Checkbox
key={subRegion.id}
checked={selectedRegions.includes(subRegion.id)}
value={selectedRegions.includes(subRegion.id)}
onChange={(): void => handleRegionSelect(subRegion.id)}
>
{subRegion.name}

View File

@@ -1,5 +1,4 @@
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { Form, Input } from 'antd';
import { CloudintegrationtypesCredentialsDTO } from 'api/generated/services/sigNoz.schemas';
function RenderConnectionFields({

View File

@@ -1,7 +1,6 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Input } from '@signozhq/ui/input';
import { Button, Form } from 'antd';
import { Button, Form, Input } from 'antd';
import apply from 'api/v3/licenses/post';
import { useNotifications } from 'hooks/useNotifications';
import APIError from 'types/api/error';

View File

@@ -1,7 +1,6 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { ChangeEvent, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Button, Modal } from 'antd';
import { Button, Input, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import ApacheIcon from 'assets/CustomIcons/ApacheIcon';
import DockerIcon from 'assets/CustomIcons/DockerIcon';

View File

@@ -12,11 +12,11 @@ import { useTranslation } from 'react-i18next';
import { generatePath } from 'react-router-dom';
import { useCopyToClipboard } from 'react-use';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import {
Button,
Dropdown,
Flex,
Input,
MenuProps,
Modal,
Popover,

View File

@@ -1,8 +1,7 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { LoaderCircle, Check } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Button, Space } from 'antd';
import { Button, Input, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import { useNotifications } from 'hooks/useNotifications';

View File

@@ -2,8 +2,7 @@ import { ReactNode, useState } from 'react';
import MEditor, { EditorProps, Monaco } from '@monaco-editor/react';
import { Color } from '@signozhq/design-tokens';
import { Button } from '@signozhq/ui/button';
import { Input } from '@signozhq/ui/input';
import { Collapse, Divider, Switch, Tag } from 'antd';
import { Collapse, Divider, Input, Switch, Tag } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { AddToQueryHOCProps } from 'components/Logs/AddToQueryHOC';
import { ChangeViewFunctionType } from 'container/ExplorerOptions/types';

View File

@@ -2,8 +2,7 @@ import { ChangeEvent, useCallback, useState } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { CirclePlus, X } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Col } from 'antd';
import { Col, Input } from 'antd';
import CategoryHeading from 'components/Logs/CategoryHeading';
import { fieldSearchFilter } from 'lib/logs/fieldSearch';
import { AppState } from 'store/reducers';

View File

@@ -2,8 +2,7 @@ import { useCallback, useMemo, useState } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { SquareX, X } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Button, Select } from 'antd';
import { Button, Input, Select } from 'antd';
import CategoryHeading from 'components/Logs/CategoryHeading';
import {
ConditionalOperators,

View File

@@ -30,12 +30,7 @@ import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import {
GraphTitle,
MENU_ITEMS,
SERVICE_CHART_ID,
SERVICE_DETAIL_DRILLDOWN_ENABLED,
} from '../constant';
import { GraphTitle, MENU_ITEMS, SERVICE_CHART_ID } from '../constant';
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
import { Card, GraphContainer, Row } from '../styles';
import { Button } from './styles';
@@ -211,7 +206,6 @@ function DBCall(): JSX.Element {
}}
onDragSelect={onDragSelect}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
</GraphContainer>
</Card>
@@ -250,7 +244,6 @@ function DBCall(): JSX.Element {
}}
onDragSelect={onDragSelect}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
</GraphContainer>
</Card>

View File

@@ -32,12 +32,7 @@ import { v4 as uuid } from 'uuid';
import { FeatureKeys } from '../../../constants/features';
import { useAppContext } from '../../../providers/App/App';
import {
GraphTitle,
legend,
MENU_ITEMS,
SERVICE_DETAIL_DRILLDOWN_ENABLED,
} from '../constant';
import { GraphTitle, legend, MENU_ITEMS } from '../constant';
import { getWidgetQueryBuilder } from '../MetricsApplication.factory';
import { Card, GraphContainer, Row } from '../styles';
import GraphControlsPanel from './Overview/GraphControlsPanel/GraphControlsPanel';
@@ -284,7 +279,6 @@ function External(): JSX.Element {
}}
onDragSelect={onDragSelect}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
</GraphContainer>
</Card>
@@ -328,7 +322,6 @@ function External(): JSX.Element {
}}
onDragSelect={onDragSelect}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
</GraphContainer>
</Card>
@@ -373,7 +366,6 @@ function External(): JSX.Element {
}
onDragSelect={onDragSelect}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
</GraphContainer>
</Card>
@@ -417,7 +409,6 @@ function External(): JSX.Element {
}}
onDragSelect={onDragSelect}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
</GraphContainer>
</Card>

View File

@@ -15,7 +15,6 @@ import DisplayThreshold from 'container/GridCardLayout/WidgetHeader/DisplayThres
import {
GraphTitle,
SERVICE_CHART_ID,
SERVICE_DETAIL_DRILLDOWN_ENABLED,
} from 'container/MetricsApplication/constant';
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
import { apDexMetricsQueryBuilderQueries } from 'container/MetricsApplication/MetricsPageQueries/OverviewQueries';
@@ -106,7 +105,6 @@ function ApDexMetrics({
threshold={threshold}
isQueryEnabled={isQueryEnabled}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
);
}

View File

@@ -8,7 +8,6 @@ import Graph from 'container/GridCardLayout/GridCard';
import {
GraphTitle,
SERVICE_CHART_ID,
SERVICE_DETAIL_DRILLDOWN_ENABLED,
} from 'container/MetricsApplication/constant';
import { getWidgetQueryBuilder } from 'container/MetricsApplication/MetricsApplication.factory';
import { latency } from 'container/MetricsApplication/MetricsPageQueries/OverviewQueries';
@@ -139,7 +138,6 @@ function ServiceOverview({
onClickHandler={handleGraphClick('Service')}
isQueryEnabled={isQueryEnabled}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
)}
</GraphContainer>

View File

@@ -4,7 +4,6 @@ import axios from 'axios';
import { SOMETHING_WENT_WRONG } from 'constants/api';
import { ENTITY_VERSION_V4 } from 'constants/app';
import Graph from 'container/GridCardLayout/GridCard';
import { SERVICE_DETAIL_DRILLDOWN_ENABLED } from 'container/MetricsApplication/constant';
import { Card, GraphContainer } from 'container/MetricsApplication/styles';
import { OnClickPluginOpts } from 'lib/uPlotLib/plugins/onClickPlugin';
import { Widgets } from 'types/api/dashboard/getAll';
@@ -44,7 +43,6 @@ function TopLevelOperation({
onDragSelect={onDragSelect}
isQueryEnabled={!topLevelOperationsIsLoading}
version={ENTITY_VERSION_V4}
enableDrillDown={SERVICE_DETAIL_DRILLDOWN_ENABLED}
/>
)}
</GraphContainer>

View File

@@ -25,8 +25,6 @@ export const OPERATION_LEGENDS = ['Operations'];
export const MENU_ITEMS = [MenuItemKeys.View, MenuItemKeys.CreateAlerts];
export const SERVICE_DETAIL_DRILLDOWN_ENABLED = true;
export enum FORMULA {
ERROR_PERCENTAGE = 'A*100/B',
DATABASE_CALLS_AVG_DURATION = 'A/B',

View File

@@ -1,7 +1,6 @@
import { Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
// TODO(@signozhq/ui-input): migrate this <Input> once @signozhq/ui Input
// supports the `onWheel` handler (used to blur on scroll for number inputs).
import { Input, Select } from 'antd';
import { Select } from 'antd';
import classNames from 'classnames';
import { TIME_AGGREGATION_OPTIONS } from './constants';

View File

@@ -1,8 +1,7 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useQueryClient } from 'react-query';
import type { TableColumnsType as ColumnsType } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Collapse, Select, Spin } from 'antd';
import { Button, Collapse, Input, Select, Spin } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import {

View File

@@ -1,4 +1,5 @@
import { Checkbox, Empty } from 'antd';
import { Empty } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { AxiosResponse } from 'axios';
import Spinner from 'components/Spinner';
import { EXCLUDED_COLUMNS } from 'container/OptionsMenu/constants';
@@ -50,9 +51,8 @@ function ExplorerAttributeColumns({
<div className="attribute-columns">
{filteredAttributeKeys.map((attributeKey: any) => (
<Checkbox
checked={isAttributeKeySelected(attributeKey.name)}
value={isAttributeKeySelected(attributeKey.name)}
onChange={(): void => handleCheckboxChange(attributeKey.name)}
style={{ padding: 0 }}
key={attributeKey.name}
>
{attributeKey.name}

View File

@@ -7,8 +7,7 @@ import {
DropResult,
} from 'react-beautiful-dnd';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import { Button, Divider, Dropdown, MenuProps, Tooltip } from 'antd';
import { Button, Divider, Dropdown, Input, MenuProps, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { FieldDataType } from 'api/v5/v5';
import { SOMETHING_WENT_WRONG } from 'constants/api';

View File

@@ -1,7 +1,5 @@
import { useEffect, useMemo, useState } from 'react';
// TODO(@signozhq/ui-input): migrate <Input> once @signozhq/ui Input
// supports the `spellCheck` prop on the URL input below.
import { Button, Col, Form, Input, Input as AntInput, Row } from 'antd';
import { Button, Col, Form, Input as AntInput, Input, Row } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { CONTEXT_LINK_FIELDS } from 'container/NewWidget/RightContainer/ContextLinks/constants';
import {

View File

@@ -1,8 +1,7 @@
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Blocks, Check, LoaderCircle } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Button, Card, Form, Select, Space } from 'antd';
import { Button, Card, Form, Input, Select, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';

View File

@@ -1,8 +1,7 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Check, Server, LoaderCircle } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Button, Card, Form, Space } from 'antd';
import { Button, Card, Form, Input, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';

View File

@@ -1,7 +1,6 @@
import { useTranslation } from 'react-i18next';
import { Plus, Trash2 } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Button, Form, FormInstance, Select, Space } from 'antd';
import { Button, Form, FormInstance, Input, Select, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { requireErrorMessage } from 'utils/form/requireErrorMessage';

View File

@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { Form, Input } from 'antd';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { formValidationRules } from '../../config';

View File

@@ -1,6 +1,4 @@
import { ChangeEventHandler, useState } from 'react';
// TODO(@signozhq/ui-input): migrate to @signozhq/ui Input once the antd
// `InputProps` spread (`size`, etc.) is no longer needed on this wrapper.
import { Input, InputProps } from 'antd';
function CSVInput({ value, onChange, ...otherProps }: InputProps): JSX.Element {

View File

@@ -1,7 +1,6 @@
import { useEffect, useState } from 'react';
import { Info } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Flex, Form, Space, Switch, Tooltip } from 'antd';
import { Flex, Form, Input, Space, Switch, Tooltip } from 'antd';
import { ProcessorData } from 'types/api/pipeline/def';
import { PREDEFINED_MAPPING } from '../config';

View File

@@ -1,6 +1,5 @@
import { useTranslation } from 'react-i18next';
import { Input } from '@signozhq/ui/input';
import { Form, Select, Space, Switch } from 'antd';
import { Form, Input, Select, Space, Switch } from 'antd';
import { ModalFooterTitle } from 'container/PipelinePage/styles';
import { ProcessorData } from 'types/api/pipeline/def';

View File

@@ -2,8 +2,7 @@ import React, { ChangeEvent, useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import { Plus, Search } from '@signozhq/icons';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import { Button, Flex, Form, Tooltip } from 'antd';
import { Button, Flex, Form, Input, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import {
useDeleteDowntimeScheduleByID,

View File

@@ -1,7 +1,6 @@
import { useCallback, useMemo, useState } from 'react';
import { useQuery } from 'react-query';
import { Input } from '@signozhq/ui/input';
import { Skeleton } from 'antd';
import { Input, Skeleton } from 'antd';
import { getKeySuggestions } from 'api/querySuggestions/getKeySuggestions';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import { QUERY_BUILDER_KEY_TYPES } from 'constants/antlrQueryConstants';

View File

@@ -169,10 +169,9 @@ describe('drilldownUtils', () => {
// Verify transformations were applied
if (filterExpression) {
// `operation` rewrites to `name` via source-side pass, then `name`
// is dropped by the logs target-side pass (logs has no span-name).
// Rule 2: operationname
expect(filterExpression).toContain(`name = 'GET'`);
expect(filterExpression).not.toContain(`operation = 'GET'`);
expect(filterExpression).not.toContain(`name = 'GET'`);
// Rule 3: span.kind → kind
expect(filterExpression).toContain(`${spanKindKey} = '${spanKindServer}'`);
@@ -263,9 +262,8 @@ describe('drilldownUtils', () => {
const filterExpression = result?.builder.queryData[0]?.filter?.expression;
if (filterExpression) {
// `operation` rewrites to `name` then drops for logs target.
expect(filterExpression).not.toContain(`operation = 'POST'`);
expect(filterExpression).not.toContain(`name = 'POST'`);
// All transformations should be applied
expect(filterExpression).toContain(`name = 'POST'`);
expect(filterExpression).toContain(`${spanKindKey} = '${spanKindClient}'`);
expect(filterExpression).toContain(`status_code_string = 'Error'`);
expect(filterExpression).toContain(`http.status_code = 500`);
@@ -412,9 +410,8 @@ describe('drilldownUtils', () => {
const filterExpression = result?.builder.queryData[0]?.filter?.expression;
if (filterExpression) {
// `operation` rewrites to `name` then drops for logs target.
expect(filterExpression).not.toContain(`operation = 'GET'`);
expect(filterExpression).not.toContain(`name = 'GET'`);
// Transformed attributes
expect(filterExpression).toContain(`name = 'GET'`);
expect(filterExpression).toContain(`${spanKindKey} = '${spanKindServer}'`);
// Preserved non-metric attributes
@@ -502,189 +499,4 @@ describe('drilldownUtils', () => {
});
});
});
describe('getViewQuery target-aware sanitisation (serviceName / name)', () => {
const makeQuery = (
expression: string,
dataSource: 'traces' | 'logs' | 'metrics' = 'traces',
): Query => ({
id: 'src-query',
queryType: 'builder' as any,
builder: {
queryData: [
{
queryName: 'src',
dataSource: dataSource as any,
aggregations: [{ metricName: 'non_apm_metric' }] as any,
groupBy: [],
expression: '',
disabled: false,
functions: [],
legend: '',
having: [],
limit: null,
stepInterval: undefined,
orderBy: [],
filter: { expression },
},
],
queryFormulas: [],
queryTraceOperator: [],
},
promql: [],
clickhouse_sql: [],
});
it('rewrites serviceName -> service.name when drilling to logs', () => {
const result = getViewQuery(
makeQuery(`serviceName = 'svc'`),
[],
'view_logs',
'src',
);
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).toContain(`service.name = 'svc'`);
expect(expr).not.toContain('serviceName');
});
it('rewrites serviceName -> service.name when drilling to traces', () => {
const result = getViewQuery(
makeQuery(`serviceName = 'svc'`),
[],
'view_traces',
'src',
);
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).toContain(`service.name = 'svc'`);
expect(expr).not.toContain('serviceName');
});
it('drops `name` clause when drilling to logs', () => {
const result = getViewQuery(
makeQuery(`name = 'GET /api'`),
[],
'view_logs',
'src',
);
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).not.toContain(`name = 'GET /api'`);
});
it('keeps `name` clause when drilling to traces', () => {
const result = getViewQuery(
makeQuery(`name = 'GET /api'`),
[],
'view_traces',
'src',
);
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).toContain(`name = 'GET /api'`);
});
it('combined: drilling to logs rewrites serviceName and drops name', () => {
const result = getViewQuery(
makeQuery(`serviceName = 'svc' AND name = 'GET /api'`),
[],
'view_logs',
'src',
);
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).toContain(`service.name = 'svc'`);
expect(expr).not.toContain('serviceName');
expect(expr).not.toContain(`name = 'GET /api'`);
});
it('combined: drilling to traces rewrites serviceName and keeps name', () => {
const result = getViewQuery(
makeQuery(`serviceName = 'svc' AND name = 'GET /api'`),
[],
'view_traces',
'src',
);
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).toContain(`service.name = 'svc'`);
expect(expr).toContain(`name = 'GET /api'`);
expect(expr).not.toContain('serviceName');
});
it('metric-APM source -> traces target preserves existing operation -> name rewrite', () => {
const metricsQuery: Query = {
id: 'apm-metrics',
queryType: 'builder' as any,
builder: {
queryData: [
{
queryName: 'm',
dataSource: 'metrics' as any,
aggregations: [{ metricName: 'signoz_calls_total' }] as any,
groupBy: [],
expression: '',
disabled: false,
functions: [],
legend: '',
having: [],
limit: null,
stepInterval: undefined,
orderBy: [],
filter: { expression: `operation = 'GET'` },
},
],
queryFormulas: [],
queryTraceOperator: [],
},
promql: [],
clickhouse_sql: [],
};
const result = getViewQuery(metricsQuery, [], 'view_traces', 'm');
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).toContain(`name = 'GET'`);
expect(expr).not.toContain(`operation = 'GET'`);
});
it('metric-APM source -> logs target: operation rewrites to name, then dropped', () => {
const metricsQuery: Query = {
id: 'apm-metrics',
queryType: 'builder' as any,
builder: {
queryData: [
{
queryName: 'm',
dataSource: 'metrics' as any,
aggregations: [{ metricName: 'signoz_calls_total' }] as any,
groupBy: [],
expression: '',
disabled: false,
functions: [],
legend: '',
having: [],
limit: null,
stepInterval: undefined,
orderBy: [],
filter: { expression: `operation = 'GET'` },
},
],
queryFormulas: [],
queryTraceOperator: [],
},
promql: [],
clickhouse_sql: [],
};
const result = getViewQuery(metricsQuery, [], 'view_logs', 'm');
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).not.toContain(`operation = 'GET'`);
expect(expr).not.toContain(`name = 'GET'`);
});
it('drilling to metrics does not apply target-side sanitisation', () => {
const result = getViewQuery(
makeQuery(`serviceName = 'svc' AND name = 'GET /api'`),
[],
'view_metrics',
'src',
);
const expr = result?.builder.queryData[0]?.filter?.expression || '';
expect(expr).toContain('serviceName');
expect(expr).toContain(`name = 'GET /api'`);
});
});
});

View File

@@ -7,10 +7,8 @@ import {
import ROUTES from 'constants/routes';
import { isApmMetric } from 'container/PanelWrapper/utils';
import {
applyMappingsToExpression,
DRILLDOWN_TO_LOGS_MAPPINGS,
DRILLDOWN_TO_TRACES_MAPPINGS,
METRIC_TO_LOGS_TRACES_MAPPINGS,
replaceKeysAndValuesInExpression,
} from 'container/QueryTable/Drilldown/metricsCorrelationUtils';
import cloneDeep from 'lodash-es/cloneDeep';
import {
@@ -349,41 +347,27 @@ export const getViewQuery = (
newQuery.builder.queryData[0].filter = newFilterExpression;
try {
// Drill-down filter sanitisation. Two stages:
// 1. Source-side: rewrite metric-APM-specific keys (operation, span.kind,
// status.code) so they map onto trace/log columns.
// 2. Target-side: normalise legacy keys to OTel-canonical (`serviceName`
// -> `service.name`) and drop keys with no equivalent in the target
// datasource (e.g. `name` for logs).
let expression = newFilterExpression?.expression || '';
// ===========================================
// TEMP LOGIC - TO BE REMOVED LATER
// ===========================================
// Apply metric-to-logs/traces transformations
const specificQuery = getQueryData(query, queryName);
const isMetricQuery = specificQuery?.dataSource === 'metrics';
const metricName = (specificQuery?.aggregations?.[0] as MetricAggregation)
?.metricName;
if (isMetricQuery && isApmMetric(metricName || '')) {
expression = applyMappingsToExpression(
expression,
const transformedExpression = replaceKeysAndValuesInExpression(
newFilterExpression?.expression || '',
METRIC_TO_LOGS_TRACES_MAPPINGS,
);
newQuery.builder.queryData[0].filter = {
expression: transformedExpression || '',
};
}
if (key === 'view_logs') {
expression = applyMappingsToExpression(
expression,
DRILLDOWN_TO_LOGS_MAPPINGS,
);
} else if (key === 'view_traces') {
expression = applyMappingsToExpression(
expression,
DRILLDOWN_TO_TRACES_MAPPINGS,
);
}
newQuery.builder.queryData[0].filter = { expression };
// ===========================================
} catch (error) {
console.error('Error sanitising drilldown filter expression:', error);
console.error('Error transforming metrics to logs/traces:', error);
}
return newQuery;

View File

@@ -1,8 +1,5 @@
/* eslint-disable sonarjs/cognitive-complexity */
import {
formatValueForExpression,
removeKeysFromExpression,
} from 'components/QueryBuilderV2/utils';
import { formatValueForExpression } from 'components/QueryBuilderV2/utils';
import { getOperatorValue } from 'container/QueryBuilder/filters/QueryBuilderSearch/utils';
import { IQueryPair } from 'types/antlrQueryTypes';
import { extractQueryPairs } from 'utils/queryContextUtils';
@@ -11,7 +8,7 @@ import { isFunctionOperator, isNonValueOperator } from 'utils/tokenUtils';
type KeyValueMapping = {
attribute: string;
newAttribute: string | null;
newAttribute: string;
valueMappings: Record<string, string>;
};
@@ -43,33 +40,8 @@ export const METRIC_TO_LOGS_TRACES_MAPPINGS: KeyValueMapping[] = [
},
];
export const DRILLDOWN_TO_LOGS_MAPPINGS: KeyValueMapping[] = [
{
attribute: 'serviceName',
newAttribute: 'service.name',
valueMappings: {},
},
{
attribute: 'name',
newAttribute: null,
valueMappings: {},
},
];
export const DRILLDOWN_TO_TRACES_MAPPINGS: KeyValueMapping[] = [
{
attribute: 'serviceName',
newAttribute: 'service.name',
valueMappings: {},
},
];
// Logic for rewriting key/values in an expression using provided mappings.
// Callers must pre-filter mappings to ensure newAttribute is non-null.
function modifyKeyVal(
pair: IQueryPair,
mapping: KeyValueMapping & { newAttribute: string },
): string {
function modifyKeyVal(pair: IQueryPair, mapping: KeyValueMapping): string {
const newKey = mapping.newAttribute;
const op = pair.operator;
@@ -135,18 +107,8 @@ export function replaceKeysAndValuesInExpression(
return expression;
}
// Only rewrite mappings (newAttribute non-null) are processed here.
// Drops are handled separately by applyMappingsToExpression via removeKeysFromExpression.
const attributeToMapping = new Map<
string,
KeyValueMapping & { newAttribute: string }
>(
mappingList
.filter(
(m): m is KeyValueMapping & { newAttribute: string } =>
m.newAttribute !== null,
)
.map((m) => [m.attribute.trim().toLowerCase(), m]),
const attributeToMapping = new Map<string, KeyValueMapping>(
mappingList.map((m) => [m.attribute.trim().toLowerCase(), m]),
);
const pairs: IQueryPair[] = extractQueryPairs(expression);
@@ -217,26 +179,3 @@ export function replaceKeysAndValuesInExpression(
return resultParts.join('');
}
// Apply a list of mappings to a filter expression. Rewrites are applied first
// (newAttribute is a string), then drops (newAttribute is null) via the
// ANTLR-parser-based removeKeysFromExpression which handles AND/OR/NOT/paren
// elision correctly.
export function applyMappingsToExpression(
expression: string,
mappings: KeyValueMapping[],
): string {
if (!expression || !mappings || mappings.length === 0) {
return expression;
}
const dropKeys = mappings
.filter((m) => m.newAttribute === null)
.map((m) => m.attribute);
let result = replaceKeysAndValuesInExpression(expression, mappings);
if (dropKeys.length > 0) {
result = removeKeysFromExpression(result, dropKeys);
}
return result;
}

View File

@@ -1,8 +1,7 @@
import { ChangeEvent, useMemo } from 'react';
import { Plus, Search } from '@signozhq/icons';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import { Button, Flex, Tooltip } from 'antd';
import { Button, Flex, Input, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { useAppContext } from 'providers/App/App';
import { USER_ROLES } from 'types/roles';

View File

@@ -1,5 +1,5 @@
import { useCallback, useMemo, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC';

View File

@@ -1,6 +1,5 @@
import { useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Collapse, Modal } from 'antd';
import { Collapse, Input, Modal } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { getYAxisFormattedValue } from 'components/Graph/yAxisConfig';
import { Diamond } from '@signozhq/icons';

View File

@@ -9,10 +9,10 @@ import {
useState,
} from 'react';
import { useMutation, useQuery } from 'react-query';
import { Input } from '@signozhq/ui/input';
import {
Button,
Checkbox,
Input,
Modal,
Select,
Skeleton,

View File

@@ -4,9 +4,9 @@ import { useDispatch, useSelector } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { useInterval } from 'react-use';
import { Check, ChevronDown } from '@signozhq/icons';
import { Button, Checkbox, Popover } from 'antd';
import { Button, Popover } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Typography } from '@signozhq/ui/typography';
import type { CheckboxChangeEvent } from 'antd/lib/checkbox';
import get from 'api/browser/localstorage/get';
import set from 'api/browser/localstorage/set';
import { DASHBOARD_TIME_IN_DURATION } from 'constants/app';
@@ -132,8 +132,8 @@ function AutoRefresh({
);
const onChangeAutoRefreshHandler = useCallback(
(event: CheckboxChangeEvent) => {
const { checked } = event.target;
(value: boolean | 'indeterminate') => {
const checked = value === true;
if (!checked) {
// remove the path from localstorage
set(
@@ -168,7 +168,7 @@ function AutoRefresh({
<div className="auto-refresh-menu">
<Checkbox
onChange={onChangeAutoRefreshHandler}
checked={isAutoRefreshEnabled}
value={isAutoRefreshEnabled}
disabled={isDisabled}
className="auto-refresh-checkbox"
>

View File

@@ -1,7 +1,8 @@
import { useMemo, useState } from 'react';
// eslint-disable-next-line no-restricted-imports
import { useDispatch, useSelector } from 'react-redux';
import { Checkbox, Tooltip } from 'antd';
import { Tooltip } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Typography } from '@signozhq/ui/typography';
import getFilters from 'api/trace/getFilters';
import { AxiosError } from 'axios';
@@ -174,8 +175,7 @@ function CheckBoxComponent(props: CheckBoxProps): JSX.Element {
<Checkbox
disabled={isLoading || filterLoading}
onClick={onCheckHandler}
checked={isCheckBoxSelected}
defaultChecked
value={isCheckBoxSelected}
key={keyValue}
>
<Tooltip overlay={TooTipOverLay}>

View File

@@ -1,7 +1,5 @@
// TODO(@signozhq/ui-input): migrate this styled(Input) once @signozhq/ui
// Input supports `addonAfter` (the consumer renders `<InputComponent addonAfter="ms">`).
import { Typography } from '@signozhq/ui/typography';
import { Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import styled from 'styled-components';
export const DurationText = styled.div`

View File

@@ -8,8 +8,7 @@ import {
import { useQuery } from 'react-query';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { Input } from '@signozhq/ui/input';
import { AutoComplete } from 'antd';
import { AutoComplete, Input } from 'antd';
import getTagFilters from 'api/trace/getTagFilter';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -2,8 +2,7 @@ import { useMemo, useState } from 'react';
import { useQuery } from 'react-query';
// eslint-disable-next-line no-restricted-imports
import { useSelector } from 'react-redux';
import { Input } from '@signozhq/ui/input';
import { AutoComplete, Space } from 'antd';
import { AutoComplete, Input, Space } from 'antd';
import getTagFilters from 'api/trace/getTagFilter';
import { AppState } from 'store/reducers';
import { GlobalReducer } from 'types/reducer/globalTime';

View File

@@ -1,7 +1,6 @@
import { ChangeEvent, useEffect, useMemo, useState } from 'react';
import { ArrowLeft, Check, Loader, Plus, Search } from '@signozhq/icons';
import { Input } from '@signozhq/ui/input';
import { Button, Spin } from 'antd';
import { Button, Input, Spin } from 'antd';
import cx from 'classnames';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import SignozModal from 'components/SignozModal/SignozModal';

View File

@@ -1,4 +1,4 @@
import { Input } from '@signozhq/ui/input';
import { Input } from 'antd';
import styled from 'styled-components';
export const InputComponent = styled(Input)`

View File

@@ -1,6 +1,5 @@
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { Input } from '@signozhq/ui/input';
import { Select } from 'antd';
import { Input, Select } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import './DropRateView.styles.scss';

View File

@@ -3,8 +3,7 @@ import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import { Button } from '@signozhq/ui/button';
import { Input } from '@signozhq/ui/input';
import { ColorPicker, Modal, Table, TableProps } from 'antd';
import { ColorPicker, Input, Modal, Table, TableProps } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import {

View File

@@ -119,12 +119,6 @@
flex-shrink: 0;
}
.statusMessageBadge {
width: 100%;
min-width: 0;
box-sizing: border-box;
}
.traceId {
color: var(--accent-primary);
overflow: hidden;

View File

@@ -1,5 +1,5 @@
import { Input } from '@signozhq/ui/input';
import { Checkbox, Select, Skeleton } from 'antd';
import { Input, Select, Skeleton } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { Button } from '@signozhq/ui/button';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
@@ -105,12 +105,12 @@ function SpanPercentilePanel({
.map((attr) => (
<div className={styles.resourceSelectorItem} key={attr.key}>
<Checkbox
checked={attr.isSelected}
onChange={(e): void => {
value={attr.isSelected}
onChange={(checked): void => {
handleResourceAttributeChange(
attr.key,
attr.value,
e.target.checked,
checked === true,
);
}}
disabled={

View File

@@ -1,6 +1,5 @@
import { ReactNode } from 'react';
import { Badge } from '@signozhq/ui/badge';
import ExpandableValue from 'periscope/components/ExpandableValue';
import { SpanV3 } from 'types/api/trace/getTraceV3';
import styles from './SpanDetailsPanel.module.scss';
@@ -49,15 +48,7 @@ export const HIGHLIGHTED_OPTIONS: HighlightedOption[] = [
label: 'STATUS MESSAGE',
render: (span): ReactNode | null =>
span.status_message ? (
<ExpandableValue value={span.status_message} title="Status message">
<Badge
color="vanilla"
textEllipsis="end"
className={styles.statusMessageBadge}
>
{span.status_message}
</Badge>
</ExpandableValue>
<Badge color="vanilla">{span.status_message}</Badge>
) : null,
},
];

View File

@@ -1,3 +0,0 @@
.traceOptionsDropdown {
z-index: 1100;
}

View File

@@ -6,8 +6,6 @@ import { Ellipsis } from '@signozhq/icons';
import { useTraceStore } from '../stores/traceStore';
import styles from './TraceOptionsMenu.module.scss';
interface TraceOptionsMenuProps {
showTraceDetails: boolean;
onToggleTraceDetails: () => void;
@@ -84,11 +82,7 @@ function TraceOptionsMenu({
]);
return (
<Dropdown
menu={{ items: menuItems }}
align="start"
className={styles.traceOptionsDropdown}
>
<Dropdown menu={{ items: menuItems }} align="start">
<Button
variant="ghost"
size="icon"

View File

@@ -1,7 +1,6 @@
import { ChangeEvent, useEffect, useMemo, useState } from 'react';
import { Button } from '@signozhq/ui/button';
import { Input } from '@signozhq/ui/input';
import { Spin } from 'antd';
import { Input, Spin } from 'antd';
import cx from 'classnames';
import OverlayScrollbar from 'components/OverlayScrollbar/OverlayScrollbar';
import SignozModal from 'components/SignozModal/SignozModal';

View File

@@ -6,8 +6,8 @@ import {
useMemo,
useState,
} from 'react';
import { Button, Card, Checkbox, Input, Tooltip } from 'antd';
import type { CheckboxChangeEvent } from 'antd/es/checkbox';
import { Button, Card, Input, Tooltip } from 'antd';
import { Checkbox } from '@signozhq/ui/checkbox';
import { ParaGraph } from 'container/Trace/Filters/Panel/PanelBody/Common/styles';
import useDebouncedFn from 'hooks/useDebouncedFunction';
import { isArray, isEmpty } from 'lodash-es';
@@ -87,8 +87,11 @@ export function SectionBody(props: SectionBodyProps): JSX.Element {
[results, searchFilter, type, visibleItemsCount],
);
const onCheckHandler = (event: CheckboxChangeEvent, value: string): void => {
const { checked } = event.target;
const onCheckHandler = (
checkedState: boolean | 'indeterminate',
value: string,
): void => {
const checked = checkedState === true;
let newValue = value;
if (type === 'hasError') {
newValue = String(value === 'Error');
@@ -147,9 +150,9 @@ export function SectionBody(props: SectionBodyProps): JSX.Element {
<Checkbox
className="submenu-checkbox"
key={`${type}-${item}`}
onChange={(e): void => onCheckHandler(e, item)}
checked={checkboxMatcher(item)}
data-testid={`${type}-${item}`}
onChange={(checked): void => onCheckHandler(checked, item)}
value={checkboxMatcher(item)}
testId={`${type}-${item}`}
>
<div className="checkbox-label">
<div className={labelClassname(item)} />

View File

@@ -327,9 +327,13 @@ describe('TracesExplorer - Filters', () => {
// check if the default query is applied - composite query has filters - serviceName : demo-app and name : HTTP GET /customer
await expect(findByText('demo-app')).resolves.toBeInTheDocument();
expect(getByTestId('serviceName-demo-app')).toBeChecked();
expect(
getByTestId('serviceName-demo-app').querySelector('[role="checkbox"]'),
).toHaveAttribute('data-state', 'checked');
await expect(findByText('HTTP GET /customer')).resolves.toBeInTheDocument();
expect(getByTestId('name-HTTP GET /customer')).toBeChecked();
expect(
getByTestId('name-HTTP GET /customer').querySelector('[role="checkbox"]'),
).toHaveAttribute('data-state', 'checked');
});
it('test edge cases of undefined filters', async () => {

View File

@@ -1,6 +1,6 @@
import { useState } from 'react';
import { useQueryClient } from 'react-query';
import { Input } from '@signozhq/ui/input';
import { Input } from 'antd';
import SignozModal from 'components/SignozModal/SignozModal';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useRenameFunnel } from 'hooks/TracesFunnels/useFunnels';

View File

@@ -1,7 +1,6 @@
import { ChangeEvent } from 'react';
import { Color } from '@signozhq/design-tokens';
import { Input } from '@signozhq/ui/input';
import { Button, Popover, Tooltip } from 'antd';
import { Button, Input, Popover, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { ArrowDownWideNarrow, Check, Plus, Search } from '@signozhq/icons';
import { useAppContext } from 'providers/App/App';

View File

@@ -1,49 +0,0 @@
.trigger {
display: block;
min-width: 0;
max-width: 100%;
overflow: hidden;
[data-truncated='true'] {
pointer-events: none;
}
}
.tooltipContent {
display: flex;
flex-direction: column;
gap: 8px;
max-width: 480px;
padding: 8px;
}
.preview {
margin: 0;
max-height: 220px;
overflow: auto;
white-space: pre-wrap;
word-break: break-word;
font-family: var(--font-family-mono, monospace);
font-size: 12px;
line-height: 1.4;
}
.expandButton {
align-self: flex-end;
}
.dialog {
max-width: 80vw;
width: 80vw;
}
.fullValue {
margin: 0;
max-height: 70vh;
overflow: auto;
white-space: pre-wrap;
word-break: break-word;
font-family: var(--font-family-mono, monospace);
font-size: 13px;
line-height: 1.5;
}

View File

@@ -1,78 +0,0 @@
import { ReactNode, useState } from 'react';
import { Button } from '@signozhq/ui/button';
import { DialogWrapper } from '@signozhq/ui/dialog';
import {
TooltipContent,
TooltipProvider,
TooltipRoot,
TooltipTrigger,
} from '@signozhq/ui/tooltip';
import { Fullscreen } from '@signozhq/icons';
import styles from './ExpandableValue.module.scss';
const DEFAULT_THRESHOLD = 100;
const DEFAULT_DIALOG_TITLE = 'Value';
const DEFAULT_Z_INDEX = 1100;
interface ExpandableValueProps {
value: string;
title?: string;
threshold?: number;
zIndex?: number;
children: ReactNode;
}
function ExpandableValue({
value,
title = DEFAULT_DIALOG_TITLE,
threshold = DEFAULT_THRESHOLD,
zIndex = DEFAULT_Z_INDEX,
children,
}: ExpandableValueProps): JSX.Element {
const [isDialogOpen, setIsDialogOpen] = useState(false);
if (value.length <= threshold) {
return <>{children}</>;
}
return (
<TooltipProvider>
<TooltipRoot>
<TooltipTrigger asChild>
<span className={styles.trigger}>{children}</span>
</TooltipTrigger>
<TooltipContent
className={styles.tooltipContent}
side="top"
style={{ zIndex }}
>
<pre className={styles.preview}>{value}</pre>
<Button
variant="outlined"
color="secondary"
size="sm"
prefix={<Fullscreen size={14} />}
onClick={(): void => setIsDialogOpen(true)}
className={styles.expandButton}
>
Expand
</Button>
</TooltipContent>
</TooltipRoot>
<DialogWrapper
title={title}
open={isDialogOpen}
onOpenChange={setIsDialogOpen}
className={styles.dialog}
style={{ zIndex }}
>
<pre className={styles.fullValue}>{value}</pre>
</DialogWrapper>
</TooltipProvider>
);
}
export default ExpandableValue;

View File

@@ -1 +0,0 @@
export { default } from './ExpandableValue';

View File

@@ -26,7 +26,7 @@ func buildClusterRecords(
records := make([]inframonitoringtypes.ClusterRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
clusterName := labels[inframonitoringtypes.ClusterNameAttrKey]
clusterName := labels[clusterNameAttrKey]
record := inframonitoringtypes.ClusterRecord{ // initialize with default values
ClusterName: clusterName,
@@ -87,9 +87,6 @@ func (m *module) getTopClusterGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.ClusterNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.ClusterNameAttrKey), nil
}
queryNamesForOrderBy := orderByToClustersQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -7,9 +7,14 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
// TODO(nikhilmantri0902): change to k8s.cluster.uid after showing the missing
// data banner. Carried forward from v1 (see k8sClusterUIDAttrKey in
// pkg/query-service/app/inframetrics/clusters.go).
const clusterNameAttrKey = "k8s.cluster.name"
var clusterNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: inframonitoringtypes.ClusterNameAttrKey,
Name: clusterNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -25,7 +25,7 @@ func buildDaemonSetRecords(
records := make([]inframonitoringtypes.DaemonSetRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
daemonSetName := labels[inframonitoringtypes.DaemonSetNameAttrKey]
daemonSetName := labels[daemonSetNameAttrKey]
record := inframonitoringtypes.DaemonSetRecord{ // initialize with default values
DaemonSetName: daemonSetName,
@@ -95,9 +95,6 @@ func (m *module) getTopDaemonSetGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.DaemonSetNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.DaemonSetNameAttrKey), nil
}
queryNamesForOrderBy := orderByToDaemonSetsQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -7,11 +7,14 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const daemonSetsBaseFilterExpr = "k8s.daemonset.name != ''"
const (
daemonSetNameAttrKey = "k8s.daemonset.name"
daemonSetsBaseFilterExpr = "k8s.daemonset.name != ''"
)
var daemonSetNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: inframonitoringtypes.DaemonSetNameAttrKey,
Name: daemonSetNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -25,7 +25,7 @@ func buildDeploymentRecords(
records := make([]inframonitoringtypes.DeploymentRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
deploymentName := labels[inframonitoringtypes.DeploymentNameAttrKey]
deploymentName := labels[deploymentNameAttrKey]
record := inframonitoringtypes.DeploymentRecord{ // initialize with default values
DeploymentName: deploymentName,
@@ -95,9 +95,6 @@ func (m *module) getTopDeploymentGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.DeploymentNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.DeploymentNameAttrKey), nil
}
queryNamesForOrderBy := orderByToDeploymentsQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -7,11 +7,14 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const deploymentsBaseFilterExpr = "k8s.deployment.name != ''"
const (
deploymentNameAttrKey = "k8s.deployment.name"
deploymentsBaseFilterExpr = "k8s.deployment.name != ''"
)
var deploymentNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: inframonitoringtypes.DeploymentNameAttrKey,
Name: deploymentNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -38,7 +38,7 @@ func (m *module) getPerGroupHostStatusCounts(
uint64(req.Start), uint64(req.End), nil,
)
hostNameExpr := fmt.Sprintf("JSONExtractString(labels, '%s')", inframonitoringtypes.HostNameAttrKey)
hostNameExpr := fmt.Sprintf("JSONExtractString(labels, '%s')", hostNameAttrKey)
sb := sqlbuilder.NewSelectBuilder()
selectCols := make([]string, 0, len(req.GroupBy)+2)
@@ -48,7 +48,7 @@ func (m *module) getPerGroupHostStatusCounts(
)
}
activeHostsSQ := m.getActiveHostsQuery(metricNames, inframonitoringtypes.HostNameAttrKey, sinceUnixMilli)
activeHostsSQ := m.getActiveHostsQuery(metricNames, hostNameAttrKey, sinceUnixMilli)
selectCols = append(selectCols,
fmt.Sprintf("uniqExactIf(%s, %s GLOBAL IN (%s)) AS active_host_count", hostNameExpr, hostNameExpr, sb.Var(activeHostsSQ)),
fmt.Sprintf("uniqExactIf(%s, %s != '') AS total_host_count", hostNameExpr, hostNameExpr),
@@ -142,7 +142,7 @@ func buildHostRecords(
records := make([]inframonitoringtypes.HostRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
hostName := labels[inframonitoringtypes.HostNameAttrKey]
hostName := labels[hostNameAttrKey]
activeStatus := inframonitoringtypes.HostStatusNone
activeHostCount := 0
@@ -216,9 +216,6 @@ func (m *module) getTopHostGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.HostNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.HostNameAttrKey), nil
}
queryNamesForOrderBy := orderByToHostsQueryNames[orderByKey]
// The last entry is the formula/query whose value we sort by.
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]
@@ -284,7 +281,7 @@ func (m *module) applyHostsActiveStatusFilter(req *inframonitoringtypes.Postable
if req.Filter.FilterByStatus == inframonitoringtypes.HostStatusInactive {
op = "NOT IN"
}
statusClause := fmt.Sprintf("%s %s (%s)", inframonitoringtypes.HostNameAttrKey, op, strings.Join(activeHosts, ", "))
statusClause := fmt.Sprintf("%s %s (%s)", hostNameAttrKey, op, strings.Join(activeHosts, ", "))
req.Filter.Expression = mergeFilterExpressions(req.Filter.Expression, statusClause)
return false
}

View File

@@ -7,10 +7,14 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
hostNameAttrKey = "host.name"
)
// Helper group-by key used across all queries.
var hostNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: inframonitoringtypes.HostNameAttrKey,
Name: hostNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

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