Skip to content

Show the Benchmark Report link in FinOps Benchmark Banner when benchmark has succeeded#2043

Merged
cezudas merged 8 commits intomainfrom
cezudas/OPS-3667-banner
Mar 3, 2026
Merged

Show the Benchmark Report link in FinOps Benchmark Banner when benchmark has succeeded#2043
cezudas merged 8 commits intomainfrom
cezudas/OPS-3667-banner

Conversation

@cezudas
Copy link
Contributor

@cezudas cezudas commented Mar 3, 2026

Fixes OPS-3667.

Screenshots:

  1. Benchmark in status "SUCCEEDED"
Screenshot 2026-03-03 at 07 46 45
  1. No benchmark
Screenshot 2026-03-03 at 07 49 09
  1. Benchmark in status "FAILED"
Screenshot 2026-03-03 at 07 47 47
  1. Benchmark in status "CREATED"
Screenshot 2026-03-03 at 07 47 18

@linear
Copy link

linear bot commented Mar 3, 2026

@cezudas cezudas marked this pull request as ready for review March 3, 2026 06:00
Copilot AI review requested due to automatic review settings March 3, 2026 06:00
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Home FinOps Benchmark banner behavior so that when a benchmark run has SUCCEEDED, the UI can switch the banner into a “report-ready” variation and provide a navigation path to the benchmark report.

Changes:

  • Added a shared BenchmarkProvider type derived from BenchmarkProviders.
  • Introduced useBenchmarkBannerState (plus tests) to fetch benchmarks and compute banner variation + provider.
  • Updated Home onboarding/operational views to pass variation, provider, and a “view report” click handler into FinOpsBenchmarkBanner.
  • Added listBenchmarks() to the React UI benchmark API client.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
packages/shared/src/lib/benchmark/benchmark-providers.ts Adds BenchmarkProvider type derived from enum values.
packages/react-ui/src/app/features/home/components/useBenchmarkBannerState.ts New hook that queries benchmarks and selects banner variation/provider.
packages/react-ui/src/app/features/home/components/useBenchmarkBannerState.test.ts Unit tests for the new banner-state hook logic.
packages/react-ui/src/app/features/home/components/home-operational-view.tsx Wires the new hook into the operational home view and passes banner props + report navigation handler.
packages/react-ui/src/app/features/home/components/home-onboarding-view.tsx Wires the new hook into the onboarding home view and passes banner props + report navigation handler.
packages/react-ui/src/app/features/benchmark/benchmark-api.ts Adds listBenchmarks() endpoint client method.
Comments suppressed due to low confidence (5)

packages/react-ui/src/app/features/benchmark/benchmark-api.ts:48

  • listBenchmarks takes provider?: string, but the backend querystring is validated against BenchmarkProviders and the rest of the feature treats provider as an enum-like value. Using string here makes it easy to pass invalid providers at compile time.

Suggestion: type this parameter as BenchmarkProvider/BenchmarkProviders (from @openops/shared) and keep the function signature consistent with the server contract.

const listBenchmarks = (provider?: string): Promise<ListBenchmarksResponse> =>
  api.get<ListBenchmarksResponse>(
    '/v1/benchmarks',
    provider ? { provider } : undefined,
  );

packages/react-ui/src/app/features/home/components/home-operational-view.tsx:55

  • The dashboard query string is built via string interpolation. Since benchmarkProvider ultimately comes from API data, it’s safer and more robust to URL-encode the value (or use createSearchParams) to avoid malformed URLs if the provider ever contains unexpected characters.

Suggestion: build the URL as /analytics?dashboard=${encodeURIComponent(${benchmarkProvider}_benchmark)} (or equivalent with createSearchParams).

  const onViewBenchmarkReportClick = () =>
    navigate(`/analytics?dashboard=${benchmarkProvider}_benchmark`);

packages/react-ui/src/app/features/home/components/home-onboarding-view.tsx:109

  • The dashboard query string is built via string interpolation. Since benchmarkProvider ultimately comes from API data, it’s safer and more robust to URL-encode the value (or use createSearchParams) to avoid malformed URLs if the provider ever contains unexpected characters.

Suggestion: build the URL as /analytics?dashboard=${encodeURIComponent(${benchmarkProvider}_benchmark)} (or equivalent with createSearchParams).

  const onViewBenchmarkReportClick = () =>
    navigate(`/analytics?dashboard=${benchmarkProvider}_benchmark`);

packages/react-ui/src/app/features/home/components/useBenchmarkBannerState.test.ts:140

  • This test uses provider: 'azure', but BenchmarkProviders (and the server routes that validate providers) currently only support 'aws'. That makes the scenario unreachable in production today and can be confusing if the test suite implies Azure benchmarks are supported.

Either update the test to only use supported providers, or (if Azure is intended) expand BenchmarkProviders/server-side support and dashboard registry so the behavior is actually possible end-to-end.

  it('returns report variation when there are multiple benchmarks and one has SUCCEEDED', () => {
    mockUseShowBenchmarkBanner.mockReturnValue(true);
    setupQueryMock([
      { benchmarkId: 'bm-1', provider: 'aws', status: BenchmarkStatus.RUNNING },
      {
        benchmarkId: 'bm-2',
        provider: 'azure',
        status: BenchmarkStatus.SUCCEEDED,
      },
    ]);

    const { result } = renderHook(() => useBenchmarkBannerState());

    expect(result.current.variation).toBe('report');
    expect(result.current.provider).toBe('azure');
  });

packages/react-ui/src/app/features/home/components/useBenchmarkBannerState.ts:29

  • provider is derived from a string coming from ListBenchmarksResponse and then forced into BenchmarkProvider via a cast, with a hard-coded 'aws' fallback. This can mask unexpected provider values (e.g., would build links like /analytics?dashboard=undefined_benchmark / render an undefined label) and makes it easy for the UI and shared types to drift.

Consider (a) avoiding the cast by aligning the response type to BenchmarkProviders/BenchmarkProvider (e.g., schema uses Type.Enum(BenchmarkProviders)), and/or (b) validating succeededBenchmark.provider against the supported providers and falling back to BenchmarkProviders.AWS when unknown (instead of 'aws').

  return {
    isEnabled,
    variation: succeededBenchmark ? 'report' : 'default',
    provider: (succeededBenchmark?.provider ?? 'aws') as BenchmarkProvider,
  };

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@cezudas cezudas force-pushed the cezudas/OPS-3667-banner branch from 923fed7 to 72986cb Compare March 3, 2026 06:33
updated: string;
projectId: string;
provider: string;
provider: BenchmarkProviders;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is a TypeScript-only change — it doesn't touch the TypeORM column definition (line 43–44 still has type: String). TypeORM reads the column as a plain string from the DB; no migration is triggered, no DB constraint is added.

@cezudas cezudas requested a review from MarceloRGonc March 3, 2026 07:42
@cezudas cezudas requested a review from MarceloRGonc March 3, 2026 08:54
@sonarqubecloud
Copy link

sonarqubecloud bot commented Mar 3, 2026

@cezudas cezudas merged commit 437d1c8 into main Mar 3, 2026
21 checks passed
@cezudas cezudas deleted the cezudas/OPS-3667-banner branch March 3, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants