SaveProvisionedDashboardForm: Reset dashboard dirty state after provisioned dashboard save (#110571)

* SaveProvisionedDashboardForm: Bugfix when changes are saved, save button still enabled
This commit is contained in:
Yunwen Zheng 2025-09-05 12:06:52 -04:00 committed by GitHub
parent d715bda8af
commit 24107abea3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 45 additions and 21 deletions

View File

@ -2040,21 +2040,6 @@
"count": 2
}
},
"public/app/features/dashboard-scene/conditional-rendering/ConditionalRenderingGroupCondition.tsx": {
"no-restricted-syntax": {
"count": 1
}
},
"public/app/features/dashboard-scene/conditional-rendering/ConditionalRenderingGroupVisibility.tsx": {
"no-restricted-syntax": {
"count": 1
}
},
"public/app/features/dashboard-scene/conditional-rendering/ConditionalRenderingTimeRangeSize.tsx": {
"no-restricted-syntax": {
"count": 1
}
},
"public/app/features/dashboard-scene/edit-pane/DashboardEditPaneRenderer.tsx": {
"@typescript-eslint/consistent-type-assertions": {
"count": 1

View File

@ -1276,9 +1276,10 @@ describe('UnifiedDashboardScenePageStateManager', () => {
await loader.loadDashboard({ uid: 'blah-blah', route: DashboardRoutes.Provisioning });
expect(loader.state.dashboard).toBeDefined();
expect(loader.state.dashboard!.serializer.initialSaveModel).toEqual(
v1ProvisionedDashboardResource.resource.dryRun.spec
);
expect(loader.state.dashboard!.serializer.initialSaveModel).toEqual({
...v1ProvisionedDashboardResource.resource.dryRun.spec,
version: v1ProvisionedDashboardResource.resource.dryRun.metadata.generation || 0,
});
});
it('should load a provisioned v2 dashboard', async () => {

View File

@ -230,6 +230,12 @@ abstract class DashboardScenePageStateManagerBase<T>
anno[AnnoKeyManagerIdentity] = repo;
anno[AnnoKeySourcePath] = provisioningPreview.ref ? path + '#' + provisioningPreview.ref : path;
// Include version information to align with the current dashboard schema
const specWithVersion = {
...dryRun.spec,
version: dryRun.metadata.generation || 0,
};
return {
meta: {
canStar: false,
@ -247,7 +253,7 @@ abstract class DashboardScenePageStateManagerBase<T>
// lookup info
provisioning: provisioningPreview,
},
dashboard: dryRun.spec,
dashboard: specWithVersion,
};
}

View File

@ -7,7 +7,7 @@ import { Trans, t } from '@grafana/i18n';
import { getAppEvents, locationService } from '@grafana/runtime';
import { Dashboard } from '@grafana/schema';
import { Button, Field, Input, Stack, TextArea } from '@grafana/ui';
import { RepositoryView } from 'app/api/clients/provisioning/v0alpha1';
import { RepositoryView, Unstructured } from 'app/api/clients/provisioning/v0alpha1';
import kbn from 'app/core/utils/kbn';
import { Resource } from 'app/features/apiserver/types';
import { SaveDashboardFormCommonOptions } from 'app/features/dashboard-scene/saving/SaveDashboardForm';
@ -19,6 +19,7 @@ import {
ProvisionedOperationInfo,
useProvisionedRequestHandler,
} from 'app/features/provisioning/hooks/useProvisionedRequestHandler';
import { SaveDashboardResponseDTO } from 'app/types/dashboard';
import { ProvisionedDashboardFormData } from '../../types/form';
import { buildResourceBranchRedirectUrl } from '../../utils/redirect';
@ -111,8 +112,13 @@ export function SaveProvisionedDashboardForm({
};
const handleDismiss = () => {
dashboard.setState({ isDirty: false });
panelEditor?.onDiscard();
const model = dashboard.getSaveModel();
const resourceData = request?.data?.resource.dryRun;
const saveResponse = createSaveResponseFromResource(resourceData);
dashboard.saveCompleted(model, saveResponse, defaultValues.folder?.uid);
drawer.onClose();
};
@ -292,3 +298,29 @@ function updateURLParams(param: string, value?: string) {
url.searchParams.set(param, value);
window.history.replaceState({}, '', url);
}
/**
* Creates a SaveDashboardResponseDTO from a provisioning resource response
* This allows us to use the standard dashboard save completion flow
*/
function createSaveResponseFromResource(resource?: Unstructured): SaveDashboardResponseDTO {
const uid = resource?.metadata?.name;
const title = resource?.spec?.title;
const slug = kbn.slugifyForUrl(title);
return {
uid,
// Use the current dashboard state version to maintain consistency
version: resource?.metadata?.generation,
id: resource?.spec?.id || 0,
status: 'success',
url: locationUtil.assureBaseUrl(
getDashboardUrl({
uid,
slug,
currentQueryParams: '',
})
),
slug,
};
}