Browse Source

Merge pull request 'Auto API-key configuration' (#11) from auto-api-key-configuration into master

Reviewed-on: #11
pull/14/head
rozetko 2 years ago
parent
commit
124a76e788
  1. 56
      src/components/PluginConfigPage/PluginConfigPage.tsx
  2. 4
      src/components/PluginConfigPage/parts/ConfigurationForm/index.tsx
  3. 24
      src/plugin_state.ts
  4. 2
      src/types.ts

56
src/components/PluginConfigPage/PluginConfigPage.tsx

@ -1,15 +1,14 @@
import React, { FC, useCallback, useEffect, useState } from 'react';
import { Legend, LoadingPlaceholder } from '@grafana/ui';
import { useLocation } from 'react-router-dom';
// import logo from '../../img/logo.svg';
import PluginState, { PluginConnectedStatusResponse } from '../../plugin_state'; import PluginState, { PluginConnectedStatusResponse } from '../../plugin_state';
import ConfigurationForm from './parts/ConfigurationForm'; import ConfigurationForm from './parts/ConfigurationForm';
import RemoveCurrentConfigurationButton from './parts/RemoveCurrentConfigurationButton'; import RemoveCurrentConfigurationButton from './parts/RemoveCurrentConfigurationButton';
import StatusMessageBlock from './parts/StatusMessageBlock'; import StatusMessageBlock from './parts/StatusMessageBlock';
import { DataExporterPluginConfigPageProps } from 'types'; import { DataExporterPluginConfigPageProps } from '../../types';
import { Legend, LoadingPlaceholder } from '@grafana/ui';
import { useLocation } from 'react-router-dom';
import React, { FC, useCallback, useEffect, useState } from 'react';
const PLUGIN_CONFIGURED_QUERY_PARAM = 'pluginConfigured'; const PLUGIN_CONFIGURED_QUERY_PARAM = 'pluginConfigured';
const PLUGIN_CONFIGURED_QUERY_PARAM_TRUTHY_VALUE = 'true'; const PLUGIN_CONFIGURED_QUERY_PARAM_TRUTHY_VALUE = 'true';
@ -71,24 +70,30 @@ export const PluginConfigPage: FC<DataExporterPluginConfigPageProps> = ({
const resetQueryParams = useCallback(() => removePluginConfiguredQueryParams(pluginIsEnabled), [pluginIsEnabled]); const resetQueryParams = useCallback(() => removePluginConfiguredQueryParams(pluginIsEnabled), [pluginIsEnabled]);
const checkConnection = useCallback(async () => { const checkConnection = useCallback(
setCheckingIfPluginIsConnected(true); async (grafanaDataExporterUrl?: string) => {
setPluginConnectionCheckError(null); setCheckingIfPluginIsConnected(true);
if (!pluginMetaDataExporterApiUrl) { setPluginConnectionCheckError(null);
setCheckingIfPluginIsConnected(false);
return;
}
const pluginConnectionResponse = await PluginState.checkIfPluginIsConnected(pluginMetaDataExporterApiUrl);
if (typeof pluginConnectionResponse === 'string') { const backendUrl = grafanaDataExporterUrl || pluginMetaDataExporterApiUrl;
setPluginConnectionCheckError(pluginConnectionResponse);
} else {
setPluginIsConnected(pluginConnectionResponse);
reloadPageWithPluginConfiguredQueryParams(pluginConnectionResponse, true);
}
setCheckingIfPluginIsConnected(false); if (!backendUrl) {
}, [pluginMetaDataExporterApiUrl]); setCheckingIfPluginIsConnected(false);
return;
}
const pluginConnectionResponse = await PluginState.checkIfPluginIsConnected(backendUrl);
if (typeof pluginConnectionResponse === 'string') {
setPluginConnectionCheckError(pluginConnectionResponse);
} else {
setPluginIsConnected(pluginConnectionResponse);
reloadPageWithPluginConfiguredQueryParams(pluginConnectionResponse, true);
}
setCheckingIfPluginIsConnected(false);
},
[pluginMetaDataExporterApiUrl]
);
useEffect(resetQueryParams, [resetQueryParams]); useEffect(resetQueryParams, [resetQueryParams]);
@ -166,10 +171,7 @@ export const PluginConfigPage: FC<DataExporterPluginConfigPageProps> = ({
<Legend>Configure DataExporter</Legend> <Legend>Configure DataExporter</Legend>
{pluginIsConnected ? ( {pluginIsConnected ? (
<> <>
<p> <p>Plugin is connected! You can now go to a dashboard and add the DataExporter panel there.</p>
Plugin is connected! Continue to DataExporter by clicking the{' '}
{/* <img alt="DataExporter Logo" src={logo} width={18} /> icon over there 👈 */}
</p>
<StatusMessageBlock text={`Connected to DataExporter`} /> <StatusMessageBlock text={`Connected to DataExporter`} />
</> </>
) : ( ) : (

4
src/components/PluginConfigPage/parts/ConfigurationForm/index.tsx

@ -16,7 +16,7 @@ import { isEmpty } from 'lodash-es';
const cx = cn.bind(styles); const cx = cn.bind(styles);
type Props = { type Props = {
onSuccessfulSetup: () => void; onSuccessfulSetup: (grafanaDataExporterUrl: string) => void;
defaultDataExporterApiUrl: string; defaultDataExporterApiUrl: string;
}; };
@ -68,7 +68,7 @@ const ConfigurationForm: FC<Props> = ({ onSuccessfulSetup, defaultDataExporterAp
const errorMsg = await PluginState.installPlugin(dataExporterApiUrl); const errorMsg = await PluginState.installPlugin(dataExporterApiUrl);
if (!errorMsg) { if (!errorMsg) {
onSuccessfulSetup(); onSuccessfulSetup(dataExporterApiUrl);
} else { } else {
setSetupErrorMsg(errorMsg); setSetupErrorMsg(errorMsg);
setFormLoading(false); setFormLoading(false);

24
src/plugin_state.ts

@ -14,10 +14,7 @@ export type UpdateGrafanaPluginSettingsProps = {
secureJsonData?: Partial<DataExporterPluginMetaSecureJSONData>; secureJsonData?: Partial<DataExporterPluginMetaSecureJSONData>;
}; };
type InstallPluginResponse<DataExporterAPIResponse = any> = Pick< type InstallPluginResponse<DataExporterAPIResponse = any> = Pick<DataExporterPluginMetaSecureJSONData, 'apiToken'> & {
DataExporterPluginMetaSecureJSONData,
'grafanaToken'
> & {
dataExporterAPIResponse: DataExporterAPIResponse; dataExporterAPIResponse: DataExporterAPIResponse;
}; };
@ -125,13 +122,14 @@ class PluginState {
static timeout = (pollCount: number) => new Promise((resolve) => setTimeout(resolve, 10 * 2 ** pollCount)); static timeout = (pollCount: number) => new Promise((resolve) => setTimeout(resolve, 10 * 2 ** pollCount));
static connectBackend = async <RT>(): Promise<InstallPluginResponse<RT>> => { static connectBackend = async <RT>(): Promise<InstallPluginResponse<RT>> => {
// TODO: try to disable success alerts from Grafana API const { key: apiToken } = await this.createGrafanaToken();
const { key: grafanaToken } = await this.createGrafanaToken(); await this.updateGrafanaPluginSettings({ secureJsonData: { apiToken } });
await this.updateGrafanaPluginSettings({ secureJsonData: { grafanaToken } }); // TODO: display alert on error
const dataExporterAPIResponse = await queryApi<RT>(`/connect`, { const dataExporterAPIResponse = await queryApi<RT>(`/connect`, {
method: 'POST', method: 'POST',
data: { apiToken, url: window.location.toString() },
}); });
return { grafanaToken, dataExporterAPIResponse }; return { apiToken, dataExporterAPIResponse };
}; };
static installPlugin = async (dataExporterApiUrl: string): Promise<string | null> => { static installPlugin = async (dataExporterApiUrl: string): Promise<string | null> => {
@ -158,14 +156,14 @@ class PluginState {
// Step 3. reprovision the Grafana plugin settings, storing information that we get back from DataExporter's backend // Step 3. reprovision the Grafana plugin settings, storing information that we get back from DataExporter's backend
try { try {
const { grafanaToken } = pluginInstallationDataExporterResponse; const { apiToken } = pluginInstallationDataExporterResponse;
await this.updateGrafanaPluginSettings({ await this.updateGrafanaPluginSettings({
jsonData: { jsonData: {
dataExporterApiUrl, dataExporterApiUrl,
}, },
secureJsonData: { secureJsonData: {
grafanaToken, apiToken,
}, },
}); });
} catch (e) { } catch (e) {
@ -179,11 +177,13 @@ class PluginState {
dataExporterApiUrl: string dataExporterApiUrl: string
): Promise<PluginConnectedStatusResponse | string> => { ): Promise<PluginConnectedStatusResponse | string> => {
try { try {
const resp = await queryApi<PluginConnectedStatusResponse>(`/status`, { const resp = await queryApi<PluginConnectedStatusResponse>(`/connect`, {
method: 'GET', method: 'GET',
params: { url: window.location.toString() },
}); });
// TODO: check if the server version is compatible with the plugin // TODO: check if the server version is compatible with the plugin
// TODO: remove configuration if backend says that api key doesn't work
if (resp.version) { if (resp.version) {
return resp; return resp;
} else { } else {
@ -204,7 +204,7 @@ class PluginState {
dataExporterApiUrl: null, dataExporterApiUrl: null,
}; };
const secureJsonData: Required<DataExporterPluginMetaSecureJSONData> = { const secureJsonData: Required<DataExporterPluginMetaSecureJSONData> = {
grafanaToken: null, apiToken: null,
}; };
return this.updateGrafanaPluginSettings({ jsonData, secureJsonData }, false); return this.updateGrafanaPluginSettings({ jsonData, secureJsonData }, false);

2
src/types.ts

@ -5,7 +5,7 @@ export type DataExporterPluginMetaJSONData = {
}; };
export type DataExporterPluginMetaSecureJSONData = { export type DataExporterPluginMetaSecureJSONData = {
grafanaToken: string | null; apiToken: string | null;
}; };
export type AppRootProps = BaseAppRootProps<DataExporterPluginMetaJSONData>; export type AppRootProps = BaseAppRootProps<DataExporterPluginMetaJSONData>;

Loading…
Cancel
Save