POC/Provisioning: Import resources from repository (#97105)
* Update endpoints * Add import component * Cleanup * Add import from repository * Rename * Move import to the list view
This commit is contained in:
1 parent
a990f67b51
commit
2129bdf596
4 files changed
+95
-17
No files matched your search
@@ -14,6 +14,7 @@ import {
|
||||
TextLink,
|
||||
ControlledCollapse,
|
||||
FieldSet,
|
||||
Stack,
|
||||
} from '@grafana/ui';
|
||||
import { FormPrompt } from 'app/core/components/FormPrompt/FormPrompt';
|
||||
import { FolderPicker } from 'app/core/components/Select/FolderPicker';
|
||||
@@ -65,7 +66,7 @@ export function ConfigForm({ data }: ConfigFormProps) {
|
||||
} = useForm<RepositoryFormData>({ defaultValues: getDefaultValues(data?.spec) });
|
||||
const [tokenConfigured, setTokenConfigured] = useState(Boolean(data?.metadata?.name));
|
||||
const navigate = useNavigate();
|
||||
const watchType = watch('type');
|
||||
const type = watch('type');
|
||||
|
||||
useEffect(() => {
|
||||
if (request.isSuccess) {
|
||||
@@ -115,7 +116,7 @@ export function ConfigForm({ data }: ConfigFormProps) {
|
||||
>
|
||||
<Input {...register('title', { required: 'This field is required.' })} placeholder={'My config'} />
|
||||
</Field>
|
||||
{watchType === 'github' && (
|
||||
{type === 'github' && (
|
||||
<>
|
||||
<ControlledCollapse collapsible label="Access Token Permissions" isOpen>
|
||||
<p>
|
||||
@@ -173,13 +174,13 @@ export function ConfigForm({ data }: ConfigFormProps) {
|
||||
</>
|
||||
)}
|
||||
|
||||
{watchType === 'local' && (
|
||||
{type === 'local' && (
|
||||
<Field label={'Local path'} error={errors?.path?.message} invalid={!!errors?.path}>
|
||||
<Input {...register('path', { required: 'This field is required.' })} placeholder={'/path/to/repo'} />
|
||||
</Field>
|
||||
)}
|
||||
|
||||
{watchType === 's3' && (
|
||||
{type === 's3' && (
|
||||
<>
|
||||
<Field label={'S3 bucket'} error={errors?.bucket?.message} invalid={!!errors?.bucket}>
|
||||
<Input {...register('bucket', { required: 'This field is required.' })} placeholder={'bucket-name'} />
|
||||
@@ -209,7 +210,9 @@ export function ConfigForm({ data }: ConfigFormProps) {
|
||||
<Switch {...register('editing.delete')} id={'editing.delete'} />
|
||||
</Field>
|
||||
</FieldSet>
|
||||
<Button type={'submit'}>Save</Button>
|
||||
<Stack gap={2}>
|
||||
<Button type={'submit'}>Save</Button>
|
||||
</Stack>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom-v5-compat';
|
||||
import { useAsync } from 'react-use';
|
||||
|
||||
import { AppEvents } from '@grafana/data';
|
||||
import { config, getAppEvents, getBackendSrv } from '@grafana/runtime';
|
||||
import { Button, ConfirmModal } from '@grafana/ui';
|
||||
|
||||
import { Loader } from '../plugins/admin/components/Loader';
|
||||
|
||||
import { useCreateRepositoryImportMutation, useListRepositoryQuery } from './api';
|
||||
|
||||
interface Props {
|
||||
name?: string;
|
||||
folder?: string;
|
||||
}
|
||||
|
||||
export function ImportFromRepository({ name, folder }: Props) {
|
||||
const query = useListRepositoryQuery();
|
||||
const [importResource, importQuery] = useCreateRepositoryImportMutation();
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const navigate = useNavigate();
|
||||
|
||||
// TODO generate endpoints for this
|
||||
const { value } = useAsync(async () => {
|
||||
return getBackendSrv().get(`/apis/folder.grafana.app/v0alpha1/namespaces/${config.namespace}/folders/${folder}`);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const appEvents = getAppEvents();
|
||||
if (importQuery.isSuccess) {
|
||||
appEvents.publish({
|
||||
type: AppEvents.alertSuccess.name,
|
||||
payload: ['Resources imported'],
|
||||
});
|
||||
// TODO the URL will be different based on the type of resource imported
|
||||
navigate(`/dashboards${folder ? `/f/${folder}` : ''}`);
|
||||
} else if (importQuery.isError) {
|
||||
appEvents.publish({
|
||||
type: AppEvents.alertError.name,
|
||||
payload: ['Error importing resources', importQuery.error],
|
||||
});
|
||||
}
|
||||
}, [folder, importQuery.error, importQuery.isError, importQuery.isSuccess, navigate]);
|
||||
|
||||
const onClick = () => {
|
||||
if (!name) {
|
||||
return;
|
||||
}
|
||||
|
||||
importResource({ name, ref: 'main' });
|
||||
};
|
||||
|
||||
if (query.isLoading) {
|
||||
return <Loader />;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Button variant={'secondary'} onClick={() => setIsModalOpen(true)} disabled={importQuery.isLoading || !name}>
|
||||
{importQuery.isLoading ? 'Importing...' : 'Import from repository'}
|
||||
</Button>
|
||||
<ConfirmModal
|
||||
isOpen={isModalOpen}
|
||||
title={'Import resources from repository'}
|
||||
body={`This will pull all resources from the repository into your instance into the "${value?.spec?.title}" folder. Existing dashboards with the same UID will be overwritten. Proceed?`}
|
||||
confirmText={'Import'}
|
||||
onConfirm={onClick}
|
||||
onDismiss={() => setIsModalOpen(false)}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { Page } from 'app/core/components/Page/Page';
|
||||
import { Resource } from '../apiserver/types';
|
||||
|
||||
import { DeleteRepositoryButton } from './DeleteRepositoryButton';
|
||||
import { ImportFromRepository } from './ImportFromRepository';
|
||||
import { RepositorySpec } from './api/types';
|
||||
import { NEW_URL, PROVISIONING_URL } from './constants';
|
||||
import { useRepositoryList } from './hooks';
|
||||
@@ -63,6 +64,7 @@ function RepositoryListPageContent({ items }: { items?: Array<Resource<Repositor
|
||||
<LinkButton variant="secondary" href={`${PROVISIONING_URL}/${item.metadata.name}/edit`}>
|
||||
Edit
|
||||
</LinkButton>
|
||||
<ImportFromRepository name={item?.metadata.name} folder={item.spec.folder} />
|
||||
<DeleteRepositoryButton name={item.metadata.name} />
|
||||
</Stack>
|
||||
</Card>
|
||||
|
||||
@@ -20,17 +20,17 @@ const injectedRtkApi = api.injectEndpoints({
|
||||
query: () => ({ url: BASE_PATH }),
|
||||
providesTags: ['RepositoryList'],
|
||||
}),
|
||||
getRepository: build.query<RepositoryResource, RequestArg>({
|
||||
query: ({ name }) => ({ url: `${BASE_PATH}/${name}` }),
|
||||
}),
|
||||
createRepository: build.mutation<void, RepositoryForCreate>({
|
||||
query: (resource) => ({
|
||||
query: (body) => ({
|
||||
url: BASE_PATH,
|
||||
method: 'POST',
|
||||
body: resource,
|
||||
body,
|
||||
}),
|
||||
invalidatesTags: ['RepositoryList'],
|
||||
}),
|
||||
getRepository: build.query<RepositoryResource, RequestArg>({
|
||||
query: ({ name }) => ({ url: `${BASE_PATH}/${name}` }),
|
||||
}),
|
||||
updateRepository: build.mutation<void, UpdateRequestArg>({
|
||||
query: ({ name, body }) => ({
|
||||
url: `${BASE_PATH}/${name}`,
|
||||
@@ -54,11 +54,6 @@ const injectedRtkApi = api.injectEndpoints({
|
||||
}),
|
||||
invalidatesTags: ['RepositoryList'],
|
||||
}),
|
||||
getRepositoryExport: build.query<ResourceWrapper, RequestArg>({
|
||||
query: ({ name }) => ({
|
||||
url: `${BASE_PATH}/${name}/export`,
|
||||
}),
|
||||
}),
|
||||
createRepositoryExport: build.mutation<ResourceWrapper, RequestArg>({
|
||||
query: ({ name }) => ({
|
||||
url: `${BASE_PATH}/${name}/export`,
|
||||
@@ -94,7 +89,6 @@ const injectedRtkApi = api.injectEndpoints({
|
||||
query: ({ name, path, ref, message }) => ({
|
||||
url: `${BASE_PATH}/${name}/files/${path}`,
|
||||
method: 'DELETE',
|
||||
params: { ref, message },
|
||||
}),
|
||||
}),
|
||||
getRepositoryHello: build.query<HelloWorld, { name: string; whom?: string }>({
|
||||
@@ -103,6 +97,13 @@ const injectedRtkApi = api.injectEndpoints({
|
||||
params: { whom },
|
||||
}),
|
||||
}),
|
||||
createRepositoryImport: build.mutation<ResourceWrapper, { name: string; ref: string }>({
|
||||
query: ({ name, ref }) => ({
|
||||
url: `${BASE_PATH}/${name}/import`,
|
||||
method: 'POST',
|
||||
params: { ref },
|
||||
}),
|
||||
}),
|
||||
getRepositoryStatus: build.query<RepositoryResource, RequestArg>({
|
||||
query: ({ name }) => ({
|
||||
url: `${BASE_PATH}/${name}/status`,
|
||||
@@ -147,13 +148,13 @@ export const {
|
||||
useUpdateRepositoryMutation,
|
||||
useDeleteRepositoryMutation,
|
||||
usePatchRepositoryMutation,
|
||||
useGetRepositoryExportQuery,
|
||||
useCreateRepositoryExportMutation,
|
||||
useGetRepositoryFilesQuery,
|
||||
useUpdateRepositoryFilesMutation,
|
||||
useCreateRepositoryFilesMutation,
|
||||
useDeleteRepositoryFilesMutation,
|
||||
useGetRepositoryHelloQuery,
|
||||
useCreateRepositoryImportMutation,
|
||||
useGetRepositoryStatusQuery,
|
||||
useUpdateRepositoryStatusMutation,
|
||||
usePatchRepositoryStatusMutation,
|
||||
|
||||
Reference in new issue
Block a user