mirror of
https://github.com/grafana/grafana.git
synced 2026-09-05 04:40:13 -05:00
Admin: Add support bundles (#60536)
* Add support bundles Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> Co-authored-by: Kalle Persson <kalle.persson@grafana.com> * tweak code owners * rename and lint frontend * lint * fix backend lint * register feature flag * add feature toggle. fix small backend issues Co-authored-by: ievaVasiljeva <ieva.vasiljeva@grafana.com> Co-authored-by: Kalle Persson <kalle.persson@grafana.com>
This commit is contained in:
co-authored by
ievaVasiljeva
Kalle Persson
parent
6e2b148745
commit
2c7410c87d
@@ -0,0 +1,73 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { useAsyncFn } from 'react-use';
|
||||
|
||||
import { dateTimeFormat } from '@grafana/data';
|
||||
import { getBackendSrv } from '@grafana/runtime';
|
||||
import { LinkButton } from '@grafana/ui';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
|
||||
const subTitle = (
|
||||
<span>
|
||||
Support bundles allow you to easily collect and share Grafana logs, configuration, and data with the Grafana Labs
|
||||
team.
|
||||
</span>
|
||||
);
|
||||
|
||||
type SupportBundleState = 'complete' | 'error' | 'timeout' | 'pending';
|
||||
|
||||
interface SupportBundle {
|
||||
uid: string;
|
||||
state: SupportBundleState;
|
||||
creator: string;
|
||||
createdAt: number;
|
||||
expiresAt: number;
|
||||
}
|
||||
|
||||
const getBundles = () => {
|
||||
return getBackendSrv().get<SupportBundle[]>('/api/support-bundles');
|
||||
};
|
||||
|
||||
function SupportBundles() {
|
||||
const [bundlesState, fetchBundles] = useAsyncFn(getBundles, []);
|
||||
|
||||
useEffect(() => {
|
||||
fetchBundles();
|
||||
}, [fetchBundles]);
|
||||
|
||||
return (
|
||||
<Page navId="support-bundles" subTitle={subTitle}>
|
||||
<Page.Contents isLoading={bundlesState.loading}>
|
||||
<LinkButton href="admin/support-bundles/create" variant="primary">
|
||||
Create New Support Bundle
|
||||
</LinkButton>
|
||||
|
||||
<table className="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Requested by</th>
|
||||
<th>Expires</th>
|
||||
<th style={{ width: '1%' }} />
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{bundlesState?.value?.map((b) => (
|
||||
<tr key={b.uid}>
|
||||
<th>{dateTimeFormat(b.createdAt * 1000)}</th>
|
||||
<th>{b.creator}</th>
|
||||
<th>{dateTimeFormat(b.expiresAt * 1000)}</th>
|
||||
<th>
|
||||
<LinkButton disabled={b.state !== 'complete'} target={'_self'} href={'/api/support-bundles/' + b.uid}>
|
||||
Download
|
||||
</LinkButton>
|
||||
</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
||||
export default SupportBundles;
|
||||
@@ -0,0 +1,96 @@
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { useAsyncFn } from 'react-use';
|
||||
|
||||
import { getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import { Form, Button, Field, Checkbox } from '@grafana/ui';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
|
||||
// move to types
|
||||
export interface SupportBundleCreateRequest {
|
||||
collectors: string[];
|
||||
}
|
||||
|
||||
export interface SupportBundleCollector {
|
||||
uid: string;
|
||||
displayName: string;
|
||||
description: string;
|
||||
includedByDefault: boolean;
|
||||
default: boolean;
|
||||
}
|
||||
|
||||
export interface Props {}
|
||||
|
||||
const createSupportBundle = async (data: SupportBundleCreateRequest) => {
|
||||
const result = await getBackendSrv().post('/api/support-bundles', data);
|
||||
return result;
|
||||
};
|
||||
|
||||
export const SupportBundlesCreate = ({}: Props): JSX.Element => {
|
||||
const onSubmit = useCallback(async (data) => {
|
||||
try {
|
||||
const selectedLabelsArray = Object.keys(data).filter((key) => data[key]);
|
||||
const response = await createSupportBundle({ collectors: selectedLabelsArray });
|
||||
console.info(response);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
locationService.push('/admin/support-bundles');
|
||||
}, []);
|
||||
|
||||
const [components, setComponents] = useState<SupportBundleCollector[]>([]);
|
||||
// populate components from the backend
|
||||
const populateComponents = async () => {
|
||||
return await getBackendSrv().get('/api/support-bundles/collectors');
|
||||
};
|
||||
|
||||
const [state, fetchComponents] = useAsyncFn(populateComponents);
|
||||
useEffect(() => {
|
||||
fetchComponents().then((res) => {
|
||||
setComponents(res);
|
||||
});
|
||||
}, [fetchComponents]);
|
||||
|
||||
// turn components into a uuid -> enabled map
|
||||
const values: Record<string, boolean> = components.reduce((acc, curr) => {
|
||||
return { ...acc, [curr.uid]: curr.default };
|
||||
}, {});
|
||||
|
||||
return (
|
||||
<Page navId="support-bundles" pageNav={{ text: 'Create support bundle' }}>
|
||||
<Page.Contents>
|
||||
<Page.OldNavOnly>
|
||||
<h3 className="page-sub-heading">Create support bundle</h3>
|
||||
</Page.OldNavOnly>
|
||||
{state.error && <p>{state.error}</p>}
|
||||
{!!components.length && (
|
||||
<Form defaultValues={values} onSubmit={onSubmit} validateOn="onSubmit">
|
||||
{({ register, errors }) => {
|
||||
return (
|
||||
<>
|
||||
{components.map((component) => {
|
||||
return (
|
||||
<Field key={component.uid}>
|
||||
<Checkbox
|
||||
{...register(component.uid)}
|
||||
label={component.displayName}
|
||||
id={component.uid}
|
||||
description={component.description}
|
||||
defaultChecked={component.default}
|
||||
disabled={component.includedByDefault}
|
||||
/>
|
||||
</Field>
|
||||
);
|
||||
})}
|
||||
<Button type="submit">Create</Button>
|
||||
</>
|
||||
);
|
||||
}}
|
||||
</Form>
|
||||
)}
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
||||
export default SupportBundlesCreate;
|
||||
Reference in New Issue
Block a user