Compare commits

..

1 Commits

Author SHA1 Message Date
Ashwin Bhatkal
b653c69e29 fix(frontend): unblock pnpm generate:api after orval v8 upgrade (#11346)
Some checks are pending
build-staging / prepare (push) Waiting to run
build-staging / js-build (push) Blocked by required conditions
build-staging / go-build (push) Blocked by required conditions
build-staging / staging (push) Blocked by required conditions
Release Drafter / update_release_draft (push) Waiting to run
Orval v8's pre-generation validator (@scalar/openapi-parser) treats every
`$ref` key as a JSON Reference. Our spec embeds Perses' `common.JSONRef`
struct, which has a property literally named `$ref`, so validation aborts
with `INVALID_REFERENCE`. Set `input.unsafeDisableValidation: true` to
bypass — codegen itself handles the spec correctly, and the spec is
backend-generated and CI-gated.

Closes SigNoz/engineering-pod#4963
2026-05-18 14:33:23 +00:00
32 changed files with 61 additions and 172 deletions

View File

@@ -10,6 +10,13 @@ export default defineConfig({
signoz: {
input: {
target: '../docs/api/openapi.yml',
// Perses' `common.JSONRef` (used by `DashboardGridItem.content`) has a
// field tagged `json:"$ref"`, so our spec contains a property literally
// named `$ref`.
// Orval v8's validator (`@scalar/openapi-parser`) treats every `$ref` key
// as a JSON Reference and aborts with `INVALID_REFERENCE` when the value isn't a URI string.
// Safe to disable: yes, the spec is generated by `cmd/openapi.go` and gated by backend CI, not hand-edited.
unsafeDisableValidation: true,
},
output: {
target: './src/api/generated/services',

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
export interface AlertmanagertypesChannelDTO {
/**

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -3,7 +3,6 @@
* * The file has been auto-generated using Orval for SigNoz
* * regenerate with 'pnpm generate:api'
* SigNoz
* OpenAPI spec version: 0.0.1
*/
import { useMutation, useQuery } from 'react-query';
import type {

View File

@@ -101,45 +101,21 @@
white-space: nowrap;
}
// Fixed-width slot for the result-nav cluster. Always present (even when no
// expression is active) so the filter input width stays stable — no lateral
// layout shift when the count/arrows/clear pop in.
.resultNavSlot {
width: 220px;
flex-shrink: 0;
.preNextToggle {
display: flex;
justify-content: flex-end;
align-items: center;
flex-shrink: 0;
gap: 12px;
}
// Result-nav cluster: count + ↑↓ + clear (X), sits between the filter input
// and the right-side status/highlight controls. Visible whenever there's an
// active expression; count + ↑↓ collapse out when no results, clear stays.
.resultNav {
.preNextCount {
display: flex;
align-items: center;
flex-shrink: 0;
gap: 2px;
margin: auto;
color: var(--l2-foreground);
font-family: 'Geist Mono';
font-size: 12px;
}
.resultNavCount {
padding: 0 6px;
white-space: nowrap;
color: var(--l1-foreground);
font-family: 'Geist Mono';
font-size: 12px;
font-variant-numeric: tabular-nums;
}
.resultNavDivider {
width: 1px;
height: 14px;
background: var(--l3-border);
margin: 0 4px;
flex-shrink: 0;
font-weight: 400;
line-height: 18px;
}
.filterStatus {

View File

@@ -3,7 +3,6 @@ import { useHistory, useLocation } from 'react-router-dom';
import { useCopyToClipboard } from 'react-use';
import {
ChevronDown,
ChevronsRight,
ChevronUp,
Copy,
Info,
@@ -107,12 +106,6 @@ function Filters({
const [currentSearchedIndex, setCurrentSearchedIndex] = useState<number>(0);
const expressionRef = useRef<string>('');
const containerRef = useRef<HTMLDivElement>(null);
// Ref to the Clear (×) button so we can suppress the search-container
// onBlur → runQuery path when focus moves to it. Otherwise the editor
// loses focus before our click handler runs, runQuery commits the (still
// bad) expression, and React Query re-fires the failing request on the
// way to being cleared.
const clearBtnRef = useRef<HTMLButtonElement>(null);
const runQuery = useCallback(
(value: string): void => {
@@ -159,18 +152,6 @@ function Filters({
runQuery(expressionRef.current);
}, [runQuery]);
// Clear filter — reset expression + filters + results in one shot.
// Wired to the X button in the result-nav cluster.
const handleClear = useCallback((): void => {
setExpression('');
expressionRef.current = '';
setFilters({ items: [], op: 'AND' });
setFilteredSpanIds([]);
onFilteredSpansChange?.([], false);
setCurrentSearchedIndex(0);
setNoData(false);
}, [onFilteredSpansChange]);
// Expression-based filter hooks
const filterProps = {
expression,
@@ -285,71 +266,10 @@ function Filters({
</div>
);
const hasExpression = expression.trim().length > 0;
const hasResults = filteredSpanIds.length > 0;
// Result-nav cluster: count + ↑↓ + clear (X), all OUTSIDE the input.
// - The cluster appears whenever there's an active expression.
// - Count + ↑↓ are hidden when there are no results to navigate (no-data or
// API error); clear (X) stays so the user can always reset.
const resultNav = hasExpression ? (
<div className={styles.resultNav}>
{hasResults && (
<>
<Typography.Text className={styles.resultNavCount}>
{currentSearchedIndex + 1} / {filteredSpanIds.length}
</Typography.Text>
<Button
variant="ghost"
size="icon"
color="secondary"
disabled={currentSearchedIndex === 0}
onClick={(): void => {
handlePrevNext(currentSearchedIndex - 1);
setCurrentSearchedIndex((prev) => prev - 1);
}}
>
<ChevronUp size={14} />
</Button>
<Button
variant="ghost"
size="icon"
color="secondary"
disabled={currentSearchedIndex === filteredSpanIds.length - 1}
onClick={(): void => {
handlePrevNext(currentSearchedIndex + 1);
setCurrentSearchedIndex((prev) => prev + 1);
}}
>
<ChevronDown size={14} />
</Button>
<span className={styles.resultNavDivider} />
</>
)}
<TooltipRoot>
<TooltipTrigger asChild>
<Button
ref={clearBtnRef}
variant="ghost"
size="icon"
color="secondary"
onClick={handleClear}
>
<X size={14} />
</Button>
</TooltipTrigger>
<TooltipContent>Clear filter</TooltipContent>
</TooltipRoot>
</div>
) : null;
// Status indicator (right side): "No results found" (muted) or "API error"
// (red ring + tooltip). Shown only when there's an active expression and
// either no matches came back or the API itself failed.
let statusIndicator: JSX.Element | null = null;
if (hasExpression && !isFetching) {
if (error) {
statusIndicator = (
const statusIndicators = (
<>
{isFetching && <Loader className="animate-spin" />}
{error && (
<TooltipRoot>
<TooltipTrigger asChild>
<span className={cx(styles.filterStatus, styles.hasError)}>
@@ -361,19 +281,14 @@ function Filters({
{(error as AxiosError)?.message || 'Something went wrong'}
</TooltipContent>
</TooltipRoot>
);
} else if (noData) {
statusIndicator = (
)}
{!error && noData && (
<Typography.Text className={styles.filterStatus}>
No results found
</Typography.Text>
);
}
}
const fetchingIndicator = isFetching ? (
<Loader className="animate-spin" />
) : null;
)}
</>
);
// --- COLLAPSED VIEW ---
if (!isExpanded) {
@@ -419,8 +334,7 @@ function Filters({
pill
)}
{highlightErrorsToggle}
{statusIndicator}
{fetchingIndicator}
{statusIndicators}
</div>
</TooltipProvider>
);
@@ -451,10 +365,7 @@ function Filters({
className={styles.searchContainer}
ref={containerRef}
onBlur={(e): void => {
const relatedTarget = e.relatedTarget as Node | null;
const blurredIntoSelf = !!containerRef.current?.contains(relatedTarget);
const blurredIntoClear = !!clearBtnRef.current?.contains(relatedTarget);
if (!blurredIntoSelf && !blurredIntoClear) {
if (!containerRef.current?.contains(e.relatedTarget as Node)) {
handleBlur();
}
}}
@@ -471,24 +382,48 @@ function Filters({
placeholder="Enter your filter query (e.g., http.status_code >= 500 AND service.name = 'frontend')"
/>
</div>
<div className={styles.resultNavSlot}>{resultNav}</div>
{highlightErrorsToggle}
{statusIndicator}
{fetchingIndicator}
<TooltipRoot>
<TooltipTrigger asChild>
{filteredSpanIds.length > 0 && (
<div className={styles.preNextToggle}>
<Typography.Text className={styles.preNextCount}>
{currentSearchedIndex + 1} / {filteredSpanIds.length}
</Typography.Text>
<Button
variant="ghost"
size="icon"
color="secondary"
className={styles.collapseBtn}
onClick={onCollapse}
disabled={currentSearchedIndex === 0}
onClick={(): void => {
handlePrevNext(currentSearchedIndex - 1);
setCurrentSearchedIndex((prev) => prev - 1);
}}
>
<ChevronsRight size={14} />
<ChevronUp size={14} />
</Button>
</TooltipTrigger>
<TooltipContent>Collapse filters</TooltipContent>
</TooltipRoot>
<Button
variant="ghost"
size="icon"
color="secondary"
disabled={currentSearchedIndex === filteredSpanIds.length - 1}
onClick={(): void => {
handlePrevNext(currentSearchedIndex + 1);
setCurrentSearchedIndex((prev) => prev + 1);
}}
>
<ChevronDown size={14} />
</Button>
</div>
)}
<Button
variant="ghost"
size="icon"
color="secondary"
className={styles.collapseBtn}
onClick={onCollapse}
>
<X size={14} />
</Button>
{highlightErrorsToggle}
{statusIndicators}
</div>
</TooltipProvider>
);