Compare commits

...

3 Commits

Author SHA1 Message Date
Gaurav Tewari
e13014baba chore: refactor input 2026-05-22 02:17:01 +05:30
Nikhil Mantri
bf201710a7 feat(infra-monitoring): allow order by primary name column in v2 apis (#11264)
Some checks failed
build-staging / js-build (push) Has been cancelled
build-staging / go-build (push) Has been cancelled
build-staging / staging (push) Has been cancelled
Release Drafter / update_release_draft (push) Has been cancelled
build-staging / prepare (push) Has been cancelled
* chore: baseline setup

* chore: endpoint detail update

* chore: added logic for hosts v3 api

* fix: bug fix

* chore: disk usage

* chore: added validate function

* chore: added some unit tests

* chore: return status as a string

* chore: yarn generate api

* chore: removed isSendingK8sAgentsMetricsCode

* chore: moved funcs

* chore: added validation on order by

* chore: added pods list logic

* chore: updated openapi yml

* chore: updated spec

* chore: pods api meta start time

* chore: nil pointer check

* chore: nil pointer dereference fix in req.Filter

* chore: added temporalities of metrics

* chore: added pods metrics temporality

* chore: unified composite key function

* chore: code improvements

* chore: added pods list api updates

* chore: hostStatusNone added for clarity that this field can be left empty as well in payload

* chore: yarn generate api

* chore: return errors from getMetadata and lint fix

* chore: return errors from getMetadata and lint fix

* chore: added hostName logic

* chore: modified getMetadata query

* chore: add type for response and files rearrange

* chore: warnings added passing from queryResponse warning to host lists response struct

* chore: added better metrics existence check

* chore: added a TODO remark

* chore: added required metrics check

* chore: distributed samples table to local table change for get metadata

* chore: frontend fix

* chore: endpoint correction

* chore: endpoint modification openapi

* chore: escape backtick to prevent sql injection

* chore: rearrage

* chore: improvements

* chore: validate order by to validate function

* chore: improved description

* chore: added TODOs and made filterByStatus a part of filter struct

* chore: ignore empty string hosts in get active hosts

* feat(infra-monitoring): v2 hosts list - return counts of active & inactive hosts for custom group by attributes (#10956)

* chore: add functionality for showing active and inactive counts in custom group by

* chore: bug fix

* chore: added subquery for active and total count

* chore: ignore empty string hosts in get active hosts

* fix: sinceUnixMilli for determining active hosts compute once per request

* chore: refactor code

* chore: rename HostsList -> ListHosts

* chore: rearrangement

* chore: inframonitoring types renaming

* chore: added types package

* chore: file structure further breakdown for clarity

* chore: comments correction

* chore: removed temporalities

* chore: pods code restructuring

* chore: comments resolve

* chore: added json tag required: true

* chore: removed pod metric temporalities

* chore: removed internal server error

* chore: added status unauthorized

* chore: remove a defensive nil map check, the function ensure non-nil map when err nil

* chore: cleanup and rename

* chore: make sort stable in case of tiebreaker by comparing composite group by keys

* chore: regen api client for inframonitoring

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: added phase counts feature

* chore: added queries for pod phase counts in custom group by

* chore: added required tags

* chore: added support for pod phase unknown

* chore: removed pods - order by phase

* chore: improved api description to document -1 as no data in numeric fields

* fix: rebase fixes

* chore: added unknown phase count

* fix: isPodUIDInGroupBy in buildPodRecords

* chore: 3 cte --> 2 cte

* chore: pod phase with local table of time series as counts

* chore: comment correction

* chore: corrected comment

* chore: value column for samples table added

* chore: removed query G for phase counts

* chore: rename variable

* chore: added PodPhaseNum constants to types

* feat(infra-monitoring): v2 pods list apis - phase counts when custom grouping (#11088)

* chore: added phase counts feature

* chore: added queries for pod phase counts in custom group by

* chore: added unknown phase count

* fix: isPodUIDInGroupBy in buildPodRecords

* chore: 3 cte --> 2 cte

* chore: pod phase with local table of time series as counts

* chore: comment correction

* chore: corrected comment

* chore: value column for samples table added

* chore: removed query G for phase counts

* chore: rename variable

* chore: added PodPhaseNum constants to types

* chore: nodes list v2 full blown

* chore: metadata fix

* chore: updated comment

* chore: namespaces code

* chore: v2 nodes api

* chore: rename

* chore: v2 clusters list api

* chore: namespaces code

* chore: rename

* chore: review clusters PR

* chore: pvcs code added

* chore: updated endpoint and spec

* chore: pvcs todo

* chore: added condition

* chore: added filter

* chore: added code for deployments

* chore: query nit

* chore: statefulsets code added

* chore: base filter added

* chore: added base deployments change

* chore: added base condition

* chore: v2 jobs list api added

* chore: added daemonsets api

* chore: added pod phase counts

* chore: for pods and nodes, replace none with no_data

* chore: node and pod counts structs added

* chore: namespace record uses PodCountsByPhase

* chore: cluster record uses PodCountsByPhase, NodeCountsByReadiness

* chore: deployment record uses PodCountsByPhase

* chore: statefulset record uses PodCountsByPhase

* chore: job record uses PodCountsByPhase

* chore: daemonset record uses PodCountsByPhase

* chore: added remaining metrics to check

* chore: metrics existence check

* chore: statefulset metrics added

* chore: added jobs metrics

* chore: added metrics

* chore: feature added

* chore: cosmetic changes

* chore: replaced common order by key with entity specific attr key

* chore: moved paginateByName to types and added unit tests

* chore: added pageGroups

* chore: assert added instead of require

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Ashwin Bhatkal <ashwin96@gmail.com>
2026-05-21 14:55:14 +00:00
Aditya Singh
a5adc52276 feat(trace-details): promote ExpandableValue to periscope + dropdown z-index fix (#11393)
* feat: add expandable value component around status message

* feat: add minor change

* feat: style fix

* feat: remove comment
2026-05-21 12:19:51 +00:00
115 changed files with 1644 additions and 130 deletions

315
INPUT_MIGRATION_AFFECTED.md Normal file
View File

@@ -0,0 +1,315 @@
# 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 'antd';
import { Input } from '@signozhq/ui/input';
import logEvent from 'api/common/logEvent';
import cx from 'classnames';
import { TimezonePickerShortcuts } from 'constants/shortcuts/TimezonePickerShortcuts';

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
/* eslint-disable sonarjs/no-identical-functions */
import { Fragment, useMemo, useState } from 'react';
import { Button, Checkbox, Input, Skeleton } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Checkbox, Skeleton } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import { removeKeysFromExpression } from 'components/QueryBuilderV2/utils';

View File

@@ -1,5 +1,6 @@
import { useMemo } from 'react';
import { Button, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button } 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 { useMemo, useState } from 'react';
import { Button, Input, Select, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, 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,4 +1,5 @@
import { Collapse, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Collapse } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { useCreateAlertState } from '../context';

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,8 @@ import {
Plus,
X,
} from '@signozhq/icons';
import { Button, Card, Input, Modal, Popover, Tag, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Card, 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

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

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 { Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { EmailChannel } from '../../CreateAlertChannels/config';
function EmailForm({ setSelectedConfig }: EmailFormProps): JSX.Element {

View File

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

View File

@@ -1,6 +1,7 @@
import { Dispatch, ReactElement, SetStateAction } from 'react';
import { useTranslation } from 'react-i18next';
import { Form, FormInstance, Input, Select, Switch } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form, FormInstance, 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

@@ -6,7 +6,8 @@ import { useIsFetching } from 'react-query';
import { useDispatch } from 'react-redux';
import { useLocation } from 'react-router-dom';
import { Color } from '@signozhq/design-tokens';
import { Button, Form, Input, Modal } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Form, 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,4 +1,5 @@
import { Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { CloudintegrationtypesCredentialsDTO } from 'api/generated/services/sigNoz.schemas';
function RenderConnectionFields({

View File

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

View File

@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import { ChangeEvent, useState } from 'react';
import { Button, Input, Modal } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, 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,7 +1,8 @@
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { LoaderCircle, Check } from '@signozhq/icons';
import { Button, Input, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Space } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import logEvent from 'api/common/logEvent';
import { useNotifications } from 'hooks/useNotifications';

View File

@@ -2,7 +2,8 @@ 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 { Collapse, Divider, Input, Switch, Tag } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Collapse, Divider, 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,7 +2,8 @@ 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 { Col, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Col } from 'antd';
import CategoryHeading from 'components/Logs/CategoryHeading';
import { fieldSearchFilter } from 'lib/logs/fieldSearch';
import { AppState } from 'store/reducers';

View File

@@ -2,7 +2,8 @@ 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 { Button, Input, Select } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Select } from 'antd';
import CategoryHeading from 'components/Logs/CategoryHeading';
import {
ConditionalOperators,

View File

@@ -1,6 +1,7 @@
import { Input } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import { Select } from 'antd';
// 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 classNames from 'classnames';
import { TIME_AGGREGATION_OPTIONS } from './constants';

View File

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

View File

@@ -7,7 +7,8 @@ import {
DropResult,
} from 'react-beautiful-dnd';
import { Color } from '@signozhq/design-tokens';
import { Button, Divider, Dropdown, Input, MenuProps, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Divider, Dropdown, 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,5 +1,7 @@
import { useEffect, useMemo, useState } from 'react';
import { Button, Col, Form, Input as AntInput, Input, Row } from 'antd';
// 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 { Typography } from '@signozhq/ui/typography';
import { CONTEXT_LINK_FIELDS } from 'container/NewWidget/RightContainer/ContextLinks/constants';
import {

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import { useTranslation } from 'react-i18next';
import { Plus, Trash2 } from '@signozhq/icons';
import { Button, Form, FormInstance, Input, Select, Space } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Form, FormInstance, 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 { Form, Input } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Form } from 'antd';
import { ProcessorFormField } from '../../AddNewProcessor/config';
import { formValidationRules } from '../../config';

View File

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

View File

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

View File

@@ -2,7 +2,8 @@ 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 { Button, Flex, Form, Input, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Flex, Form, Tooltip } from 'antd';
import { Typography } from '@signozhq/ui/typography';
import {
useDeleteDowntimeScheduleByID,

View File

@@ -1,6 +1,7 @@
import { useCallback, useMemo, useState } from 'react';
import { useQuery } from 'react-query';
import { Input, Skeleton } from 'antd';
import { Input } from '@signozhq/ui/input';
import { 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

@@ -1,7 +1,8 @@
import { ChangeEvent, useMemo } from 'react';
import { Plus, Search } from '@signozhq/icons';
import { Color } from '@signozhq/design-tokens';
import { Button, Flex, Input, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, Flex, 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 'antd';
import { Input } from '@signozhq/ui/input';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';
import CopyClipboardHOC from 'components/Logs/CopyClipboardHOC';

View File

@@ -1,5 +1,6 @@
import { useState } from 'react';
import { Collapse, Input, Modal } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Collapse, 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

@@ -1,5 +1,7 @@
import { Input } from 'antd';
// 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 styled from 'styled-components';
export const DurationText = styled.div`

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import { ChangeEvent, useEffect, useMemo, useState } from 'react';
import { ArrowLeft, Check, Loader, Plus, Search } from '@signozhq/icons';
import { Button, Input, Spin } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, 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 'antd';
import { Input } from '@signozhq/ui/input';
import styled from 'styled-components';
export const InputComponent = styled(Input)`

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,5 @@
import { Checkbox, Input, Select, Skeleton } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Checkbox, Select, Skeleton } from 'antd';
import { Button } from '@signozhq/ui/button';
import { Typography } from '@signozhq/ui/typography';
import cx from 'classnames';

View File

@@ -1,5 +1,6 @@
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';
@@ -48,7 +49,15 @@ export const HIGHLIGHTED_OPTIONS: HighlightedOption[] = [
label: 'STATUS MESSAGE',
render: (span): ReactNode | null =>
span.status_message ? (
<Badge color="vanilla">{span.status_message}</Badge>
<ExpandableValue value={span.status_message} title="Status message">
<Badge
color="vanilla"
textEllipsis="end"
className={styles.statusMessageBadge}
>
{span.status_message}
</Badge>
</ExpandableValue>
) : null,
},
];

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,7 @@
import { ChangeEvent } from 'react';
import { Color } from '@signozhq/design-tokens';
import { Button, Input, Popover, Tooltip } from 'antd';
import { Input } from '@signozhq/ui/input';
import { Button, 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

@@ -0,0 +1,49 @@
.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

@@ -0,0 +1,78 @@
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

@@ -0,0 +1 @@
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[clusterNameAttrKey]
clusterName := labels[inframonitoringtypes.ClusterNameAttrKey]
record := inframonitoringtypes.ClusterRecord{ // initialize with default values
ClusterName: clusterName,
@@ -87,6 +87,9 @@ 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,14 +7,9 @@ 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: clusterNameAttrKey,
Name: inframonitoringtypes.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[daemonSetNameAttrKey]
daemonSetName := labels[inframonitoringtypes.DaemonSetNameAttrKey]
record := inframonitoringtypes.DaemonSetRecord{ // initialize with default values
DaemonSetName: daemonSetName,
@@ -95,6 +95,9 @@ 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,14 +7,11 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
daemonSetNameAttrKey = "k8s.daemonset.name"
daemonSetsBaseFilterExpr = "k8s.daemonset.name != ''"
)
const daemonSetsBaseFilterExpr = "k8s.daemonset.name != ''"
var daemonSetNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: daemonSetNameAttrKey,
Name: inframonitoringtypes.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[deploymentNameAttrKey]
deploymentName := labels[inframonitoringtypes.DeploymentNameAttrKey]
record := inframonitoringtypes.DeploymentRecord{ // initialize with default values
DeploymentName: deploymentName,
@@ -95,6 +95,9 @@ 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,14 +7,11 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
deploymentNameAttrKey = "k8s.deployment.name"
deploymentsBaseFilterExpr = "k8s.deployment.name != ''"
)
const deploymentsBaseFilterExpr = "k8s.deployment.name != ''"
var deploymentNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: deploymentNameAttrKey,
Name: inframonitoringtypes.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')", hostNameAttrKey)
hostNameExpr := fmt.Sprintf("JSONExtractString(labels, '%s')", inframonitoringtypes.HostNameAttrKey)
sb := sqlbuilder.NewSelectBuilder()
selectCols := make([]string, 0, len(req.GroupBy)+2)
@@ -48,7 +48,7 @@ func (m *module) getPerGroupHostStatusCounts(
)
}
activeHostsSQ := m.getActiveHostsQuery(metricNames, hostNameAttrKey, sinceUnixMilli)
activeHostsSQ := m.getActiveHostsQuery(metricNames, inframonitoringtypes.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[hostNameAttrKey]
hostName := labels[inframonitoringtypes.HostNameAttrKey]
activeStatus := inframonitoringtypes.HostStatusNone
activeHostCount := 0
@@ -216,6 +216,9 @@ 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]
@@ -281,7 +284,7 @@ func (m *module) applyHostsActiveStatusFilter(req *inframonitoringtypes.Postable
if req.Filter.FilterByStatus == inframonitoringtypes.HostStatusInactive {
op = "NOT IN"
}
statusClause := fmt.Sprintf("%s %s (%s)", hostNameAttrKey, op, strings.Join(activeHosts, ", "))
statusClause := fmt.Sprintf("%s %s (%s)", inframonitoringtypes.HostNameAttrKey, op, strings.Join(activeHosts, ", "))
req.Filter.Expression = mergeFilterExpressions(req.Filter.Expression, statusClause)
return false
}

View File

@@ -7,14 +7,10 @@ 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: hostNameAttrKey,
Name: inframonitoringtypes.HostNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -25,7 +25,7 @@ func buildJobRecords(
records := make([]inframonitoringtypes.JobRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
jobName := labels[jobNameAttrKey]
jobName := labels[inframonitoringtypes.JobNameAttrKey]
record := inframonitoringtypes.JobRecord{ // initialize with default values
JobName: jobName,
@@ -103,6 +103,9 @@ func (m *module) getTopJobGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.JobNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.JobNameAttrKey), nil
}
queryNamesForOrderBy := orderByToJobsQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -7,14 +7,11 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
jobNameAttrKey = "k8s.job.name"
jobsBaseFilterExpr = "k8s.job.name != ''"
)
const jobsBaseFilterExpr = "k8s.job.name != ''"
var jobNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: jobNameAttrKey,
Name: inframonitoringtypes.JobNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -100,7 +100,7 @@ func (m *module) ListHosts(ctx context.Context, orgID valuer.UUID, req *inframon
// Determine active hosts: those with metrics reported in the last 10 minutes.
// Compute the cutoff once so every downstream query/subquery agrees on what "active" means.
sinceUnixMilli := time.Now().Add(-10 * time.Minute).UTC().UnixMilli()
activeHostsMap, err := m.getActiveHosts(ctx, hostsTableMetricNamesList, hostNameAttrKey, sinceUnixMilli)
activeHostsMap, err := m.getActiveHosts(ctx, hostsTableMetricNamesList, inframonitoringtypes.HostNameAttrKey, sinceUnixMilli)
if err != nil {
return nil, err
}
@@ -146,7 +146,7 @@ func (m *module) ListHosts(ctx context.Context, orgID valuer.UUID, req *inframon
// When host.name is not in groupBy, we need to run an additional query to get the counts per group for the current page,
// using the same filter expression as the main query (including user filters + page groups IN clause).
hostCounts := make(map[string]groupHostStatusCounts)
isHostNameInGroupBy := isKeyInGroupByAttrs(req.GroupBy, hostNameAttrKey)
isHostNameInGroupBy := isKeyInGroupByAttrs(req.GroupBy, inframonitoringtypes.HostNameAttrKey)
if !isHostNameInGroupBy {
hostCounts, err = m.getPerGroupHostStatusCounts(ctx, req, hostsTableMetricNamesList, pageGroups, sinceUnixMilli)
if err != nil {
@@ -324,7 +324,7 @@ func (m *module) ListNodes(ctx context.Context, orgID valuer.UUID, req *inframon
return nil, err
}
isNodeNameInGroupBy := isKeyInGroupByAttrs(req.GroupBy, nodeNameAttrKey)
isNodeNameInGroupBy := isKeyInGroupByAttrs(req.GroupBy, inframonitoringtypes.NodeNameAttrKey)
resp.Records = buildNodeRecords(isNodeNameInGroupBy, queryResp, pageGroups, req.GroupBy, metadataMap, nodeConditionCounts, podPhaseCounts)
resp.Warning = queryResp.Warning

View File

@@ -24,7 +24,7 @@ func buildNamespaceRecords(
records := make([]inframonitoringtypes.NamespaceRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
namespaceName := labels[namespaceNameAttrKey]
namespaceName := labels[inframonitoringtypes.NamespaceNameAttrKey]
record := inframonitoringtypes.NamespaceRecord{ // initialize with default values
NamespaceName: namespaceName,
@@ -70,6 +70,9 @@ func (m *module) getTopNamespaceGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.NamespaceNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.NamespaceNameAttrKey), nil
}
queryNamesForOrderBy := orderByToNamespacesQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -7,13 +7,9 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
namespaceNameAttrKey = "k8s.namespace.name"
)
var namespaceNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: namespaceNameAttrKey,
Name: inframonitoringtypes.NamespaceNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -33,7 +33,7 @@ func buildNodeRecords(
records := make([]inframonitoringtypes.NodeRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
nodeName := labels[nodeNameAttrKey]
nodeName := labels[inframonitoringtypes.NodeNameAttrKey]
record := inframonitoringtypes.NodeRecord{ // initialize with default values
NodeName: nodeName,
@@ -105,6 +105,9 @@ func (m *module) getTopNodeGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.NodeNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.NodeNameAttrKey), nil
}
queryNamesForOrderBy := orderByToNodesQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]
@@ -201,7 +204,7 @@ func (m *module) getPerGroupNodeConditionCounts(
timeSeriesFPs := sqlbuilder.NewSelectBuilder()
timeSeriesFPsSelectCols := []string{
"fingerprint",
fmt.Sprintf("JSONExtractString(labels, %s) AS node_name", timeSeriesFPs.Var(nodeNameAttrKey)),
fmt.Sprintf("JSONExtractString(labels, %s) AS node_name", timeSeriesFPs.Var(inframonitoringtypes.NodeNameAttrKey)),
}
for _, key := range groupBy {
timeSeriesFPsSelectCols = append(timeSeriesFPsSelectCols,

View File

@@ -7,14 +7,11 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
nodeNameAttrKey = "k8s.node.name"
nodeConditionMetricName = "k8s.node.condition_ready"
)
const nodeConditionMetricName = "k8s.node.condition_ready"
var nodeNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: nodeNameAttrKey,
Name: inframonitoringtypes.NodeNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -124,6 +124,9 @@ func (m *module) getTopPodGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.PodNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.PodNameAttrKey), nil
}
queryNamesForOrderBy := orderByToPodsQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -25,7 +25,7 @@ func buildStatefulSetRecords(
records := make([]inframonitoringtypes.StatefulSetRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
statefulSetName := labels[statefulSetNameAttrKey]
statefulSetName := labels[inframonitoringtypes.StatefulSetNameAttrKey]
record := inframonitoringtypes.StatefulSetRecord{ // initialize with default values
StatefulSetName: statefulSetName,
@@ -95,6 +95,9 @@ func (m *module) getTopStatefulSetGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.StatefulSetNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.StatefulSetNameAttrKey), nil
}
queryNamesForOrderBy := orderByToStatefulSetsQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -7,14 +7,11 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
statefulSetNameAttrKey = "k8s.statefulset.name"
statefulSetsBaseFilterExpr = "k8s.statefulset.name != ''"
)
const statefulSetsBaseFilterExpr = "k8s.statefulset.name != ''"
var statefulSetNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: statefulSetNameAttrKey,
Name: inframonitoringtypes.StatefulSetNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -23,7 +23,7 @@ func buildVolumeRecords(
records := make([]inframonitoringtypes.VolumeRecord, 0, len(pageGroups))
for _, labels := range pageGroups {
compositeKey := compositeKeyFromLabels(labels, groupBy)
pvcName := labels[persistentVolumeClaimNameAttrKey]
pvcName := labels[inframonitoringtypes.PersistentVolumeClaimNameAttrKey]
record := inframonitoringtypes.VolumeRecord{ // initialize with default values
PersistentVolumeClaimName: pvcName,
@@ -75,6 +75,9 @@ func (m *module) getTopVolumeGroups(
metadataMap map[string]map[string]string,
) ([]map[string]string, error) {
orderByKey := req.OrderBy.Key.Name
if orderByKey == inframonitoringtypes.PersistentVolumeClaimNameAttrKey {
return inframonitoringtypes.PaginateMetadataByName(metadataMap, req.GroupBy, req.OrderBy.Direction, req.Offset, req.Limit, inframonitoringtypes.PersistentVolumeClaimNameAttrKey), nil
}
queryNamesForOrderBy := orderByToVolumesQueryNames[orderByKey]
rankingQueryName := queryNamesForOrderBy[len(queryNamesForOrderBy)-1]

View File

@@ -7,14 +7,11 @@ import (
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
)
const (
persistentVolumeClaimNameAttrKey = "k8s.persistentvolumeclaim.name"
volumesBaseFilterExpr = "k8s.persistentvolumeclaim.name != ''"
)
const volumesBaseFilterExpr = "k8s.persistentvolumeclaim.name != ''"
var pvcNameGroupByKey = qbtypes.GroupByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: persistentVolumeClaimNameAttrKey,
Name: inframonitoringtypes.PersistentVolumeClaimNameAttrKey,
FieldContext: telemetrytypes.FieldContextResource,
FieldDataType: telemetrytypes.FieldDataTypeString,
},

View File

@@ -19,8 +19,8 @@ type Clusters struct {
type ClusterRecord struct {
// TODO(nikhilmantri0902): once the underlying attr key is migrated to
// k8s.cluster.uid (see clusterNameAttrKey TODO in implinframonitoring),
// surface ClusterUID alongside (or replace) ClusterName.
// k8s.cluster.uid (see ClusterNameAttrKey), surface ClusterUID alongside
// (or replace) ClusterName.
ClusterName string `json:"clusterName" required:"true"`
ClusterCPU float64 `json:"clusterCPU" required:"true"`
ClusterCPUAllocatable float64 `json:"clusterCPUAllocatable" required:"true"`
@@ -88,6 +88,9 @@ func (req *PostableClusters) Validate() error {
if req.OrderBy.Direction != qbtypes.OrderDirectionAsc && req.OrderBy.Direction != qbtypes.OrderDirectionDesc {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid order by direction: %s", req.OrderBy.Direction)
}
if req.OrderBy.Key.Name == ClusterNameAttrKey && len(req.GroupBy) > 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "order by '%s' is only allowed when groupBy is empty", ClusterNameAttrKey)
}
}
return nil

View File

@@ -1,5 +1,7 @@
package inframonitoringtypes
const ClusterNameAttrKey = "k8s.cluster.name"
const (
ClustersOrderByCPU = "cpu"
ClustersOrderByCPUAllocatable = "cpu_allocatable"
@@ -12,4 +14,5 @@ var ClustersValidOrderByKeys = []string{
ClustersOrderByCPUAllocatable,
ClustersOrderByMemory,
ClustersOrderByMemoryAllocatable,
ClusterNameAttrKey,
}

View File

@@ -275,6 +275,57 @@ func TestPostableClusters_Validate(t *testing.T) {
},
wantErr: true,
},
{
name: "orderBy name asc with empty groupBy is valid",
req: &PostableClusters{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: ClusterNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: false,
},
{
name: "orderBy name desc with empty groupBy is valid",
req: &PostableClusters{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: ClusterNameAttrKey},
},
Direction: qbtypes.OrderDirectionDesc,
},
},
wantErr: false,
},
{
name: "orderBy name with non-empty groupBy is rejected",
req: &PostableClusters{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
GroupBy: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "k8s.cluster.name"}},
},
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: ClusterNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: true,
},
}
for _, tt := range tests {

View File

@@ -88,6 +88,9 @@ func (req *PostableDaemonSets) Validate() error {
if req.OrderBy.Direction != qbtypes.OrderDirectionAsc && req.OrderBy.Direction != qbtypes.OrderDirectionDesc {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid order by direction: %s", req.OrderBy.Direction)
}
if req.OrderBy.Key.Name == DaemonSetNameAttrKey && len(req.GroupBy) > 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "order by '%s' is only allowed when groupBy is empty", DaemonSetNameAttrKey)
}
}
return nil

View File

@@ -1,12 +1,14 @@
package inframonitoringtypes
const DaemonSetNameAttrKey = "k8s.daemonset.name"
const (
DaemonSetsOrderByCPU = "cpu"
DaemonSetsOrderByCPURequest = "cpu_request"
DaemonSetsOrderByCPULimit = "cpu_limit"
DaemonSetsOrderByMemory = "memory"
DaemonSetsOrderByMemoryRequest = "memory_request"
DaemonSetsOrderByMemoryLimit = "memory_limit"
DaemonSetsOrderByCPU = "cpu"
DaemonSetsOrderByCPURequest = "cpu_request"
DaemonSetsOrderByCPULimit = "cpu_limit"
DaemonSetsOrderByMemory = "memory"
DaemonSetsOrderByMemoryRequest = "memory_request"
DaemonSetsOrderByMemoryLimit = "memory_limit"
DaemonSetsOrderByDesiredNodes = "desired_nodes"
DaemonSetsOrderByCurrentNodes = "current_nodes"
)
@@ -20,4 +22,5 @@ var DaemonSetsValidOrderByKeys = []string{
DaemonSetsOrderByMemoryLimit,
DaemonSetsOrderByDesiredNodes,
DaemonSetsOrderByCurrentNodes,
DaemonSetNameAttrKey,
}

View File

@@ -257,6 +257,63 @@ func TestPostableDaemonSets_Validate(t *testing.T) {
},
wantErr: true,
},
{
name: "orderBy name asc with empty groupBy is valid",
req: &PostableDaemonSets{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: DaemonSetNameAttrKey,
},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: false,
},
{
name: "orderBy name desc with empty groupBy is valid",
req: &PostableDaemonSets{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: DaemonSetNameAttrKey,
},
},
Direction: qbtypes.OrderDirectionDesc,
},
},
wantErr: false,
},
{
name: "orderBy name with non-empty groupBy is rejected",
req: &PostableDaemonSets{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
GroupBy: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "k8s.namespace.name"}},
},
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{
Name: DaemonSetNameAttrKey,
},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: true,
},
}
for _, tt := range tests {

View File

@@ -88,6 +88,9 @@ func (req *PostableDeployments) Validate() error {
if req.OrderBy.Direction != qbtypes.OrderDirectionAsc && req.OrderBy.Direction != qbtypes.OrderDirectionDesc {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid order by direction: %s", req.OrderBy.Direction)
}
if req.OrderBy.Key.Name == DeploymentNameAttrKey && len(req.GroupBy) > 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "order by '%s' is only allowed when groupBy is empty", DeploymentNameAttrKey)
}
}
return nil

View File

@@ -1,5 +1,7 @@
package inframonitoringtypes
const DeploymentNameAttrKey = "k8s.deployment.name"
const (
DeploymentsOrderByCPU = "cpu"
DeploymentsOrderByCPURequest = "cpu_request"
@@ -20,4 +22,5 @@ var DeploymentsValidOrderByKeys = []string{
DeploymentsOrderByMemoryLimit,
DeploymentsOrderByDesiredPods,
DeploymentsOrderByAvailablePods,
DeploymentNameAttrKey,
}

View File

@@ -257,6 +257,57 @@ func TestPostableDeployments_Validate(t *testing.T) {
},
wantErr: true,
},
{
name: "orderBy name asc with empty groupBy is valid",
req: &PostableDeployments{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: DeploymentNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: false,
},
{
name: "orderBy name desc with empty groupBy is valid",
req: &PostableDeployments{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: DeploymentNameAttrKey},
},
Direction: qbtypes.OrderDirectionDesc,
},
},
wantErr: false,
},
{
name: "orderBy name with non-empty groupBy is rejected",
req: &PostableDeployments{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
GroupBy: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "k8s.namespace.name"}},
},
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: DeploymentNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: true,
},
}
for _, tt := range tests {

View File

@@ -100,6 +100,9 @@ func (req *PostableHosts) Validate() error {
if req.OrderBy.Direction != qbtypes.OrderDirectionAsc && req.OrderBy.Direction != qbtypes.OrderDirectionDesc {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid order by direction: %s", req.OrderBy.Direction)
}
if req.OrderBy.Key.Name == HostNameAttrKey && len(req.GroupBy) > 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "order by '%s' is only allowed when groupBy is empty", HostNameAttrKey)
}
}
return nil

