Compare commits

...

8 Commits

Author SHA1 Message Date
Gaurav Tewari
c5139eba32 fix: css fixes for llm o11y model pricing and overview 2026-07-17 13:52:50 +05:30
Gaurav Tewari
1a18bc8489 chore: move model pricing out of settings 2026-07-17 13:52:31 +05:30
Gaurav Tewari
c25060950f chore: rename draft 2026-07-17 13:52:31 +05:30
Gaurav Tewari
66604a3c75 chore: change name to ai 2026-07-17 13:52:31 +05:30
Gaurav Tewari
a00d274ecd chore: update constants 2026-07-17 13:52:31 +05:30
Gaurav Tewari
3dc26102c5 chore: review comments 2026-07-17 13:52:21 +05:30
Gaurav Tewari
283dea2be0 chore: rename route 2026-07-17 13:52:21 +05:30
Gaurav Tewari
805ef3771d feat: add llm o11y to side nav 2026-07-17 13:50:39 +05:30
128 changed files with 187 additions and 171 deletions

View File

@@ -62,7 +62,7 @@
"TRACES_FUNNELS_DETAIL": "SigNoz | Funnel",
"INTEGRATIONS_DETAIL": "SigNoz | Integration",
"PUBLIC_DASHBOARD": "SigNoz | Dashboard",
"LLM_OBSERVABILITY_OVERVIEW": "SigNoz | LLM Observability Overview",
"LLM_OBSERVABILITY_CONFIGURATION": "SigNoz | LLM Observability Configuration",
"LLM_OBSERVABILITY_ATTRIBUTE_MAPPING": "SigNoz | LLM Observability Attribute Mapping"
"AI_OBSERVABILITY_OVERVIEW": "SigNoz | AI Observability Overview",
"AI_OBSERVABILITY_CONFIGURATION": "SigNoz | AI Observability Configuration",
"AI_OBSERVABILITY_ATTRIBUTE_MAPPING": "SigNoz | AI Observability Attribute Mapping"
}

View File

@@ -87,7 +87,7 @@
"TRACES_FUNNELS_DETAIL": "SigNoz | Funnel",
"INTEGRATIONS_DETAIL": "SigNoz | Integration",
"PUBLIC_DASHBOARD": "SigNoz | Dashboard",
"LLM_OBSERVABILITY_OVERVIEW": "SigNoz | LLM Observability Overview",
"LLM_OBSERVABILITY_CONFIGURATION": "SigNoz | LLM Observability Configuration",
"LLM_OBSERVABILITY_ATTRIBUTE_MAPPING": "SigNoz | LLM Observability Attribute Mapping"
"AI_OBSERVABILITY_OVERVIEW": "SigNoz | AI Observability Overview",
"AI_OBSERVABILITY_CONFIGURATION": "SigNoz | AI Observability Configuration",
"AI_OBSERVABILITY_ATTRIBUTE_MAPPING": "SigNoz | AI Observability Attribute Mapping"
}

View File

