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": {