Skip to content
Open

Lily #27

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion cbmonitor/src/components/App/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React from 'react';
import { AppRootProps } from '@grafana/data';
import { config } from '@grafana/runtime';
import { CB_DATASOURCE_REF } from '../../constants';
import { CB_DATASOURCE_REF, ROUTES } from '../../constants';
import { SceneApp, useSceneApp } from '@grafana/scenes';
import { Alert } from '@grafana/ui';
import { PluginPropsContext } from 'utils/utils.plugin';
import { snapshotPage } from 'components/SnapshotDisplay/snapshotInstance';
import Showfast from '../../pages/Showfast';

// Defines the app and its pages
function getCBMonitorApp(){
Expand Down Expand Up @@ -42,7 +43,24 @@ function CBMonitorHome() {
);
}

// Showfast component wrapper that doesn't check for couchbase datasource
function ShowfastHome() {
return <Showfast />;
}

function App(props: AppRootProps) {
const { path } = props;

// Route based on the path
if (path?.includes(ROUTES.Showfast)) {
return (
<PluginPropsContext.Provider value={props}>
<ShowfastHome />
</PluginPropsContext.Provider>
);
}

// Default to CBMonitor
return (
<PluginPropsContext.Provider value={props}>
<CBMonitorHome />
Expand Down
6 changes: 6 additions & 0 deletions cbmonitor/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ export const CB_DATASOURCE_REF = {
type: 'couchbase-datasource'
} as const;

// Showfast Datasource Reference
export const SHOWFAST_DATASOURCE_REF = {
uid: 'Showfast',
type: 'yesoreyeram-infinity-datasource'
} as const;

export type DashboardId = keyof typeof DASHBOARD_UIDS;

// Helper function to get UID from dashboard name
Expand Down
85 changes: 85 additions & 0 deletions cbmonitor/src/dashboards/Showfast/kv/kv_90th_throughput.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import {
EmbeddedScene,
SceneFlexLayout,
SceneFlexItem,
SceneVariableSet,
} from '@grafana/scenes';
import { PanelBuilders } from '@grafana/scenes';
import { ShowfastQueryBuilder, createShowfastQueries } from '../../../utils/utils.showfast';

/**
* Creates a dynamic KV throughput dashboard using the ShowfastQueryBuilder
* This dashboard shows performance metrics from external APIs via Showfast
*/
export function kvThroughputDashboard(): EmbeddedScene {
// Create template variables for dynamic metric selection
const variables = ShowfastQueryBuilder.buildVariableSet(['kv']);

return new EmbeddedScene({
$variables: variables,
body: new SceneFlexLayout({
minHeight: 50,
direction: 'row',
wrap: 'wrap',
children: [
// KV Max Ops Performance Panel
new SceneFlexItem({
height: 400,
width: '50%',
minWidth: '45%',
body: PanelBuilders.barchart()
.setTitle('KV Max Ops Performance')
.build(),
$data: new ShowfastQueryBuilder('kv', 'max_ops')
.setVisualizationType('barchart')
.useTimelineData(true)
.buildQueryRunner()
}),

// KV Max Ops SSL Performance Panel
new SceneFlexItem({
height: 400,
width: '50%',
minWidth: '45%',
body: PanelBuilders.timeseries()
.setTitle('KV Max Ops SSL')
.setUnit('ops')
.build(),
$data: new ShowfastQueryBuilder('kv', 'max_ops_ssl')
.setVisualizationType('timeseries')
.useTimelineData(true)
.buildQueryRunner()
}),

// KV 95th Percentile Latency Panel
new SceneFlexItem({
height: 400,
width: '50%',
minWidth: '45%',
body: PanelBuilders.timeseries()
.setTitle('KV 95th Percentile Latency')
.setUnit('ms')
.build(),
$data: new ShowfastQueryBuilder('kv', 'latency_95th')
.setVisualizationType('timeseries')
.useTimelineData(true)
.buildQueryRunner()
}),

// KV Metrics Table Panel
new SceneFlexItem({
height: 400,
width: '50%',
minWidth: '45%',
body: PanelBuilders.table()
.setTitle('Available KV Metrics')
.build(),
$data: new ShowfastQueryBuilder('kv', 'max_ops')
.setVisualizationType('table')
.useTimelineData(false) // Use metrics endpoint for table
.buildQueryRunner()
})
]
})
});
}
13 changes: 12 additions & 1 deletion cbmonitor/src/pages/Showfast.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ function Showfast() {
const { metrics, loading, error, refetch } = useMetrics(activeTab);

const renderTabContent = (componentId: ComponentId) => {

return (
<div className={s.tabContent}>
{/* Real metrics display */}
Expand All @@ -51,6 +50,13 @@ function Showfast() {
return (
<PluginPage>
<div data-testid={testIds.showfast.container} className={s.dashboard}>
<div className={s.header}>
<h1 className={s.title}>Welcome to the Showfast dashboard.</h1>
<p className={s.description}>
Explore comprehensive performance metrics across different Couchbase components and services.
</p>
</div>

<div className={s.tabsContainer}>
<TabsBar className={s.tabsBar}>
{COMPONENTS.map((component) => (
Expand Down Expand Up @@ -114,6 +120,11 @@ const getStyles = (theme: GrafanaTheme2) => ({
tabContent: css`
padding: 16px 0;
`,
sceneContainer: css`
width: 100%;
min-height: 600px;
background-color: ${theme.colors.background.primary};
`,
Comment on lines +123 to +127
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CSS class 'sceneContainer' is defined but not used anywhere in the component. Remove this unused style definition or apply it to the appropriate element.

Suggested change
sceneContainer: css`
width: 100%;
min-height: 600px;
background-color: ${theme.colors.background.primary};
`,

Copilot uses AI. Check for mistakes.
contentHeader: css`
margin-bottom: 24px;

Expand Down
18 changes: 13 additions & 5 deletions cbmonitor/src/services/metricsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@ class MetricsService {
try {
// Build query parameters
const params = new URLSearchParams();
if (category) params.append('category', category);
if (subCategory) params.append('subCategory', subCategory);
if (category) {
params.append('category', category);
}
if (subCategory) {
params.append('subCategory', subCategory);
}

const queryString = params.toString();
const url = `${API_BASE_URL}/metrics/${componentId}${queryString ? `?${queryString}` : ''}`;
Expand Down Expand Up @@ -63,7 +67,7 @@ class MetricsService {
/**
* Fetch specific metric with historical data
*/
async getMetricHistory(componentId: string, metricId: string, limit: number = 50): Promise<Metric> {
async getMetricHistory(componentId: string, metricId: string, limit = 50): Promise<Metric> {
try {
console.log(`Fetching metric history for ${componentId}/${metricId}`);

Expand Down Expand Up @@ -113,10 +117,14 @@ class MetricsService {
buildNumber: `${version}-${Math.floor(Math.random() * 9999)}`
}));

// const description = metricName === 'draft-1'
// ? 'Key-Value throughput performance metric showing operations per second across versions'
// : `${this.formatMetricName(metricName)} performance metric`;

return {
id: metricName,
name: this.formatMetricName(metricName),
description: `${this.formatMetricName(metricName)} performance metric`,
description: '',
Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting description to an empty string removes useful information from the metric. The commented code above suggests this was a deliberate change, but empty descriptions reduce the usability of the metrics display. Consider keeping the formatted description or providing a meaningful default.

Copilot uses AI. Check for mistakes.
unit: this.getMetricUnit(metricName),
category: this.getMetricCategory(metricName),
values: values.sort((a, b) => a.version.localeCompare(b.version))
Expand Down Expand Up @@ -159,7 +167,7 @@ class MetricsService {
return nameMap[componentId] || componentId;
}

private getMetricUnit(metricId: string): string {
private getMetricUnit(metricId: string): string {
if (metricId.includes('latency') || metricId.includes('time') || metricId.includes('duration')) {
return 'ms';
}
Expand Down
1 change: 1 addition & 0 deletions cbmonitor/src/types/metrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export interface MetricsApiResponse {
export const METRIC_DEFINITIONS: Record<string, string[]> = {
kv: [
'kv_99p_throughput',
'kv_90th_throughput',
'kv_95p_latency',
'kv_set_latency',
'kv_get_latency',
Expand Down
5 changes: 4 additions & 1 deletion cbmonitor/src/utils/utils.panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export function getNewTimeSeriesDataTransformer(queryRunner: SceneQueryRunner) {
/**
* Create a new metric panel using the CBQueryBuilder and TimeSeriesDataTransformer
*/
// TO DO: add a way to assign a unit to each panel
export function createMetricPanel(
snapshotId: string,
metricName: string,
Expand Down Expand Up @@ -70,3 +69,7 @@ export function createMetricPanel(
$data: getNewTimeSeriesDataTransformer(builder.buildQueryRunner()),
});
}

export function createShowfastTab(){

Copy link

Copilot AI Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty function without implementation or documentation. Either implement the function body or remove it if it's not yet needed. If this is a placeholder for future work, add a TODO comment explaining the planned functionality.

Suggested change
// TODO: Implement the Showfast tab creation logic.

Copilot uses AI. Check for mistakes.
}