From e1b5026bc61f3bf180f0f476d5b17d6ad690a155 Mon Sep 17 00:00:00 2001 From: Roberto Jimenez Sanchez Date: Thu, 18 Dec 2025 08:30:02 +0100 Subject: [PATCH] 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 --- .../provisioning/Wizard/SynchronizeStep.tsx | 125 ++++++++++++++---- .../Wizard/hooks/useCreateSyncJob.ts | 24 +++- .../app/features/provisioning/Wizard/types.ts | 1 + public/locales/en-US/grafana.json | 15 ++- 4 files changed, 130 insertions(+), 35 deletions(-) diff --git a/public/app/features/provisioning/Wizard/SynchronizeStep.tsx b/public/app/features/provisioning/Wizard/SynchronizeStep.tsx index 5842b313060..569712babd2 100644 --- a/public/app/features/provisioning/Wizard/SynchronizeStep.tsx +++ b/public/app/features/provisioning/Wizard/SynchronizeStep.tsx @@ -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(); + const { watch, register, getValues } = useFormContext(); 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(); @@ -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 && ( -
    -
  • - - Resources can still be created, edited, or deleted during this process, but changes may not be exported. + + + + Please be aware of the following limitations. For more details, see the{' '} + + Git Sync documentation + + . -
  • -
  • - - Once provisioning is complete, resources will be marked as managed through external storage. - -
  • -
  • - - The duration of this process depends on the number of resources involved. - -
  • -
  • + +
      +
    • + + Resources can still be created, edited, or deleted during this process, but changes may not be + exported. + +
    • +
    • + + Alerts and library panels are not supported in provisioned folders. + +
    • +
    • + + Fine-grained permissions are not supported. Default permissions apply: Admin, Editor, and Viewer roles + are preserved with their standard access levels. + +
    • +
    • + + The duration of this process depends on the number of resources involved. + +
    • + {syncTarget === 'instance' && ( + <> +
    • + + Fine-grained folder permissions will be lost and cannot be recovered. + +
    • +
    • + + Existing alerts and library panels will be lost and will not be usable after migration. + +
    • + + )} + {syncTarget === 'folder' && ( + <> +
    • + + 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. + +
    • +
    • + + You may need to manually remove or manage original folders after migration. + +
    • + + )} +
    + 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 {' '} for step-by-step instructions. -
  • -
+ +
)} + {syncTarget === 'folder' && ( + <> + + Synchronization options + + + + Import existing dashboards from all folders into the new provisioned folder + + } + /> + + + )} {healthStatusNotReady ? ( <> diff --git a/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts b/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts index 7e3c0c30874..f00ef0af024 100644 --- a/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts +++ b/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts @@ -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: {}, } diff --git a/public/app/features/provisioning/Wizard/types.ts b/public/app/features/provisioning/Wizard/types.ts index 0dc2f001a43..34ee246da04 100644 --- a/public/app/features/provisioning/Wizard/types.ts +++ b/public/app/features/provisioning/Wizard/types.ts @@ -9,6 +9,7 @@ export type RepoType = RepositorySpec['type']; export interface MigrateFormData { history: boolean; identifier: boolean; + migrateResources?: boolean; } export interface WizardFormData { diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 79b1f20b8e0..bca9d4875ec 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -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.", "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 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",