mirror of
https://github.com/grafana/grafana.git
synced 2025-02-03 20:21:01 -06:00
Import: Load gcom dashboards from URL (#41799)
* mob next [ci-skip] [ci skip] [skip ci] * mob next [ci-skip] [ci skip] [skip ci] * mob next [ci-skip] [ci skip] [skip ci] * mob next [ci-skip] [ci skip] [skip ci] * mob next [ci-skip] [ci skip] [skip ci] * mob next [ci-skip] [ci skip] [skip ci] * mob next [ci-skip] [ci skip] [skip ci] * Update import in reducer test Co-authored-by: thisisobate <obasiuche62@gmail.com> Co-authored-by: kay delaney <kay@grafana.com> Co-authored-by: Hugo Häggmark <hugo.haggmark@gmail.com>
This commit is contained in:
parent
6c8bc749ca
commit
4f9c096599
@ -1,33 +1,67 @@
|
||||
import React, { FormEvent, PureComponent } from 'react';
|
||||
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { css } from '@emotion/css';
|
||||
import { AppEvents, GrafanaTheme2, NavModel } from '@grafana/data';
|
||||
import { AppEvents, GrafanaTheme2, LoadingState } from '@grafana/data';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Button, stylesFactory, withTheme2, Input, TextArea, Field, Form, FileUpload, Themeable2 } from '@grafana/ui';
|
||||
import {
|
||||
Button,
|
||||
Field,
|
||||
FileUpload,
|
||||
Form,
|
||||
HorizontalGroup,
|
||||
Input,
|
||||
Spinner,
|
||||
stylesFactory,
|
||||
TextArea,
|
||||
Themeable2,
|
||||
VerticalGroup,
|
||||
withTheme2,
|
||||
} from '@grafana/ui';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { connectWithCleanUp } from 'app/core/components/connectWithCleanUp';
|
||||
import { ImportDashboardOverview } from './components/ImportDashboardOverview';
|
||||
import { validateDashboardJson, validateGcomDashboard } from './utils/validation';
|
||||
import { fetchGcomDashboard, importDashboardJson } from './state/actions';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { StoreState } from 'app/types';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
import { cleanUpAction } from '../../core/actions/cleanUp';
|
||||
|
||||
interface OwnProps extends Themeable2 {}
|
||||
type DashboardImportPageRouteSearchParams = {
|
||||
gcomDashboardId?: string;
|
||||
};
|
||||
|
||||
interface ConnectedProps {
|
||||
navModel: NavModel;
|
||||
isLoaded: boolean;
|
||||
}
|
||||
type OwnProps = Themeable2 & GrafanaRouteComponentProps<{}, DashboardImportPageRouteSearchParams>;
|
||||
|
||||
interface DispatchProps {
|
||||
fetchGcomDashboard: typeof fetchGcomDashboard;
|
||||
importDashboardJson: typeof importDashboardJson;
|
||||
}
|
||||
const mapStateToProps = (state: StoreState) => ({
|
||||
navModel: getNavModel(state.navIndex, 'import', undefined, true),
|
||||
loadingState: state.importDashboard.state,
|
||||
});
|
||||
|
||||
type Props = OwnProps & ConnectedProps & DispatchProps;
|
||||
const mapDispatchToProps = {
|
||||
fetchGcomDashboard,
|
||||
importDashboardJson,
|
||||
cleanUpAction,
|
||||
};
|
||||
|
||||
const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
|
||||
class UnthemedDashboardImport extends PureComponent<Props> {
|
||||
constructor(props: Props) {
|
||||
super(props);
|
||||
const { gcomDashboardId } = this.props.queryParams;
|
||||
if (gcomDashboardId) {
|
||||
this.getGcomDashboard({ gcomDashboard: gcomDashboardId });
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.cleanUpAction({ stateSelector: (state: StoreState) => state.importDashboard });
|
||||
}
|
||||
|
||||
onFileUpload = (event: FormEvent<HTMLInputElement>) => {
|
||||
const { importDashboardJson } = this.props;
|
||||
const file = event.currentTarget.files && event.currentTarget.files.length > 0 && event.currentTarget.files[0];
|
||||
@ -135,36 +169,30 @@ class UnthemedDashboardImport extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isLoaded, navModel } = this.props;
|
||||
const { loadingState, navModel } = this.props;
|
||||
|
||||
return (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents>{isLoaded ? <ImportDashboardOverview /> : this.renderImportForm()}</Page.Contents>
|
||||
<Page.Contents>
|
||||
{loadingState === LoadingState.Loading && (
|
||||
<VerticalGroup justify="center">
|
||||
<HorizontalGroup justify="center">
|
||||
<Spinner size={32} />
|
||||
</HorizontalGroup>
|
||||
</VerticalGroup>
|
||||
)}
|
||||
{[LoadingState.Error, LoadingState.NotStarted].includes(loadingState) && this.renderImportForm()}
|
||||
{loadingState === LoadingState.Done && <ImportDashboardOverview />}
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const DashboardImportUnConnected = withTheme2(UnthemedDashboardImport);
|
||||
|
||||
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state: StoreState) => ({
|
||||
navModel: getNavModel(state.navIndex, 'import', undefined, true),
|
||||
isLoaded: state.importDashboard.isLoaded,
|
||||
});
|
||||
|
||||
const mapDispatchToProps: MapDispatchToProps<DispatchProps, Props> = {
|
||||
fetchGcomDashboard,
|
||||
importDashboardJson,
|
||||
};
|
||||
|
||||
export const DashboardImportPage = connectWithCleanUp(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
(state) => state.importDashboard
|
||||
)(DashboardImportUnConnected);
|
||||
|
||||
export default DashboardImportPage;
|
||||
|
||||
DashboardImportPage.displayName = 'DashboardImport';
|
||||
const DashboardImport = connector(DashboardImportUnConnected);
|
||||
DashboardImport.displayName = 'DashboardImport';
|
||||
export default DashboardImport;
|
||||
|
||||
const importStyles = stylesFactory((theme: GrafanaTheme2) => {
|
||||
return {
|
||||
|
@ -2,6 +2,8 @@ import { AppEvents, DataSourceInstanceSettings, locationUtil } from '@grafana/da
|
||||
import { getBackendSrv } from 'app/core/services/backend_srv';
|
||||
import {
|
||||
clearDashboard,
|
||||
fetchDashboard,
|
||||
fetchFailed,
|
||||
ImportDashboardDTO,
|
||||
InputType,
|
||||
LibraryPanelInput,
|
||||
@ -23,11 +25,13 @@ import { LibraryElementExport } from '../../dashboard/components/DashExportModal
|
||||
export function fetchGcomDashboard(id: string): ThunkResult<void> {
|
||||
return async (dispatch) => {
|
||||
try {
|
||||
dispatch(fetchDashboard());
|
||||
const dashboard = await getBackendSrv().get(`/api/gnet/dashboards/${id}`);
|
||||
dispatch(setGcomDashboard(dashboard));
|
||||
dispatch(processInputs(dashboard.json));
|
||||
dispatch(processElements(dashboard.json));
|
||||
} catch (error) {
|
||||
dispatch(fetchFailed());
|
||||
appEvents.emit(AppEvents.alertError, [error.data.message || error]);
|
||||
}
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
setLibraryPanelInputs,
|
||||
} from './reducers';
|
||||
import { LibraryElementDTO } from '../../library-panels/types';
|
||||
import { LoadingState } from '@grafana/data';
|
||||
|
||||
describe('importDashboardReducer', () => {
|
||||
describe('when setGcomDashboard action is dispatched', () => {
|
||||
@ -32,7 +33,7 @@ describe('importDashboardReducer', () => {
|
||||
},
|
||||
meta: { updatedAt: '2001-01-01', orgName: 'Some Org' },
|
||||
source: DashboardSource.Gcom,
|
||||
isLoaded: true,
|
||||
state: LoadingState.Done,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -49,7 +50,7 @@ describe('importDashboardReducer', () => {
|
||||
id: null,
|
||||
},
|
||||
source: DashboardSource.Json,
|
||||
isLoaded: true,
|
||||
state: LoadingState.Done,
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -63,13 +64,13 @@ describe('importDashboardReducer', () => {
|
||||
title: 'Imported',
|
||||
id: null,
|
||||
},
|
||||
isLoaded: true,
|
||||
state: LoadingState.Done,
|
||||
})
|
||||
.whenActionIsDispatched(clearDashboard())
|
||||
.thenStateShouldEqual({
|
||||
...initialImportDashboardState,
|
||||
dashboard: {},
|
||||
isLoaded: false,
|
||||
state: LoadingState.NotStarted,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createSlice, Draft, PayloadAction } from '@reduxjs/toolkit';
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { DataSourceInstanceSettings, LoadingState } from '@grafana/data';
|
||||
import { LibraryElementDTO } from '../../library-panels/types';
|
||||
|
||||
export enum DashboardSource {
|
||||
@ -57,7 +57,7 @@ export interface ImportDashboardState {
|
||||
dashboard: any;
|
||||
source: DashboardSource;
|
||||
inputs: DashboardInputs;
|
||||
isLoaded: boolean;
|
||||
state: LoadingState;
|
||||
}
|
||||
|
||||
export const initialImportDashboardState: ImportDashboardState = {
|
||||
@ -65,7 +65,7 @@ export const initialImportDashboardState: ImportDashboardState = {
|
||||
dashboard: {},
|
||||
source: DashboardSource.Json,
|
||||
inputs: {} as DashboardInputs,
|
||||
isLoaded: false,
|
||||
state: LoadingState.NotStarted,
|
||||
};
|
||||
|
||||
const importDashboardSlice = createSlice({
|
||||
@ -79,7 +79,7 @@ const importDashboardSlice = createSlice({
|
||||
};
|
||||
state.meta = { updatedAt: action.payload.updatedAt, orgName: action.payload.orgName };
|
||||
state.source = DashboardSource.Gcom;
|
||||
state.isLoaded = true;
|
||||
state.state = LoadingState.Done;
|
||||
},
|
||||
setJsonDashboard: (state: Draft<ImportDashboardState>, action: PayloadAction<any>) => {
|
||||
state.dashboard = {
|
||||
@ -88,11 +88,11 @@ const importDashboardSlice = createSlice({
|
||||
};
|
||||
state.meta = initialImportDashboardState.meta;
|
||||
state.source = DashboardSource.Json;
|
||||
state.isLoaded = true;
|
||||
state.state = LoadingState.Done;
|
||||
},
|
||||
clearDashboard: (state: Draft<ImportDashboardState>) => {
|
||||
state.dashboard = {};
|
||||
state.isLoaded = false;
|
||||
state.state = LoadingState.NotStarted;
|
||||
},
|
||||
setInputs: (state: Draft<ImportDashboardState>, action: PayloadAction<any[]>) => {
|
||||
state.inputs = {
|
||||
@ -104,6 +104,13 @@ const importDashboardSlice = createSlice({
|
||||
setLibraryPanelInputs: (state: Draft<ImportDashboardState>, action: PayloadAction<LibraryPanelInput[]>) => {
|
||||
state.inputs.libraryPanels = action.payload;
|
||||
},
|
||||
fetchFailed: (state: Draft<ImportDashboardState>) => {
|
||||
state.dashboard = {};
|
||||
state.state = LoadingState.Error;
|
||||
},
|
||||
fetchDashboard: (state: Draft<ImportDashboardState>) => {
|
||||
state.state = LoadingState.Loading;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -113,6 +120,8 @@ export const {
|
||||
setGcomDashboard,
|
||||
setJsonDashboard,
|
||||
setLibraryPanelInputs,
|
||||
fetchFailed,
|
||||
fetchDashboard,
|
||||
} = importDashboardSlice.actions;
|
||||
|
||||
export const importDashboardReducer = importDashboardSlice.reducer;
|
||||
|
Loading…
Reference in New Issue
Block a user