View File

@@ -20,6 +20,8 @@ func (HostStatus) Enum() []any {
}
}
const HostNameAttrKey = "host.name"
const (
HostsOrderByCPU = "cpu"
HostsOrderByMemory = "memory"
@@ -34,4 +36,5 @@ var HostsValidOrderByKeys = []string{
HostsOrderByWait,
HostsOrderByDiskUsage,
HostsOrderByLoad15,
HostNameAttrKey,
}

View File

@@ -228,6 +228,57 @@ func TestHostsListRequest_Validate(t *testing.T) {
},
wantErr: true,
},
{
name: "orderBy name asc with empty groupBy is valid",
req: &PostableHosts{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: HostNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: false,
},
{
name: "orderBy name desc with empty groupBy is valid",
req: &PostableHosts{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: HostNameAttrKey},
},
Direction: qbtypes.OrderDirectionDesc,
},
},
wantErr: false,
},
{
name: "orderBy name with non-empty groupBy is rejected",
req: &PostableHosts{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
GroupBy: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "os.type"}},
},
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: HostNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: true,
},
}
for _, tt := range tests {

View File

@@ -90,6 +90,9 @@ func (req *PostableJobs) Validate() error {
if req.OrderBy.Direction != qbtypes.OrderDirectionAsc && req.OrderBy.Direction != qbtypes.OrderDirectionDesc {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid order by direction: %s", req.OrderBy.Direction)
}
if req.OrderBy.Key.Name == JobNameAttrKey && len(req.GroupBy) > 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "order by '%s' is only allowed when groupBy is empty", JobNameAttrKey)
}
}
return nil

View File

@@ -1,5 +1,7 @@
package inframonitoringtypes
const JobNameAttrKey = "k8s.job.name"
const (
JobsOrderByCPU = "cpu"
JobsOrderByCPURequest = "cpu_request"
@@ -24,4 +26,5 @@ var JobsValidOrderByKeys = []string{
JobsOrderByActivePods,
JobsOrderByFailedPods,
JobsOrderBySuccessfulPods,
JobNameAttrKey,
}

View File

@@ -293,6 +293,57 @@ func TestPostableJobs_Validate(t *testing.T) {
},
wantErr: true,
},
{
name: "orderBy name asc with empty groupBy is valid",
req: &PostableJobs{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: JobNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: false,
},
{
name: "orderBy name desc with empty groupBy is valid",
req: &PostableJobs{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: JobNameAttrKey},
},
Direction: qbtypes.OrderDirectionDesc,
},
},
wantErr: false,
},
{
name: "orderBy name with non-empty groupBy is rejected",
req: &PostableJobs{
Start: 1000,
End: 2000,
Limit: 100,
Offset: 0,
GroupBy: []qbtypes.GroupByKey{
{TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: "k8s.namespace.name"}},
},
OrderBy: &qbtypes.OrderBy{
Key: qbtypes.OrderByKey{
TelemetryFieldKey: telemetrytypes.TelemetryFieldKey{Name: JobNameAttrKey},
},
Direction: qbtypes.OrderDirectionAsc,
},
},
wantErr: true,
},
}
for _, tt := range tests {

View File

@@ -82,6 +82,9 @@ func (req *PostableNamespaces) Validate() error {
if req.OrderBy.Direction != qbtypes.OrderDirectionAsc && req.OrderBy.Direction != qbtypes.OrderDirectionDesc {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "invalid order by direction: %s", req.OrderBy.Direction)
}
if req.OrderBy.Key.Name == NamespaceNameAttrKey && len(req.GroupBy) > 0 {
return errors.NewInvalidInputf(errors.CodeInvalidInput, "order by '%s' is only allowed when groupBy is empty", NamespaceNameAttrKey)
}
}
return nil

View File

@@ -1,5 +1,7 @@
package inframonitoringtypes
const NamespaceNameAttrKey = "k8s.namespace.name"
const (
NamespacesOrderByCPU = "cpu"
NamespacesOrderByMemory = "memory"
@@ -8,4 +10,5 @@ const (
var NamespacesValidOrderByKeys = []string{
NamespacesOrderByCPU,
NamespacesOrderByMemory,
NamespaceNameAttrKey,
}

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