@@ -134,8 +134,8 @@ function PrivateRoute({ children }: PrivateRouteProps): JSX.Element {
}
if (
(pathname.startsWith(`${ROUTES.LLM_OBSERVABILITY_BASE}/`) ||
pathname === ROUTES.LLM_OBSERVABILITY_BASE) &&
(pathname.startsWith(`${ROUTES.AI_OBSERVABILITY_BASE}/`) ||
pathname === ROUTES.AI_OBSERVABILITY_BASE) &&
!isAIObservabilityEnabled
) {
return <Redirect to={ROUTES.HOME} />;

View File

@@ -323,9 +323,9 @@ export const AIAssistantPage = Loadable(
),
);
export const LLMObservabilityPage = Loadable(
export const AIObservabilityPage = Loadable(
() =>
import(
/* webpackChunkName: "LLM Observability Page" */ 'pages/LLMObservability'
/* webpackChunkName: "AI Observability Page" */ 'pages/AIObservability'
),
);

View File

@@ -23,7 +23,7 @@ import {
IntegrationsDetailsPage,
LicensePage,
ListAllALertsPage,
LLMObservabilityPage,
AIObservabilityPage,
LiveLogs,
Login,
Logs,
@@ -514,24 +514,24 @@ const routes: AppRoutes[] = [
isPrivate: true,
},
{
path: ROUTES.LLM_OBSERVABILITY_ATTRIBUTE_MAPPING,
path: ROUTES.AI_OBSERVABILITY_ATTRIBUTE_MAPPING,
exact: true,
component: LLMObservabilityPage,
key: 'LLM_OBSERVABILITY_ATTRIBUTE_MAPPING',
component: AIObservabilityPage,
key: 'AI_OBSERVABILITY_ATTRIBUTE_MAPPING',
isPrivate: true,
},
{
path: ROUTES.LLM_OBSERVABILITY_OVERVIEW,
path: ROUTES.AI_OBSERVABILITY_OVERVIEW,
exact: true,
component: LLMObservabilityPage,
key: 'LLM_OBSERVABILITY_OVERVIEW',
component: AIObservabilityPage,
key: 'AI_OBSERVABILITY_OVERVIEW',
isPrivate: true,
},
{
path: ROUTES.LLM_OBSERVABILITY_CONFIGURATION,
path: ROUTES.AI_OBSERVABILITY_CONFIGURATION,
exact: true,
component: LLMObservabilityPage,
key: 'LLM_OBSERVABILITY_CONFIGURATION',
component: AIObservabilityPage,
key: 'AI_OBSERVABILITY_CONFIGURATION',
isPrivate: true,
},
];

View File

@@ -89,10 +89,10 @@ const ROUTES = {
AI_ASSISTANT_BASE: '/ai-assistant',
AI_ASSISTANT_ICON_PREVIEW: '/ai-assistant-icon-preview',
MCP_SERVER: '/settings/mcp-server',
LLM_OBSERVABILITY_ATTRIBUTE_MAPPING: '/llm-observability/attribute-mapping',
LLM_OBSERVABILITY_BASE: '/llm-observability',
LLM_OBSERVABILITY_OVERVIEW: '/llm-observability/overview',
LLM_OBSERVABILITY_CONFIGURATION: '/llm-observability/configuration',
AI_OBSERVABILITY_ATTRIBUTE_MAPPING: '/ai-observability/attribute-mapping',
AI_OBSERVABILITY_BASE: '/ai-observability',
AI_OBSERVABILITY_OVERVIEW: '/ai-observability/overview',
AI_OBSERVABILITY_CONFIGURATION: '/ai-observability/configuration',
} as const;
export default ROUTES;

View File

@@ -1,4 +1,4 @@
.llmObservability {
.aiObservability {
display: flex;
flex-direction: column;
height: 100%;

View File

@@ -0,0 +1,24 @@
import { Tabs } from '@signozhq/ui/tabs';
import { useAIObservabilityTabs } from './hooks/useAIObservabilityTabs';
import styles from './AIObservability.module.scss';
// Shell for the AI Observability page: renders the top-level tab bar
// (Overview / Configuration) using the SigNoz design-system Tabs, with
// route-driven active state from useAIObservabilityTabs.
function AIObservability(): JSX.Element {
const { items, activeTab, onTabChange } = useAIObservabilityTabs();
return (
<div className={styles.aiObservability} data-testid="ai-observability-page">
<Tabs
items={items}
value={activeTab}
onChange={onTabChange}
testId="ai-observability-tabs"
/>
</div>
);
}
export default AIObservability;

View File

@@ -1,4 +1,4 @@
.llmObservabilityAttributeMapping {
.aiObservabilityAttributeMapping {
display: flex;
flex-direction: column;
gap: var(--spacing-4);

View File

@@ -7,11 +7,11 @@ import AttributeMappingHeader from './components/AttributeMappingHeader/Attribut
import AttributeMappingsTab from './AttributeMappingsTab/AttributeMappingsTab';
import DiscardChangesDialog from './components/DiscardChangesDialog/DiscardChangesDialog';
import GroupFormDrawer from './components/GroupFormDrawer/GroupFormDrawer';
import styles from './LLMObservabilityAttributeMapping.module.scss';
import styles from './AIObservabilityAttributeMapping.module.scss';
import { useAttributeMappingEditor } from './hooks/useAttributeMappingEditor';
import { useGroupFormDrawer } from './components/GroupFormDrawer/hooks/useGroupFormDrawer';
function LLMObservabilityAttributeMapping(): JSX.Element {
function AIObservabilityAttributeMapping(): JSX.Element {
const editor = useAttributeMappingEditor();
const groupDrawer = useGroupFormDrawer();
@@ -52,8 +52,8 @@ function LLMObservabilityAttributeMapping(): JSX.Element {
return (
<div
className={styles.llmObservabilityAttributeMapping}
data-testid="llm-observability-attribute-mapping-page"
className={styles.aiObservabilityAttributeMapping}
data-testid="ai-observability-attribute-mapping-page"
>
<AttributeMappingHeader
isDirty={editor.isDirty}
@@ -93,4 +93,4 @@ function LLMObservabilityAttributeMapping(): JSX.Element {
);
}
export default LLMObservabilityAttributeMapping;
export default AIObservabilityAttributeMapping;

View File

@@ -23,8 +23,8 @@ import {
mappersEndpoint,
mockGroups,
mockMappers,
} from 'container/LLMObservability/AttributeMapping/__tests__/fixtures';
import { DraftGroup } from 'container/LLMObservability/AttributeMapping/types';
} from 'container/AIObservability/AttributeMapping/__tests__/fixtures';
import { DraftGroup } from 'container/AIObservability/AttributeMapping/types';
import AttributeMappingsTab from '../AttributeMappingsTab';
import { useAttributeMappingEditor } from '../../hooks/useAttributeMappingEditor';

View File

@@ -3,7 +3,7 @@ import { EllipsisVertical, Pencil, Trash2 } from '@signozhq/icons';
import { Button } from '@signozhq/ui/button';
import { DropdownMenuSimple, type MenuItem } from '@signozhq/ui/dropdown-menu';
import type { DraftGroup } from 'container/LLMObservability/AttributeMapping/types';
import type { DraftGroup } from 'container/AIObservability/AttributeMapping/types';
interface GroupActionsMenuProps {
group: DraftGroup;

View File

@@ -2,7 +2,7 @@ import { Info } from '@signozhq/icons';
import { TooltipSimple } from '@signozhq/ui/tooltip';
import { Typography } from '@signozhq/ui/typography';
import { DraftGroup } from 'container/LLMObservability/AttributeMapping/types';
import { DraftGroup } from 'container/AIObservability/AttributeMapping/types';
import ConditionsTooltip from './ConditionsTooltip';
import styles from './GroupHeader.module.scss';

View File

@@ -1,6 +1,6 @@
import { Switch } from '@signozhq/ui/switch';
import { DraftGroup } from 'container/LLMObservability/AttributeMapping/types';
import { DraftGroup } from 'container/AIObservability/AttributeMapping/types';
import GroupActionsMenu from '../GroupActionsMenu/GroupActionsMenu';
import styles from './GroupHeaderActions.module.scss';

View File

@@ -9,8 +9,8 @@ import {
DraftGroup,
DraftMapper,
Mapper,
} from 'container/LLMObservability/AttributeMapping/types';
import { AttributeMappingEditor } from 'container/LLMObservability/AttributeMapping/hooks/useAttributeMappingEditor';
} from 'container/AIObservability/AttributeMapping/types';
import { AttributeMappingEditor } from 'container/AIObservability/AttributeMapping/hooks/useAttributeMappingEditor';
import { COLUMN_COUNT } from '../constants';
import MapperRow from '../MapperRow/MapperRow';
import MapperRowSkeleton from '../MapperRow/MapperRowSkeleton';

View File

@@ -3,7 +3,7 @@ import { EllipsisVertical, Pencil, Trash2 } from '@signozhq/icons';
import { Button } from '@signozhq/ui/button';
import { DropdownMenuSimple, type MenuItem } from '@signozhq/ui/dropdown-menu';
import type { DraftMapper } from 'container/LLMObservability/AttributeMapping/types';
import type { DraftMapper } from 'container/AIObservability/AttributeMapping/types';
interface MapperActionsMenuProps {
mapper: DraftMapper;

View File

@@ -5,7 +5,7 @@ import { SpantypesFieldContextDTO } from 'api/generated/services/sigNoz.schemas'
import cx from 'classnames';
import { motion } from 'motion/react';
import { DraftMapper } from 'container/LLMObservability/AttributeMapping/types';
import { DraftMapper } from 'container/AIObservability/AttributeMapping/types';
import MapperActionsMenu from '../MapperActionsMenu/MapperActionsMenu';
import styles from './MapperRow.module.scss';

View File

@@ -4,13 +4,13 @@ import { Typography } from '@signozhq/ui/typography';
import { ChevronDown, ChevronRight, Layers, Plus } from '@signozhq/icons';
import { Collapse, type CollapseProps, Skeleton } from 'antd';
import MapperFormDrawer from 'container/LLMObservability/AttributeMapping/components/MapperFormDrawer/MapperFormDrawer';
import { useMapperFormDrawer } from 'container/LLMObservability/AttributeMapping/components/MapperFormDrawer/hooks/useMapperFormDrawer';
import MapperFormDrawer from 'container/AIObservability/AttributeMapping/components/MapperFormDrawer/MapperFormDrawer';
import { useMapperFormDrawer } from 'container/AIObservability/AttributeMapping/components/MapperFormDrawer/hooks/useMapperFormDrawer';
import {
DraftGroup,
DraftMapper,
} from 'container/LLMObservability/AttributeMapping/types';
import { AttributeMappingEditor } from 'container/LLMObservability/AttributeMapping/hooks/useAttributeMappingEditor';
} from 'container/AIObservability/AttributeMapping/types';
import { AttributeMappingEditor } from 'container/AIObservability/AttributeMapping/hooks/useAttributeMappingEditor';
import GroupHeader from './GroupHeader/GroupHeader';
import GroupHeaderActions from './GroupHeaderActions/GroupHeaderActions';
import GroupMappers from './GroupMappers/GroupMappers';

View File

@@ -1,7 +1,7 @@
import { rest, server } from 'mocks-server/server';
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import LLMObservabilityAttributeMapping from '../LLMObservabilityAttributeMapping';
import AIObservabilityAttributeMapping from '../AIObservabilityAttributeMapping';
import { GROUPS_ENDPOINT, makeGroupsResponse, mockGroups } from './fixtures';
function setupGroups(): void {
@@ -12,7 +12,7 @@ function setupGroups(): void {
);
}
describe('LLMObservabilityAttributeMapping', () => {
describe('AIObservabilityAttributeMapping', () => {
beforeEach(() => {
window.history.pushState(null, '', '/');
setupGroups();
@@ -23,15 +23,15 @@ describe('LLMObservabilityAttributeMapping', () => {
});
it('renders the page shell', () => {
render(<LLMObservabilityAttributeMapping />);
render(<AIObservabilityAttributeMapping />);
expect(
screen.getByTestId('llm-observability-attribute-mapping-page'),
screen.getByTestId('ai-observability-attribute-mapping-page'),
).toBeInTheDocument();
});
it('shows the attribute-mappings and test sub-tab labels', () => {
render(<LLMObservabilityAttributeMapping />);
render(<AIObservabilityAttributeMapping />);
expect(
screen.getByRole('tab', { name: 'Attribute Mappings' }),
@@ -40,7 +40,7 @@ describe('LLMObservabilityAttributeMapping', () => {
});
it('activates the attribute-mappings tab by default and renders its content', async () => {
render(<LLMObservabilityAttributeMapping />);
render(<AIObservabilityAttributeMapping />);
const attributeMappingsTab = screen.getByRole('tab', {
name: 'Attribute Mappings',
@@ -52,7 +52,7 @@ describe('LLMObservabilityAttributeMapping', () => {
});
it('renders the header with its description and no Save/Discard while pristine', () => {
render(<LLMObservabilityAttributeMapping />);
render(<AIObservabilityAttributeMapping />);
expect(
screen.getByText(
@@ -67,7 +67,7 @@ describe('LLMObservabilityAttributeMapping', () => {
it('prompts before discarding, then reverts staged changes on confirm', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<LLMObservabilityAttributeMapping />);
render(<AIObservabilityAttributeMapping />);
const toggle = await screen.findByTestId('group-enabled-group-1');
expect(toggle).toBeChecked();
@@ -88,7 +88,7 @@ describe('LLMObservabilityAttributeMapping', () => {
it('keeps staged changes when the discard prompt is dismissed', async () => {
const user = userEvent.setup({ pointerEventsCheck: 0 });
render(<LLMObservabilityAttributeMapping />);
render(<AIObservabilityAttributeMapping />);
const toggle = await screen.findByTestId('group-enabled-group-1');
await user.click(toggle);

View File

@@ -1,7 +1,7 @@
import { Button } from '@signozhq/ui/button';
import { Plus, X } from '@signozhq/icons';
import { FieldContextValue } from 'container/LLMObservability/AttributeMapping/types';
import { FieldContextValue } from 'container/AIObservability/AttributeMapping/types';
import KeySearchInput from '../../../KeySearchInput/KeySearchInput';
import styles from './ConditionKeyList.module.scss';

View File

@@ -12,7 +12,7 @@ import useDebounce from 'hooks/useDebounce';
import {
FieldContext,
FieldContextValue,
} from 'container/LLMObservability/AttributeMapping/types';
} from 'container/AIObservability/AttributeMapping/types';
import styles from './KeySearchInput.module.scss';
const SUGGESTION_LIMIT = 50;

View File

@@ -10,7 +10,7 @@ import {
MapperOperation,
MapperOperationValue,
SourceConfig,
} from 'container/LLMObservability/AttributeMapping/types';
} from 'container/AIObservability/AttributeMapping/types';
import KeySearchInput from '../../../KeySearchInput/KeySearchInput';
import styles from './SourceAttributeRow.module.scss';

View File

@@ -1,4 +1,4 @@
.llmObservabilityModelPricing {
.aiObservabilityModelPricing {
display: flex;
flex-direction: column;
gap: var(--spacing-8);

View File

@@ -4,11 +4,11 @@ import { useListUnmappedLLMModels } from 'api/generated/services/llmpricingrules
import { parseAsStringEnum, useQueryState } from 'nuqs';
import { MODEL_COSTS_TAB, TAB_KEY, UNPRICED_MODELS_TAB } from './constants';
import styles from './LLMObservabilityModelPricing.module.scss';
import styles from './AIObservabilityModelPricing.module.scss';
import ModelCostTabPanel from './ModelCostTabPanel';
import UnpricedModelsTab from './UnpricedModelsTab';
function LLMObservabilityModelPricing(): JSX.Element {
function AIObservabilityModelPricing(): JSX.Element {
const [activeTab, setActiveTab] = useQueryState(
TAB_KEY,
parseAsStringEnum([MODEL_COSTS_TAB, UNPRICED_MODELS_TAB]).withDefault(
@@ -22,8 +22,8 @@ function LLMObservabilityModelPricing(): JSX.Element {
return (
<div
className={styles.llmObservabilityModelPricing}
data-testid="llm-observability-model-pricing-page"
className={styles.aiObservabilityModelPricing}
data-testid="ai-observability-model-pricing-page"
>
<Tabs
value={activeTab}
@@ -60,4 +60,4 @@ function LLMObservabilityModelPricing(): JSX.Element {
);
}
export default LLMObservabilityModelPricing;
export default AIObservabilityModelPricing;

View File

@@ -2,13 +2,13 @@ import { LlmpricingruletypesLLMPricingRuleUnitDTO as UnitDTO } from 'api/generat
import {
TOAST_MODEL_COST_DELETED,
TOAST_MODEL_COST_UPDATED,
} from 'container/LLMObservability/Settings/ModelPricing/constants';
} from 'container/AIObservability/ModelPricing/constants';
import {
LLM_PRICING_ENDPOINT,
LLM_PRICING_RULE_ENDPOINT,
makeListResponse,
mockRules,
} from 'container/LLMObservability/Settings/ModelPricing/__tests__/fixtures';
} from 'container/AIObservability/ModelPricing/__tests__/fixtures';
import { rest, server } from 'mocks-server/server';
import { render, screen, userEvent, waitFor, within } from 'tests/test-utils';

View File

@@ -1,6 +1,6 @@
import { makePricingRule } from 'container/LLMObservability/Settings/ModelPricing/__tests__/fixtures';
import { EMPTY_DRAFT } from 'container/LLMObservability/Settings/ModelPricing/constants';
import { draftFromRule } from 'container/LLMObservability/Settings/ModelPricing/utils';
import { makePricingRule } from 'container/AIObservability/ModelPricing/__tests__/fixtures';
import { EMPTY_DRAFT } from 'container/AIObservability/ModelPricing/constants';
import { draftFromRule } from 'container/AIObservability/ModelPricing/utils';
import { render, screen, userEvent, waitFor } from 'tests/test-utils';
import ModelCostDrawer from '../ModelCostDrawer';

View File

@@ -30,7 +30,6 @@
padding: var(--spacing-5) var(--spacing-6);
border-radius: var(--radius-2);
border: 1px solid transparent;
background: var(--l3-background);
margin: 0;
width: 100%;
// Include padding + border in the 100% width so the card fits inside
@@ -67,16 +66,11 @@
// Radix RadioGroupItem renders <button data-state="checked|unchecked">.
// Use :has() to highlight the wrapper card when its inner button is checked.
&.sourceRadioAuto:has(button[data-state='checked']) {
&:has(button[data-state='checked']) {
background: color-mix(in srgb, var(--accent-primary) 10%, transparent);
border-color: color-mix(in srgb, var(--accent-primary) 30%, transparent);
}
&.sourceRadioOverride:has(button[data-state='checked']) {
background: color-mix(in srgb, var(--accent-amber) 10%, transparent);
border-color: color-mix(in srgb, var(--accent-amber) 30%, transparent);
}
&:hover {
background: var(--l3-background-hover);
}

View File

@@ -60,7 +60,7 @@ function SourceSelector({
>
<RadioGroupItem
value="auto"
containerClassName={cx(styles.sourceRadio, styles.sourceRadioAuto)}
containerClassName={styles.sourceRadio}
testId="drawer-source-auto"
disabled={disableAuto}
>
@@ -73,7 +73,7 @@ function SourceSelector({
</RadioGroupItem>
<RadioGroupItem
value="override"
containerClassName={cx(styles.sourceRadio, styles.sourceRadioOverride)}
containerClassName={styles.sourceRadio}
testId="drawer-source-override"
>
<div className={styles.sourceRadioTitle}>User override</div>

View File

@@ -11,16 +11,16 @@ import {
EMPTY_DRAFT,
TOAST_MODEL_COST_ADDED,
TOAST_MODEL_COST_UPDATED,
} from 'container/LLMObservability/Settings/ModelPricing/constants';
} from 'container/AIObservability/ModelPricing/constants';
import type {
DrawerDraft,
DrawerMode,
PricingRule,
} from 'container/LLMObservability/Settings/ModelPricing/types';
} from 'container/AIObservability/ModelPricing/types';
import {
buildRulePayload,
draftFromRule,
} from 'container/LLMObservability/Settings/ModelPricing/utils';
} from 'container/AIObservability/ModelPricing/utils';
interface UseModelCostDrawerResult {
isOpen: boolean;

View File

@@ -13,6 +13,7 @@
border: 1px solid color-mix(in srgb, var(--bg-amber-400) 30%, transparent);
background: color-mix(in srgb, var(--bg-amber-400) 8%, transparent);
color: var(--bg-amber-300, var(--bg-amber-400));
margin-top: var(--spacing-4);
}
.bannerIcon {

View File

@@ -5,7 +5,7 @@ import {
makeListResponse,
makeUnmappedResponse,
mockRules,
} from 'container/LLMObservability/Settings/ModelPricing/__tests__/fixtures';
} from 'container/AIObservability/ModelPricing/__tests__/fixtures';
import { rest, server } from 'mocks-server/server';
import { render, screen, userEvent, waitFor, within } from 'tests/test-utils';

View File

@@ -8,12 +8,12 @@ import styles from './MapConfirmDialog.module.scss';
import type {
PricingRule,
UnpricedModel,
} from 'container/LLMObservability/Settings/ModelPricing/types';
} from 'container/AIObservability/ModelPricing/types';
import {
formatPricePerMillion,
getCanonicalId,
getExtraBuckets,
} from 'container/LLMObservability/Settings/ModelPricing/utils';
} from 'container/AIObservability/ModelPricing/utils';
interface MapConfirmDialogProps {
open: boolean;

View File

@@ -15,10 +15,10 @@ import { Plus } from '@signozhq/icons';
import { Skeleton } from 'antd';
import styles from './MapToBillingModelSelect.module.scss';
import { RULE_OPTIONS_LIMIT } from 'container/LLMObservability/Settings/ModelPricing/constants';
import type { PricingRule } from 'container/LLMObservability/Settings/ModelPricing/types';
import { getRuleOptionLabel } from 'container/LLMObservability/Settings/ModelPricing/utils';
import { usePendingMappingLabel } from 'container/LLMObservability/Settings/ModelPricing/UnpricedModelsTab/usePendingMappingStore';
import { RULE_OPTIONS_LIMIT } from 'container/AIObservability/ModelPricing/constants';
import type { PricingRule } from 'container/AIObservability/ModelPricing/types';
import { getRuleOptionLabel } from 'container/AIObservability/ModelPricing/utils';
import { usePendingMappingLabel } from 'container/AIObservability/ModelPricing/UnpricedModelsTab/usePendingMappingStore';
import { useMapToBillingModelSearch } from './useMapToBillingModelSearch';
// One placeholder row per fetched option, so the skeleton height matches the

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