refactor: Control Monitor tab visibility via storage capabilities of the backend#3554
Conversation
There was a problem hiding this comment.
Pull request overview
This PR replaces three overlapping ATM/Monitor tab visibility mechanisms (monitor.menuEnabled, isATMActivated, and partial use of StorageCapabilities) with a single source of truth: storageCapabilities.metricsStorage, reported by the query service at startup.
Changes:
- Added
metricsStorage?: booleantoStorageCapabilitiesand removedMonitorEmptyStateConfig,menuEnabled, andemptyStatefromMonitorConfigand related types/defaults. - Removed the
isATMActivatedruntime 501-detection mechanism from the metrics reducer and all related component/test references. - Deleted the
Monitor/EmptyState/component directory (4 files) and updatedTopNavto gate the Monitor tab onstorageCapabilities.metricsStorage.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/types/config.ts |
Adds metricsStorage to StorageCapabilities; removes MonitorEmptyStateConfig and cleans up MonitorConfig |
src/types/metrics.ts |
Removes isATMActivated field from MetricsReduxState |
src/reducers/metrics.ts |
Removes isATMActivated from initial state and 501-detection logic |
src/reducers/metrics.mock.ts |
Removes isATMActivated from mock initial state |
src/reducers/metrics.test.js |
Removes isATMActivated from all expected state objects |
src/constants/default-config.ts |
Adds metricsStorage: false default; removes monitor.emptyState and menuEnabled |
index.html |
Adds metricsStorage: false to DEFAULT_STORAGE_CAPABILITIES |
src/components/App/TopNav.tsx |
Switches Monitor tab guard to storageCapabilities.metricsStorage |
src/components/App/TopNav.test.js |
Updates mock config key to match new guard |
src/components/Monitor/ServicesView/index.tsx |
Removes isATMActivated fetch guard and EmptyState render block |
src/components/Monitor/ServicesView/index.test.js |
Removes isATMActivated from all test props/state |
src/components/Monitor/index.test.js |
Removes isATMActivated from initial state and deletes EmptyState test |
src/components/Monitor/EmptyState/index.tsx |
Deleted entirely |
src/components/Monitor/EmptyState/index.test.js |
Deleted entirely |
src/components/Monitor/EmptyState/index.css |
Deleted entirely |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Hi @hharshhsaini, thanks for your contribution! To ensure quality reviews, we limit how many concurrent PRs new contributors can open:
This PR is currently on hold. We will automatically move this into the review queue once your existing PRs are merged or closed. Please see our Contributing Guidelines for details on our tiered quota policy. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3554 +/- ##
==========================================
+ Coverage 88.60% 89.15% +0.55%
==========================================
Files 299 304 +5
Lines 9484 9719 +235
Branches 2420 2562 +142
==========================================
+ Hits 8403 8665 +262
+ Misses 1078 1050 -28
- Partials 3 4 +1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Codecov reports -0.01% drop due to deletion of Monitor/EmptyState/ (dead code). All modified and coverable lines remain covered per Codecov's own report. The ServicesView/index.test.js |
6eeca16 to
54b33fb
Compare
|
@yurishkuro please add the appropriate changelog:refactoring label. This is a pure refactoring PR with no user-visible behavior changes. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
packages/jaeger-ui/src/components/Monitor/ServicesView/index.tsx
Outdated
Show resolved
Hide resolved
8a4b7c1 to
1328737
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
packages/jaeger-ui/src/components/Monitor/ServicesView/index.test.js:291
- Two
isATMActivatedreferences remain inindex.test.jsthat were not cleaned up in this refactor:
-
Line 239:
isATMActivated: trueis still present in thepropsNoServicesmetrics object inside the'fetches metrics only when services are available'test. This is now a stale property that no longer exists onMetricsReduxState. -
Lines 270–291: The test
'fetches metrics when isATMActivated is null (initial state)'and its associatedisATMActivated: nullat line 282 still exist. The PR description explicitly states this test should have been deleted ("Delete the 'fetches metrics when isATMActivated is null' test"), and the comment on line 282 ("Initial state before any metrics fetch") still references the removed concept. These leftover references should be removed.
isATMActivated: true,
},
fetchAllServiceMetrics: mockFetchAllServiceMetrics,
fetchAggregatedServiceMetrics: mockFetchAggregatedServiceMetrics,
};
useServices.mockReturnValue({ data: [], isLoading: false });
cleanup();
renderWithRouter(<MonitorATMServicesView {...propsNoServices} />);
// Should not fetch when no services
expect(mockFetchAllServiceMetrics).not.toHaveBeenCalled();
expect(mockFetchAggregatedServiceMetrics).not.toHaveBeenCalled();
cleanup();
const propsWithServices = {
...props,
metrics: {
...originInitialState,
serviceMetrics,
serviceOpsMetrics,
loading: false,
},
fetchAllServiceMetrics: mockFetchAllServiceMetrics,
fetchAggregatedServiceMetrics: mockFetchAggregatedServiceMetrics,
};
useServices.mockReturnValue({ data: ['apple'], isLoading: false });
renderWithRouter(<MonitorATMServicesView {...propsWithServices} />);
expect(mockFetchAllServiceMetrics).toHaveBeenCalled();
expect(mockFetchAggregatedServiceMetrics).toHaveBeenCalled();
});
it('fetches metrics when isATMActivated is null (initial state)', () => {
cleanup();
mockFetchAllServiceMetrics.mockClear();
mockFetchAggregatedServiceMetrics.mockClear();
const propsWithNullATM = {
...props,
metrics: {
...originInitialState,
serviceMetrics: null,
serviceOpsMetrics: undefined,
loading: false,
isATMActivated: null, // Initial state before any metrics fetch
},
fetchAllServiceMetrics: mockFetchAllServiceMetrics,
fetchAggregatedServiceMetrics: mockFetchAggregatedServiceMetrics,
};
useServices.mockReturnValue({ data: ['apple'], isLoading: false });
renderWithRouter(<MonitorATMServicesView {...propsWithNullATM} />);
expect(mockFetchAllServiceMetrics).toHaveBeenCalled();
expect(mockFetchAggregatedServiceMetrics).toHaveBeenCalled();
});
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
@yurishkuro @Parship12 Could you please take a look. This implements everything from issue #3540. two checks still need a maintainer:
|
1328737 to
b2bacbe
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 15 out of 16 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
jkowall
left a comment
There was a problem hiding this comment.
Thanks for the contribution
yurishkuro
left a comment
There was a problem hiding this comment.
PR removes existing configuration options
@yurishkuro the PR follows the implementation steps in this issue exactly -> Step 2 asks to remove Could you clarify what you'd like? Options:
Happy to go with whichever direction you prefer. |
|
PR quota unlocked! @hharshhsaini, this PR has been moved out of the waiting room and into the active review queue:
Thank you for your patience. |
how does this resolve the issue if step 1 (server side) is not implemented? |
@yurishkuro , This PR strictly covers the frontend React implementation (Steps 2-7 of the issue design) to remove the fragile Because |
|
no it doesn't make sense. If we land this PR the SPM functionality will become permanently disabled since the backend is not going to send the right capabilities. |
|
Please do not follow the roadmap from the issue verbatim. Aim for smaller changes. I think we can first switch the logic to use capability settings instead of config flag, and then clean up unused config flags later. |
Head branch was pushed to by a user without write access
b2bacbe to
68b0363
Compare
|
@yurishkuro, doing it all at once was far too heavy. I have completely reverted the MonitorEmptyState component deletions and the 501 isATMActivated Redux cleanup logic. I heavily stripped down this PR so it's strictly laser-focused on just swapping out the TopNav configuration read from monitor.menuEnabled over to storageCapabilities.metricsStorage as you requested! We can do the flag cleanups in a later PR... |
Signed-off-by: hharshhsaini <sainiharsh3311@gmail.com>
68b0363 to
88c5ed8
Compare
|
@yurishkuro @jkowall The code changes are ready and passing perfectly locally, but the Since I don't have the permissions to cancel/restart the worker on this repository from my fork, could you please either smash the "Re-run" button on the stuck job, or just squash and merge it manually since the code is approved? |
0127635
|
@yurishkuro @jkowall Thank you so much for the review and merge. As discussed, the capability injection is now live. For the follow-up cleanup PR, I plan to:
Would you like me to tackle all three of these dead-code cleanups in a single PR, or should I break them down further? Let me know |
This continues PR jaegertracing#3554 by selectively cleaning up the old menuEnabled and isATMActivated capabilities from the TypeScript definitions and Redux states. A follow up PR will strip the components from the DOM. Signed-off-by: hharshhsaini <sainiharsh3311@gmail.com>
…for SPM availability (#3587) ## Problem - Part of #3540 - Previous PR #3554 made the whole Monitor tab conditional on storage support, but we want to keep the Empty state as advertisement of the capabilities unless explicitly turned off in the config. The Service Performance Monitoring (SPM) Monitor page had several interconnected issues: 1. **Page crash on load** — `MonitorATMEmptyState` crashed with `TypeError: Cannot read properties of undefined (reading 'mainTitle')` because the embedded config provided a `monitor` key that completely overwrote `defaultConfig.monitor` (including `emptyState`), due to a shallow merge. 2. **Unnecessary API calls** — When metrics storage is not configured, the Monitor page fired API requests on load and only showed the empty state after receiving a `501 Not Implemented` response. The intent was always to use `storageCapabilities.metricsStorage` from config as the authoritative signal, not a runtime API probe. 3. **`storageCapabilities` in `jaeger-ui.config.json` was silently ignored** — The Vite dev-server plugin injected the JSON config into `getJaegerUiConfig()` but never into `getJaegerStorageCapabilities()`. Since `index.html` always defines `getJaegerStorageCapabilities` (hardcoded to return `metricsStorage: false`), the config file value was always overwritten. ## Changes ### `default-config.ts` — add `monitor` to `mergeFields` `mergeFields` controls which top-level config keys are shallow-merged (rather than wholesale replaced) when the embedded config is combined with defaults. `monitor` was missing, so a backend-provided `monitor: { menuEnabled: true }` silently dropped `emptyState`, causing the crash. ### `vite.config.mts` — inject `storageCapabilities` into `getJaegerStorageCapabilities()` The Go query-service injects `storageCapabilities` into `index.html` via a separate search-replace on `JAEGER_STORAGE_CAPABILITIES`. The Vite plugin was only replicating the `JAEGER_CONFIG` injection. It now also replaces `JAEGER_STORAGE_CAPABILITIES` when `storageCapabilities` is present in `jaeger-ui.config.json`, making local dev fully equivalent to production. ### `get-config.ts` — add comments clarifying the two-source design `storageCapabilities` is intentionally loaded from a separate source (`getJaegerStorageCapabilities`) and always overrides anything in the main UI config, keeping the backend authoritative. This was not documented; comments now explain the three-priority merge model. ### `Monitor/ServicesView/index.tsx` — gate on config, not runtime API response - Reads `storageCapabilities.metricsStorage` from config at render time. - Returns `<MonitorATMEmptyState />` immediately when it is `false`, with no API calls made. - Removed the `isATMActivated !== false` guard from `fetchMetrics` (it was checking a Redux flag that was only set after a 501 response). ### `reducers/metrics.ts` / `types/metrics.ts` — remove `isATMActivated` `isATMActivated` was a runtime approximation of `storageCapabilities.metricsStorage`: it started as `null`, then flipped to `false` upon a `501` response. Now that the config is the authoritative source (known at page load), this redundant state and the 501-detection logic have been removed entirely. ### Tests - `get-config.test.js` — new `storageCapabilities` describe block covering: backend injection, fallback to defaults, and precedence of `getJaegerStorageCapabilities` over the UI config. - `reducers/metrics.test.js` — removed `isATMActivated` assertions and the dedicated "501 Not Implemented" test case. - `Monitor/ServicesView/index.test.js` — updated `getConfigValue` mock to return `true` for `storageCapabilities.metricsStorage`; empty-state test now toggles the config mock instead of setting `isATMActivated: false`. - `Monitor/index.test.js` — added `getConfigValue` mock; updated empty-state test accordingly. ## How the config loading works (for reference) ``` jaeger-ui.config.json │ ▼ [dev] Vite plugin injects into index.html: • JAEGER_CONFIG → consumed by getJaegerUiConfig() • JAEGER_STORAGE_CAPABILITIES → consumed by getJaegerStorageCapabilities() ← was missing [prod] Go query-service does the same search-replace │ ▼ get-config.ts assembles the final Config from three sources (lowest → highest priority): 1. defaultConfig (compile-time defaults) 2. getJaegerUiConfig() (full UI config) 3. getJaegerStorageCapabilities() (always wins for storageCapabilities) ``` ## AI Usage in this PR (choose one) See [AI Usage Policy](https://github.com/jaegertracing/jaeger/blob/main/CONTRIBUTING_GUIDELINES.md#ai-usage-policy). - [ ] **None**: No AI tools were used in creating this PR - [ ] **Light**: AI provided minor assistance (formatting, simple suggestions) - [ ] **Moderate**: AI helped with code generation or debugging specific parts - [x] **Heavy**: AI generated most or all of the code changes --------- Signed-off-by: Yuri Shkuro <github@ysh.us> Signed-off-by: Yuri Shkuro <yurishkuro@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Which problem is this PR solving?
Part of #3540 - Control Monitor tab visibility via storage capabilities
Problem
Three overlapping mechanisms controlled Monitor/SPM tab visibility:
monitor.menuEnabled— static local config flag (defaulttrue, always on)isATMActivated— fragile runtime detection via HTTP 501 probingStorageCapabilities— correct server-reported mechanism, but only hadarchiveStorageChanges
Replace
isATMActivatedandmonitor.menuEnabledwith a single source of truth:storageCapabilities.metricsStorage, reported by the query service at startup.metricsStorage?: booleantoStorageCapabilities; removedmenuEnabled/emptyStatefromMonitorConfig; deletedMonitorEmptyStateConfig; removedisATMActivatedfromMetricsReduxStatemetricsStorage: falseto defaultstorageCapabilitiesandindex.html; removedmonitor.menuEnabled/emptyStatefrom default configisATMActivatedstate and HTTP 501 detection; 501 errors now stored inserviceErrorlike any other API errorTopNavreadsstorageCapabilities.metricsStorageinstead ofmonitor.menuEnabled;ServicesViewdropsisATMActivatedfetch guard andEmptyStaterenderMonitor/EmptyState/directory (4 files)isATMActivatedreferences; updated config mocks; deleted obsolete EmptyState tests