grafana/public/app/features/provisioning/Wizard/BootstrapStep.tsx

159 lines
5.6 KiB
TypeScript

import { useEffect, useMemo } from 'react';
import { Controller, useFormContext } from 'react-hook-form';
import { Trans, t } from '@grafana/i18n';
import { Box, Card, Field, Input, LoadingPlaceholder, Stack, Text } from '@grafana/ui';
import {
RepositoryViewList,
useGetRepositoryFilesQuery,
useGetResourceStatsQuery,
} from 'app/api/clients/provisioning/v0alpha1';
import { generateRepositoryTitle } from 'app/features/provisioning/utils/data';
import { useStepStatus } from './StepStatusContext';
import { getResourceStats, useModeOptions } from './actions';
import { WizardFormData } from './types';
export interface Props {
onOptionSelect: (requiresMigration: boolean) => void;
settingsData?: RepositoryViewList;
repoName: string;
}
export function BootstrapStep({ onOptionSelect, settingsData, repoName }: Props) {
const { setStepStatusInfo } = useStepStatus();
const {
register,
control,
setValue,
watch,
getValues,
formState: { errors },
} = useFormContext<WizardFormData>();
const resourceStats = useGetResourceStatsQuery();
const filesQuery = useGetRepositoryFilesQuery({ name: repoName });
const selectedTarget = watch('repository.sync.target');
const options = useModeOptions(repoName, settingsData);
const { target } = options[0];
const { resourceCount, resourceCountString, fileCount } = useMemo(
() => getResourceStats(filesQuery.data, resourceStats.data),
[filesQuery.data, resourceStats.data]
);
const requiresMigration = settingsData?.legacyStorage || resourceCount > 0;
const isLoading = resourceStats.isLoading || filesQuery.isLoading;
useEffect(() => {
// Pick a name nice name based on type+settings
const repository = getValues('repository');
const title = generateRepositoryTitle(repository);
setValue('repository.title', title);
}, [getValues, setValue]);
useEffect(() => {
setStepStatusInfo({ status: isLoading ? 'running' : 'idle' });
}, [isLoading, setStepStatusInfo]);
useEffect(() => {
setValue('repository.sync.target', target);
onOptionSelect(requiresMigration);
}, [target, setValue, onOptionSelect, requiresMigration]);
if (isLoading) {
return (
<Box padding={4}>
<LoadingPlaceholder
text={t('provisioning.bootstrap-step.text-loading-resource-information', 'Loading resource information...')}
/>
</Box>
);
}
return (
<Stack direction="column" gap={2}>
<Stack direction="column" gap={2}>
<Box alignItems="center" padding={4}>
<Stack direction="row" gap={4} alignItems="flex-start" justifyContent="center">
<Stack direction="column" gap={1} alignItems="center">
<Text color="secondary">
<Trans i18nKey="provisioning.bootstrap-step.grafana">Grafana instance</Trans>
</Text>
<Stack direction="row" gap={2}>
<Text variant="h4">
{resourceCount > 0 ? resourceCountString : t('provisioning.bootstrap-step.empty', 'Empty')}
</Text>
</Stack>
</Stack>
<Stack direction="column" gap={1} alignItems="center">
<Text color="secondary">
<Trans i18nKey="provisioning.bootstrap-step.ext-storage">External storage</Trans>
</Text>
<Text variant="h4">
{fileCount > 0
? t('provisioning.bootstrap-step.files-count', '{{count}} files', { count: fileCount })
: t('provisioning.bootstrap-step.empty', 'Empty')}
</Text>
</Stack>
</Stack>
</Box>
<Controller
name="repository.sync.target"
control={control}
render={({ field: { ref, onChange, ...field } }) => (
<>
{options.map((action) => (
<Card
key={action.target}
isSelected={action.target === selectedTarget}
onClick={() => {
onChange(action.target);
}}
noMargin
{...field}
>
<Card.Heading>{action.label}</Card.Heading>
<Card.Description>
<Stack direction="column" gap={3}>
{action.description}
<Text color="primary">{action.subtitle}</Text>
</Stack>
</Card.Description>
</Card>
))}
</>
)}
/>
{/* Only show title field if folder sync */}
{selectedTarget === 'folder' && (
<Field
label={t('provisioning.bootstrap-step.label-display-name', 'Display name')}
description={t(
'provisioning.bootstrap-step.description-clear-repository-connection',
'Add a clear name for this repository connection'
)}
error={errors.repository?.title?.message}
invalid={!!errors.repository?.title}
required
noMargin
>
<Input
id="repository-title"
{...register('repository.title', {
required: t('provisioning.bootstrap-step.error-field-required', 'This field is required.'),
})}
placeholder={t(
'provisioning.bootstrap-step.placeholder-my-repository-connection',
'My repository connection'
)}
// Autofocus the title field if it's the only available option
autoFocus={options.length === 1 && options[0].target === 'folder'}
/>
</Field>
)}
</Stack>
</Stack>
);
}