From b792c31eddfaa94d5956f6afe541449c980e2cb4 Mon Sep 17 00:00:00 2001 From: Stephanie Hingtgen Date: Tue, 25 Mar 2025 07:53:13 -0600 Subject: [PATCH] Dashboard versions: disable show more when last page (#102655) --------- Co-authored-by: Dominik Prokop --- .../settings/VersionsEditView.test.tsx | 87 +++++++++++++++++++ .../settings/VersionsEditView.tsx | 10 ++- .../VersionsSettings.test.tsx | 58 ++++++++++--- .../DashboardSettings/VersionsSettings.tsx | 9 +- 4 files changed, 148 insertions(+), 16 deletions(-) diff --git a/public/app/features/dashboard-scene/settings/VersionsEditView.test.tsx b/public/app/features/dashboard-scene/settings/VersionsEditView.test.tsx index e6449d0d3f6..dc0c3619940 100644 --- a/public/app/features/dashboard-scene/settings/VersionsEditView.test.tsx +++ b/public/app/features/dashboard-scene/settings/VersionsEditView.test.tsx @@ -1,4 +1,5 @@ import { SceneTimeRange } from '@grafana/scenes'; +import { config } from '@grafana/runtime'; import { DashboardScene } from '../scene/DashboardScene'; import { activateFullSceneTree } from '../utils/test-utils'; @@ -108,6 +109,92 @@ describe('VersionsEditView', () => { expect(versionsView.state.isNewLatest).toBe(true); }); + + it('should correctly identify last page when partial page is returned without version 1', async () => { + jest.mocked(historySrv.getHistoryList).mockResolvedValueOnce({ + continueToken: '', + versions: [ + { + id: 4, + dashboardId: 1, + dashboardUID: '_U4zObQMz', + parentVersion: 3, + restoredFrom: 0, + version: 4, + created: '2017-02-22T17:43:01-08:00', + createdBy: 'admin', + message: '', + checked: false, + }, + { + id: 3, + dashboardId: 1, + dashboardUID: '_U4zObQMz', + parentVersion: 1, + restoredFrom: 1, + version: 3, + created: '2017-02-22T17:43:01-08:00', + createdBy: 'admin', + message: '', + checked: false, + }, + ], + }); + + versionsView.reset(); + versionsView.fetchVersions(); + await new Promise(process.nextTick); + + expect(versionsView.versions.length).toBeLessThan(VERSIONS_FETCH_LIMIT); + expect(versionsView.versions.find((rev) => rev.version === 1)).toBeUndefined(); + }); + + it('should correctly identify last page when kubernetesClientDashboardsFolders is enabled and continueToken is empty', async () => { + // @ts-ignore + config.featureToggles.kubernetesClientDashboardsFolders = true; + + jest.mocked(historySrv.getHistoryList).mockResolvedValueOnce({ + continueToken: '', + versions: [ + { + id: 4, + dashboardId: 1, + dashboardUID: '_U4zObQMz', + parentVersion: 3, + restoredFrom: 0, + version: 4, + created: '2017-02-22T17:43:01-08:00', + createdBy: 'admin', + message: '', + checked: false, + }, + { + id: 3, + dashboardId: 1, + dashboardUID: '_U4zObQMz', + parentVersion: 1, + restoredFrom: 1, + version: 3, + created: '2017-02-22T17:43:01-08:00', + createdBy: 'admin', + message: '', + checked: false, + }, + ], + }); + + versionsView.reset(); + versionsView.fetchVersions(); + await new Promise(process.nextTick); + + expect(versionsView.versions.length).toBeLessThan(VERSIONS_FETCH_LIMIT); + expect(versionsView.versions.find((rev) => rev.version === 1)).toBeUndefined(); + expect(versionsView.continueToken).toBe(''); + + // reset feature flag + // @ts-ignore + config.featureToggles.kubernetesClientDashboardsFolders = false; + }); }); }); diff --git a/public/app/features/dashboard-scene/settings/VersionsEditView.tsx b/public/app/features/dashboard-scene/settings/VersionsEditView.tsx index 96431929a4c..6eb427966cf 100644 --- a/public/app/features/dashboard-scene/settings/VersionsEditView.tsx +++ b/public/app/features/dashboard-scene/settings/VersionsEditView.tsx @@ -83,6 +83,10 @@ export class VersionsEditView extends SceneObjectBase imp return this._start; } + public get continueToken(): string { + return this._continueToken; + } + public getUrlKey(): string { return 'versions'; } @@ -202,7 +206,11 @@ function VersionsEditorSettingsListView({ model }: SceneComponentProps version.checked).length === 2; const showButtons = model.versions.length > 1; const hasMore = model.versions.length >= model.limit; - const isLastPage = model.versions.find((rev) => rev.version === 1); + // older versions may have been cleaned up in the db, so also check if the last page is less than the limit, if so, we are at the end + let isLastPage = model.versions.find((rev) => rev.version === 1) || model.versions.length % model.limit !== 0; + if (config.featureToggles.kubernetesClientDashboardsFolders) { + isLastPage = isLastPage || model.continueToken === ''; + } const viewModeCompare = ( <> diff --git a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx index 16f8d84f237..f311d32d3f1 100644 --- a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.test.tsx @@ -2,6 +2,7 @@ import { screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { render } from 'test/test-utils'; +import { config } from '@grafana/runtime'; import { historySrv } from 'app/features/dashboard-scene/settings/version-history/HistorySrv'; import { createDashboardModelFixture } from '../../state/__fixtures__/dashboardFixtures'; @@ -56,8 +57,7 @@ describe('VersionSettings', () => { }); test('renders a header and a loading indicator followed by results in a table', async () => { - // @ts-ignore - historySrv.getHistoryList.mockResolvedValue(versions); + historySrv.getHistoryList = jest.fn().mockResolvedValue(versions); setup(); expect(screen.getByRole('heading', { name: /versions/i })).toBeInTheDocument(); @@ -75,8 +75,7 @@ describe('VersionSettings', () => { }); test('does not render buttons if versions === 1', async () => { - // @ts-ignore - historySrv.getHistoryList.mockResolvedValue({ + historySrv.getHistoryList = jest.fn().mockResolvedValue({ continueToken: versions.continueToken, versions: versions.versions.slice(0, 1), }); @@ -93,8 +92,7 @@ describe('VersionSettings', () => { }); test('does not render show more button if versions < VERSIONS_FETCH_LIMIT', async () => { - // @ts-ignore - historySrv.getHistoryList.mockResolvedValue({ + historySrv.getHistoryList = jest.fn().mockResolvedValue({ continueToken: versions.continueToken, versions: versions.versions.slice(0, VERSIONS_FETCH_LIMIT - 5), }); @@ -111,8 +109,7 @@ describe('VersionSettings', () => { }); test('renders buttons if versions >= VERSIONS_FETCH_LIMIT', async () => { - // @ts-ignore - historySrv.getHistoryList.mockResolvedValue({ + historySrv.getHistoryList = jest.fn().mockResolvedValue({ continueToken: versions.continueToken, versions: versions.versions.slice(0, VERSIONS_FETCH_LIMIT), }); @@ -134,8 +131,8 @@ describe('VersionSettings', () => { }); test('clicking show more appends results to the table', async () => { - historySrv.getHistoryList - // @ts-ignore + historySrv.getHistoryList = jest + .fn() .mockImplementationOnce(() => Promise.resolve({ continueToken: versions.continueToken, @@ -170,14 +167,47 @@ describe('VersionSettings', () => { }); }); + test('does not show more button when receiving partial page without version 1', async () => { + // Mock a partial page response (less than VERSIONS_FETCH_LIMIT) + historySrv.getHistoryList = jest.fn().mockResolvedValueOnce({ + continueToken: '', + versions: versions.versions.slice(0, VERSIONS_FETCH_LIMIT - 5), + }); + + setup(); + + await waitFor(() => expect(screen.getByRole('table')).toBeInTheDocument()); + + // Verify that show more button is not present since we got a partial page + expect(screen.queryByRole('button', { name: /show more versions/i })).not.toBeInTheDocument(); + // Verify that compare button is still present + expect(screen.getByRole('button', { name: /compare versions/i })).toBeInTheDocument(); + }); + + test('does not show more button when kubernetesClientDashboardsFolders is enabled and continueToken is empty', async () => { + config.featureToggles.kubernetesClientDashboardsFolders = true; + historySrv.getHistoryList = jest.fn().mockResolvedValueOnce({ + continueToken: '', + versions: versions.versions.slice(0, VERSIONS_FETCH_LIMIT - 1), + }); + + setup(); + + await waitFor(() => expect(screen.getByRole('table')).toBeInTheDocument()); + + expect(screen.queryByRole('button', { name: /show more versions/i })).not.toBeInTheDocument(); + expect(screen.getByRole('button', { name: /compare versions/i })).toBeInTheDocument(); + + config.featureToggles.kubernetesClientDashboardsFolders = false; + }); + test('selecting two versions and clicking compare button should render compare view', async () => { - // @ts-ignore - historySrv.getHistoryList.mockResolvedValue({ + historySrv.getHistoryList = jest.fn().mockResolvedValue({ continueToken: versions.continueToken, versions: versions.versions.slice(0, VERSIONS_FETCH_LIMIT), }); - historySrv.getDashboardVersion - // @ts-ignore + historySrv.getDashboardVersion = jest + .fn() .mockImplementationOnce(() => Promise.resolve(diffs.lhs)) .mockImplementationOnce(() => Promise.resolve(diffs.rhs)); diff --git a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx index ac4a4e89de6..31ee8c9ba2e 100644 --- a/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx +++ b/public/app/features/dashboard/components/DashboardSettings/VersionsSettings.tsx @@ -125,7 +125,14 @@ export class VersionsSettings extends PureComponent { })); isLastPage() { - return this.state.versions.find((rev) => rev.version === 1); + if (config.featureToggles.kubernetesClientDashboardsFolders) { + return ( + this.state.versions.find((rev) => rev.version === 1) || + this.state.versions.length % this.limit !== 0 || + this.continueToken === '' + ); + } + return this.state.versions.find((rev) => rev.version === 1) || this.state.versions.length % this.limit !== 0; } onCheck = (ev: React.FormEvent, versionId: number) => {