Provisioning: Add Git Sync limitations warning and migrate resources checkbox

- Update SynchronizeStep alert to use warning severity with comprehensive Git Sync limitations
- Add conditional warnings for instance sync (permissions loss, alerts/library panels loss)
- Add conditional warnings for folder sync (folder structure changes, manual cleanup needed)
- Add "Migrate existing resources" checkbox for folder sync mode
- Update useCreateSyncJob hook to handle migrateResources option for folder sync
- Extract i18n translations for new strings
This commit is contained in:
Roberto Jimenez Sanchez
2025-12-18 08:30:02 +01:00
parent 7572acf380
commit e1b5026bc6
4 changed files with 130 additions and 35 deletions
@@ -3,7 +3,7 @@ import { memo, useEffect, useState } from 'react';
import { useFormContext } from 'react-hook-form';
import { Trans, t } from '@grafana/i18n';
import { Alert, Button, Field, Spinner, Stack, Text, TextLink } from '@grafana/ui';
import { Alert, Button, Checkbox, Field, Spinner, Stack, Text, TextLink } from '@grafana/ui';
import { Job, useGetRepositoryStatusQuery } from 'app/api/clients/provisioning/v0alpha1';
import { JobStatus } from '../Job/JobStatus';
@@ -12,7 +12,7 @@ import { ProvisioningAlert } from '../Shared/ProvisioningAlert';
import { useStepStatus } from './StepStatusContext';
import { useCreateSyncJob } from './hooks/useCreateSyncJob';
import { useResourceStats } from './hooks/useResourceStats';
import { WizardFormData } from './types';
import { Target, WizardFormData } from './types';
export interface SynchronizeStepProps {
onCancel?: (repoName: string) => void;
@@ -20,13 +20,15 @@ export interface SynchronizeStepProps {
}
export const SynchronizeStep = memo(function SynchronizeStep({ onCancel, isCancelling }: SynchronizeStepProps) {
const { watch } = useFormContext<WizardFormData>();
const { watch, register, getValues } = useFormContext<WizardFormData>();
const { setStepStatusInfo } = useStepStatus();
const [repoName = '', syncTarget] = watch(['repositoryName', 'repository.sync.target']);
const repoName = watch('repositoryName') ?? '';
const syncTarget = watch('repository.sync.target');
const { requiresMigration } = useResourceStats(repoName, syncTarget);
const { createSyncJob } = useCreateSyncJob({
repoName,
requiresMigration,
syncTarget,
setStepStatusInfo,
});
const [job, setJob] = useState<Job>();
@@ -63,7 +65,8 @@ export const SynchronizeStep = memo(function SynchronizeStep({ onCancel, isCance
const isButtonDisabled = hasError || (checked !== undefined && isRepositoryHealthy === false) || healthStatusNotReady;
const startSynchronization = async () => {
const response = await createSyncJob();
const migrateResources = getValues('migrate.migrateResources');
const response = await createSyncJob({ migrateResources });
if (response) {
setJob(response);
}
@@ -108,29 +111,76 @@ export const SynchronizeStep = memo(function SynchronizeStep({ onCancel, isCance
)}
{isRepositoryHealthy && (
<Alert
title={t(
'provisioning.wizard.alert-title',
'Important: No data or configuration will be lost. Dashboards remain accessible during migration, but changes made during this process may not be exported.'
)}
severity={'info'}
title={t('provisioning.wizard.alert-title', 'Important: Review Git Sync limitations before proceeding')}
severity={'warning'}
>
<ul style={{ marginLeft: '16px' }}>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-1">
Resources can still be created, edited, or deleted during this process, but changes may not be exported.
<Stack direction="column" gap={2}>
<Text>
<Trans i18nKey="provisioning.wizard.alert-intro">
Please be aware of the following limitations. For more details, see the{' '}
<TextLink
external
href="https://grafana.com/docs/grafana/latest/as-code/observability-as-code/provision-resources/intro-git-sync/"
>
Git Sync documentation
</TextLink>
.
</Trans>
</li>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-2">
Once provisioning is complete, resources will be marked as managed through external storage.
</Trans>
</li>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-3">
The duration of this process depends on the number of resources involved.
</Trans>
</li>
<li>
</Text>
<ul style={{ marginLeft: '16px', marginTop: 0, marginBottom: 0 }}>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-1">
Resources can still be created, edited, or deleted during this process, but changes may not be
exported.
</Trans>
</li>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-unsupported">
Alerts and library panels are not supported in provisioned folders.
</Trans>
</li>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-permissions">
Fine-grained permissions are not supported. Default permissions apply: Admin, Editor, and Viewer roles
are preserved with their standard access levels.
</Trans>
</li>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-3">
The duration of this process depends on the number of resources involved.
</Trans>
</li>
{syncTarget === 'instance' && (
<>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-instance-permissions">
Fine-grained folder permissions will be lost and cannot be recovered.
</Trans>
</li>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-instance-alerts">
Existing alerts and library panels will be lost and will not be usable after migration.
</Trans>
</li>
</>
)}
{syncTarget === 'folder' && (
<>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-folder-structure">
When migrating existing dashboards, the folder structure will be replicated in the repository.
Original folders will be emptied of dashboards but may still contain alerts or library panels.
</Trans>
</li>
<li>
<Trans i18nKey="provisioning.wizard.alert-point-folder-cleanup">
You may need to manually remove or manage original folders after migration.
</Trans>
</li>
</>
)}
</ul>
<Text color="secondary" variant="bodySmall">
<Trans i18nKey="provisioning.wizard.alert-point-4">
Enterprise instance administrators can display an announcement banner to notify users that migration is
in progress. See{' '}
@@ -139,10 +189,29 @@ export const SynchronizeStep = memo(function SynchronizeStep({ onCancel, isCance
</TextLink>{' '}
for step-by-step instructions.
</Trans>
</li>
</ul>
</Text>
</Stack>
</Alert>
)}
{syncTarget === 'folder' && (
<>
<Text element="h3">
<Trans i18nKey="provisioning.synchronize-step.synchronization-options">Synchronization options</Trans>
</Text>
<Field noMargin>
<Checkbox
{...register('migrate.migrateResources')}
id="migrate-resources"
label={t('provisioning.wizard.sync-option-migrate-resources', 'Migrate existing resources')}
description={
<Trans i18nKey="provisioning.synchronize-step.migrate-resources-description">
Import existing dashboards from all folders into the new provisioned folder
</Trans>
}
/>
</Field>
</>
)}
{healthStatusNotReady ? (
<>
<Stack>
@@ -1,18 +1,28 @@
import { t } from '@grafana/i18n';
import { useCreateRepositoryJobsMutation } from 'app/api/clients/provisioning/v0alpha1';
import { StepStatusInfo } from '../types';
import { StepStatusInfo, Target } from '../types';
export interface UseCreateSyncJobParams {
repoName: string;
requiresMigration: boolean;
syncTarget?: Target;
setStepStatusInfo?: (info: StepStatusInfo) => void;
}
export function useCreateSyncJob({ repoName, requiresMigration, setStepStatusInfo }: UseCreateSyncJobParams) {
export interface CreateSyncJobOptions {
migrateResources?: boolean;
}
export function useCreateSyncJob({
repoName,
requiresMigration,
syncTarget,
setStepStatusInfo,
}: UseCreateSyncJobParams) {
const [createJob, { isLoading }] = useCreateRepositoryJobsMutation();
const createSyncJob = async () => {
const createSyncJob = async (options?: CreateSyncJobOptions) => {
if (!repoName) {
setStepStatusInfo?.({
status: 'error',
@@ -24,7 +34,13 @@ export function useCreateSyncJob({ repoName, requiresMigration, setStepStatusInf
try {
setStepStatusInfo?.({ status: 'running' });
const jobSpec = requiresMigration
// Determine if we should run a migration job:
// - For instance sync: always migrate if there are resources
// - For folder sync: migrate only if user explicitly opted in via checkbox
const shouldMigrate =
syncTarget === 'instance' ? requiresMigration : syncTarget === 'folder' && options?.migrateResources;
const jobSpec = shouldMigrate
? {
migrate: {},
}
@@ -9,6 +9,7 @@ export type RepoType = RepositorySpec['type'];
export interface MigrateFormData {
history: boolean;
identifier: boolean;
migrateResources?: boolean;
}
export interface WizardFormData {
+12 -3
View File
@@ -12182,9 +12182,11 @@
"tooltip-unhealthy-repository": "Unable to pull an unhealthy repository"
},
"synchronize-step": {
"migrate-resources-description": "Import existing dashboards from all folders into the new provisioned folder",
"repository-error": "Repository error",
"repository-error-message": "Unable to check repository status. Please verify the repository configuration and try again.",
"repository-unhealthy": "The repository cannot be synchronized. Cancel provisioning and try again once the issue has been resolved. See details below."
"repository-unhealthy": "The repository cannot be synchronized. Cancel provisioning and try again once the issue has been resolved. See details below.",
"synchronization-options": "Synchronization options"
},
"token-permissions-info": {
"and-click": "and click",
@@ -12201,11 +12203,17 @@
},
"warning-title-default": "Warning",
"wizard": {
"alert-intro": "Please be aware of the following limitations. For more details, see the <2>Git Sync documentation</2>.",
"alert-point-1": "Resources can still be created, edited, or deleted during this process, but changes may not be exported.",
"alert-point-2": "Once provisioning is complete, resources will be marked as managed through external storage.",
"alert-point-3": "The duration of this process depends on the number of resources involved.",
"alert-point-4": "Enterprise instance administrators can display an announcement banner to notify users that migration is in progress. See <2>this guide</2> for step-by-step instructions.",
"alert-title": "Important: No data or configuration will be lost. Dashboards remain accessible during migration, but changes made during this process may not be exported.",
"alert-point-folder-cleanup": "You may need to manually remove or manage original folders after migration.",
"alert-point-folder-structure": "When migrating existing dashboards, the folder structure will be replicated in the repository. Original folders will be emptied of dashboards but may still contain alerts or library panels.",
"alert-point-instance-alerts": "Existing alerts and library panels will be lost and will not be usable after migration.",
"alert-point-instance-permissions": "Fine-grained folder permissions will be lost and cannot be recovered.",
"alert-point-permissions": "Fine-grained permissions are not supported. Default permissions apply: Admin, Editor, and Viewer roles are preserved with their standard access levels.",
"alert-point-unsupported": "Alerts and library panels are not supported in provisioned folders.",
"alert-title": "Important: Review Git Sync limitations before proceeding",
"button-cancel": "Cancel",
"button-cancelling": "Cancelling...",
"button-next": "Finish",
@@ -12223,6 +12231,7 @@
"step-finish": "Choose additional settings",
"step-synchronize": "Synchronize with external storage",
"sync-description": "Sync resources with external storage. After this one-time step, all future updates will be automatically saved to the repository and provisioned back into the instance.",
"sync-option-migrate-resources": "Migrate existing resources",
"title-bootstrap": "Choose what to synchronize",
"title-connect": "Connect to external storage",
"title-finish": "Choose additional settings",