diff --git a/.betterer.results b/.betterer.results
index 027526239f6..ee807040ee7 100644
--- a/.betterer.results
+++ b/.betterer.results
@@ -5900,14 +5900,14 @@ exports[`better eslint`] = {
[0, 0, 0, "No untranslated strings. Wrap text with ", "21"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "22"]
],
+ "public/app/features/provisioning/Wizard/JobStep.tsx:5381": [
+ [0, 0, 0, "No untranslated strings. Wrap text with ", "0"]
+ ],
"public/app/features/provisioning/Wizard/MigrateStep.tsx:5381": [
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"],
[0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "1"],
[0, 0, 0, "No untranslated strings. Wrap text with ", "2"]
],
- "public/app/features/provisioning/Wizard/PullStep.tsx:5381": [
- [0, 0, 0, "No untranslated strings in text props. Wrap text with or use t()", "0"]
- ],
"public/app/features/provisioning/Wizard/Stepper.tsx:5381": [
[0, 0, 0, "No untranslated strings. Wrap text with ", "0"]
],
diff --git a/public/app/features/provisioning/JobStatus.tsx b/public/app/features/provisioning/JobStatus.tsx
index 823bcd473e6..15faee89603 100644
--- a/public/app/features/provisioning/JobStatus.tsx
+++ b/public/app/features/provisioning/JobStatus.tsx
@@ -39,7 +39,7 @@ export function JobStatus({ name, onStatusChange, onRunningChange, onErrorChange
}
}, [job, onStatusChange, onErrorChange, onRunningChange]);
- if (!name || jobQuery.isLoading || !job) {
+ if (jobQuery.isLoading || !job) {
return (
diff --git a/public/app/features/provisioning/Wizard/JobStep.tsx b/public/app/features/provisioning/Wizard/JobStep.tsx
index 554806679f8..73c60755e55 100644
--- a/public/app/features/provisioning/Wizard/JobStep.tsx
+++ b/public/app/features/provisioning/Wizard/JobStep.tsx
@@ -1,10 +1,11 @@
-import { ReactNode, useState } from 'react';
+import { skipToken } from '@reduxjs/toolkit/query';
+import { ReactNode, useEffect, useRef, useState } from 'react';
import { useFormContext } from 'react-hook-form';
-import { useAsync } from 'react-use';
-import { Stack, Text } from '@grafana/ui';
+import { Box, Spinner, Stack, Text } from '@grafana/ui';
import { JobStatus } from '../JobStatus';
+import { useListJobQuery } from '../api';
import { StepStatus, useStepStatus } from '../hooks/useStepStatus';
import { WizardFormData } from './types';
@@ -19,59 +20,92 @@ interface JobStepProps {
export type { JobStepProps };
export function JobStep({ onStepUpdate, description, startJob, children }: JobStepProps) {
+ const hasInitialized = useRef(false);
const { watch } = useFormContext();
const repositoryName = watch('repositoryName');
const stepStatus = useStepStatus({ onStepUpdate });
const [jobName, setJobName] = useState();
- useAsync(async () => {
- if (!repositoryName) {
+ // Query the job status if we have a job name
+ const jobQuery = useListJobQuery(jobName ? { watch: true, fieldSelector: `metadata.name=${jobName}` } : skipToken);
+
+ useEffect(() => {
+ if (!repositoryName || hasInitialized.current) {
return;
}
- try {
- stepStatus.setRunning();
- const response = await startJob(repositoryName);
+ hasInitialized.current = true;
+ let isMounted = true;
- if (!response?.metadata?.name) {
- stepStatus.setError('Invalid response from operation');
- throw new Error('Invalid response from operation');
+ const executeJob = async () => {
+ try {
+ if (!isMounted) {
+ return;
+ }
+
+ stepStatus.setRunning();
+ const response = await startJob(repositoryName);
+
+ if (!response?.metadata?.name) {
+ stepStatus.setError('Invalid response from operation');
+ return;
+ }
+ setJobName(response.metadata.name);
+ } catch (error) {
+ if (!isMounted) {
+ return;
+ }
+ stepStatus.setError(error instanceof Error ? error.message : 'Failed to start operation');
}
+ };
- setJobName(response.metadata.name);
- } catch (error) {
- stepStatus.setError(error instanceof Error ? error.message : 'Failed to start operation');
- throw error; // Re-throw to mark the async operation as failed
- }
+ executeJob();
+ return () => {
+ isMounted = false;
+ };
}, [repositoryName, startJob, stepStatus]);
+ const job = jobQuery.data?.items?.[0];
+ const showSpinner = !job;
+
return (
{description && {description}}
{children}
- {jobName && (
- {
- if (success) {
- stepStatus.setSuccess();
- } else {
- stepStatus.setError('Job failed');
- }
- }}
- onRunningChange={(isRunning) => {
- if (isRunning) {
- stepStatus.setRunning();
- }
- }}
- onErrorChange={(error) => {
- if (error) {
- stepStatus.setError(error);
- }
- }}
- />
- )}
+
+ {showSpinner && (
+
+
+
+ Starting...
+
+
+ )}
+
+ {job && (
+ {
+ if (success) {
+ stepStatus.setSuccess();
+ } else {
+ stepStatus.setError('Job failed');
+ }
+ }}
+ onRunningChange={(isRunning) => {
+ if (isRunning) {
+ stepStatus.setRunning();
+ }
+ }}
+ onErrorChange={(error) => {
+ if (error) {
+ stepStatus.setError(error);
+ }
+ }}
+ />
+ )}
+
);
}
diff --git a/public/app/features/provisioning/Wizard/PullStep.tsx b/public/app/features/provisioning/Wizard/PullStep.tsx
index 34fda60bdab..3d7f1d1791a 100644
--- a/public/app/features/provisioning/Wizard/PullStep.tsx
+++ b/public/app/features/provisioning/Wizard/PullStep.tsx
@@ -1,3 +1,5 @@
+import { ReactNode } from 'react';
+
import { useCreateRepositorySyncMutation } from '../api';
import { StepStatus } from '../hooks/useStepStatus';
@@ -5,9 +7,10 @@ import { JobStep } from './JobStep';
interface PullStepProps {
onStepUpdate: (status: StepStatus, error?: string) => void;
+ description?: ReactNode;
}
-export function PullStep({ onStepUpdate }: PullStepProps) {
+export function PullStep({ onStepUpdate, description }: PullStepProps) {
const [syncRepo] = useCreateRepositorySyncMutation();
const startSync = async (repositoryName: string) => {
@@ -21,7 +24,7 @@ export function PullStep({ onStepUpdate }: PullStepProps) {
return (
);