diff --git a/pkg/registry/apis/provisioning/jobs/sync/sync.go b/pkg/registry/apis/provisioning/jobs/sync/sync.go index 7f677a8ce3b..6fec2783a6a 100644 --- a/pkg/registry/apis/provisioning/jobs/sync/sync.go +++ b/pkg/registry/apis/provisioning/jobs/sync/sync.go @@ -14,7 +14,7 @@ import ( //go:generate mockery --name FullSyncFn --structname MockFullSyncFn --inpackage --filename full_sync_fn_mock.go --with-expecter type FullSyncFn func(ctx context.Context, repo repository.Reader, compare CompareFn, clients resources.ResourceClients, currentRef string, repositoryResources resources.RepositoryResources, progress jobs.JobProgressRecorder, tracer tracing.Tracer, maxSyncWorkers int, metrics jobs.JobMetrics) error -//go:generate mockery --name CompareFn --structname MockCompareFn --inpackage --filename compare_fn_mock.go --with-expecter +//go:generate mockery -name CompareFn --structname MockCompareFn --inpackage --filename compare_fn_mock.go --with-expecter type CompareFn func(ctx context.Context, repo repository.Reader, repositoryResources resources.RepositoryResources, ref string) ([]ResourceFileChange, error) //go:generate mockery --name IncrementalSyncFn --structname MockIncrementalSyncFn --inpackage --filename incremental_sync_fn_mock.go --with-expecter diff --git a/public/app/features/provisioning/Wizard/BootstrapStep.tsx b/public/app/features/provisioning/Wizard/BootstrapStep.tsx index df0fe9d8ba1..3c792b81189 100644 --- a/public/app/features/provisioning/Wizard/BootstrapStep.tsx +++ b/public/app/features/provisioning/Wizard/BootstrapStep.tsx @@ -1,10 +1,10 @@ import { css } from '@emotion/css'; -import { memo, useEffect } from 'react'; +import React, { memo, useEffect } from 'react'; import { Controller, useFormContext } from 'react-hook-form'; import { GrafanaTheme2 } from '@grafana/data'; import { t } from '@grafana/i18n'; -import { Box, Card, Field, Icon, Input, LoadingPlaceholder, Stack, Text, useStyles2 } from '@grafana/ui'; +import { Box, Card, Checkbox, Field, Icon, Input, LoadingPlaceholder, Stack, Text, useStyles2 } from '@grafana/ui'; import { RepositoryViewList } from 'app/api/clients/provisioning/v0alpha1'; import { generateRepositoryTitle } from 'app/features/provisioning/utils/data'; @@ -116,30 +116,56 @@ export const BootstrapStep = memo(function BootstrapStep({ settingsData, repoNam {/* Only show title field if folder sync */} {selectedTarget === 'folder' && ( - - + + + + ( + + ) => onChange(e.target.checked)} + label={t( + 'provisioning.bootstrap-step.label-migrate-existing-resources', + 'Migrate all existing resources into this folder' + )} + /> + )} - // Autofocus the title field if it's the only available option - autoFocus={enabledOptions?.length === 1 && enabledOptions[0]?.target === 'folder'} /> - + )} {disabledOptions?.length > 0 && ( diff --git a/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx b/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx index 037df5c0d06..98b82089e6e 100644 --- a/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx +++ b/public/app/features/provisioning/Wizard/ProvisioningWizard.tsx @@ -114,7 +114,12 @@ export const ProvisioningWizard = memo(function ProvisioningWizard({ handleSubmit, } = methods; - const [repoName = '', repoType, syncTarget] = watch(['repositoryName', 'repository.type', 'repository.sync.target']); + const [repoName = '', repoType, syncTarget, migrateExistingResources] = watch([ + 'repositoryName', + 'repository.type', + 'repository.sync.target', + 'migrate.migrateExistingResources', + ]); const [submitData] = useCreateOrUpdateRepository(repoName); const [deleteRepository] = useDeleteRepositoryMutation(); const { @@ -125,6 +130,7 @@ export const ProvisioningWizard = memo(function ProvisioningWizard({ const { createSyncJob, isLoading: isCreatingSkipJob } = useCreateSyncJob({ repoName: repoName, requiresMigration, + migrateExistingResources, setStepStatusInfo, }); diff --git a/public/app/features/provisioning/Wizard/SynchronizeStep.tsx b/public/app/features/provisioning/Wizard/SynchronizeStep.tsx index e3f1ad9cb8a..4ba2c844425 100644 --- a/public/app/features/provisioning/Wizard/SynchronizeStep.tsx +++ b/public/app/features/provisioning/Wizard/SynchronizeStep.tsx @@ -25,11 +25,12 @@ export const SynchronizeStep = memo(function SynchronizeStep({ }: SynchronizeStepProps) { const { watch } = useFormContext(); const { setStepStatusInfo } = useStepStatus(); - const [repoName = ''] = watch(['repositoryName']); + const [repoName = '', migrateExistingResources] = watch(['repositoryName', 'migrate.migrateExistingResources']); const { requiresMigration } = useResourceStats(repoName); const { createSyncJob } = useCreateSyncJob({ repoName, requiresMigration, + migrateExistingResources, setStepStatusInfo, }); const [job, setJob] = useState(); diff --git a/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts b/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts index d44023c6b23..38ce4cc2dd7 100644 --- a/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts +++ b/public/app/features/provisioning/Wizard/hooks/useCreateSyncJob.ts @@ -6,12 +6,14 @@ import { StepStatusInfo } from '../types'; export interface UseCreateSyncJobParams { repoName: string; requiresMigration: boolean; + migrateExistingResources?: boolean; setStepStatusInfo?: (info: StepStatusInfo) => void; } export function useCreateSyncJob({ repoName, requiresMigration, + migrateExistingResources, setStepStatusInfo, }: UseCreateSyncJobParams) { const [createJob, { isLoading }] = useCreateRepositoryJobsMutation(); @@ -28,7 +30,8 @@ export function useCreateSyncJob({ try { setStepStatusInfo?.({ status: 'running' }); - const jobSpec = requiresMigration + const shouldMigrate = requiresMigration || migrateExistingResources === true; + const jobSpec = shouldMigrate ? { migrate: {}, } diff --git a/public/app/features/provisioning/Wizard/types.ts b/public/app/features/provisioning/Wizard/types.ts index 0dc2f001a43..50b49441b68 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; + migrateExistingResources?: boolean; } export interface WizardFormData { diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index 4248d017487..c1a38c08eff 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -11668,6 +11668,7 @@ "dashboards-count_one": "{{count}} dashboard", "dashboards-count_other": "{{count}} dashboard", "description-clear-repository-connection": "Add a clear name for this repository connection", + "description-migrate-existing-resources": "Migrate all existing resources into the repository and pull everything from there.", "empty": "Empty", "error-field-required": "This field is required.", "external-storage-label": "External storage", @@ -11676,6 +11677,7 @@ "folders-count_one": "{{count}} folder", "folders-count_other": "{{count}} folder", "label-display-name": "Display name", + "label-migrate-existing-resources": "Migrate all existing resources into this folder", "placeholder-my-repository-connection": "My repository connection", "text-loading-resource-information": "Loading resource information...", "unavailable-options": {