mirror of https://github.com/grafana/grafana
Prometheus: Use frontend package in Prometheus DS with a feature toggle (#84397)
* add feature toggle usePrometheusFrontendPackage * add feature toggle logic to Prometheus module * use config editor with package and remove configOverhaul feature toggle * update betterer because we will be removing other files as we replace with files from @grafana/prometheus * fix exemplar ds picker selector * add more description to ts-ignore * remove go.work.sum change * copy go.work.sum from main * update go.work.sum after talking with ismail * put back the promlib entry --------- Co-authored-by: ismail simsek <ismailsimsek09@gmail.com>pull/85151/head
parent
d7a94af7d7
commit
c40708ffab
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,152 @@ |
||||
import { css } from '@emotion/css'; |
||||
import React from 'react'; |
||||
|
||||
import { SIGV4ConnectionConfig } from '@grafana/aws-sdk'; |
||||
import { DataSourcePluginOptionsEditorProps, DataSourceSettings, GrafanaTheme2 } from '@grafana/data'; |
||||
import { AdvancedHttpSettings, ConfigSection, DataSourceDescription } from '@grafana/experimental'; |
||||
import { AlertingSettingsOverhaul, PromOptions, PromSettings } from '@grafana/prometheus'; |
||||
import { config } from '@grafana/runtime'; |
||||
import { Alert, FieldValidationMessage, useTheme2 } from '@grafana/ui'; |
||||
|
||||
import { AzureAuthSettings } from './AzureAuthSettings'; |
||||
import { hasCredentials, setDefaultCredentials, resetCredentials } from './AzureCredentialsConfig'; |
||||
import { DataSourcehttpSettingsOverhaul } from './DataSourceHttpSettingsOverhaulPackage'; |
||||
|
||||
export const PROM_CONFIG_LABEL_WIDTH = 30; |
||||
|
||||
export type Props = DataSourcePluginOptionsEditorProps<PromOptions>; |
||||
|
||||
export const ConfigEditor = (props: Props) => { |
||||
const { options, onOptionsChange } = props; |
||||
|
||||
const azureAuthSettings = { |
||||
azureAuthSupported: config.azureAuthEnabled, |
||||
getAzureAuthEnabled: (config: DataSourceSettings<any, any>): boolean => hasCredentials(config), |
||||
setAzureAuthEnabled: (config: DataSourceSettings<any, any>, enabled: boolean) => |
||||
enabled ? setDefaultCredentials(config) : resetCredentials(config), |
||||
azureSettingsUI: AzureAuthSettings, |
||||
}; |
||||
|
||||
const theme = useTheme2(); |
||||
const styles = overhaulStyles(theme); |
||||
|
||||
return ( |
||||
<> |
||||
{options.access === 'direct' && ( |
||||
<Alert title="Error" severity="error"> |
||||
Browser access mode in the Prometheus data source is no longer available. Switch to server access mode. |
||||
</Alert> |
||||
)} |
||||
<DataSourceDescription |
||||
dataSourceName="Prometheus" |
||||
docsLink="https://grafana.com/docs/grafana/latest/datasources/prometheus/configure-prometheus-data-source/" |
||||
/> |
||||
<hr className={`${styles.hrTopSpace} ${styles.hrBottomSpace}`} /> |
||||
<DataSourcehttpSettingsOverhaul |
||||
options={options} |
||||
onOptionsChange={onOptionsChange} |
||||
azureAuthSettings={azureAuthSettings} |
||||
sigV4AuthToggleEnabled={config.sigV4AuthEnabled} |
||||
renderSigV4Editor={ |
||||
<SIGV4ConnectionConfig inExperimentalAuthComponent={true} {...props}></SIGV4ConnectionConfig> |
||||
} |
||||
secureSocksDSProxyEnabled={config.secureSocksDSProxyEnabled} |
||||
/> |
||||
<hr /> |
||||
<ConfigSection |
||||
className={styles.advancedSettings} |
||||
title="Advanced settings" |
||||
description="Additional settings are optional settings that can be configured for more control over your data source." |
||||
> |
||||
<AdvancedHttpSettings |
||||
className={styles.advancedHTTPSettingsMargin} |
||||
config={options} |
||||
onChange={onOptionsChange} |
||||
/> |
||||
<AlertingSettingsOverhaul<PromOptions> options={options} onOptionsChange={onOptionsChange} /> |
||||
<PromSettings options={options} onOptionsChange={onOptionsChange} /> |
||||
</ConfigSection> |
||||
</> |
||||
); |
||||
}; |
||||
/** |
||||
* Use this to return a url in a tooltip in a field. Don't forget to make the field interactive to be able to click on the tooltip |
||||
* @param url |
||||
* @returns |
||||
*/ |
||||
export function docsTip(url?: string) { |
||||
const docsUrl = 'https://grafana.com/docs/grafana/latest/datasources/prometheus/#configure-the-data-source'; |
||||
|
||||
return ( |
||||
<a href={url ? url : docsUrl} target="_blank" rel="noopener noreferrer"> |
||||
Visit docs for more details here. |
||||
</a> |
||||
); |
||||
} |
||||
|
||||
export const validateInput = ( |
||||
input: string, |
||||
pattern: string | RegExp, |
||||
errorMessage?: string |
||||
): boolean | JSX.Element => { |
||||
const defaultErrorMessage = 'Value is not valid'; |
||||
if (input && !input.match(pattern)) { |
||||
return <FieldValidationMessage>{errorMessage ? errorMessage : defaultErrorMessage}</FieldValidationMessage>; |
||||
} else { |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
export function overhaulStyles(theme: GrafanaTheme2) { |
||||
return { |
||||
additionalSettings: css({ |
||||
marginBottom: '25px', |
||||
}), |
||||
secondaryGrey: css({ |
||||
color: `${theme.colors.secondary.text}`, |
||||
opacity: '65%', |
||||
}), |
||||
inlineError: css({ |
||||
margin: '0px 0px 4px 245px', |
||||
}), |
||||
switchField: css({ |
||||
alignItems: 'center', |
||||
}), |
||||
sectionHeaderPadding: css({ |
||||
paddingTop: '32px', |
||||
}), |
||||
sectionBottomPadding: css({ |
||||
paddingBottom: '28px', |
||||
}), |
||||
subsectionText: css({ |
||||
fontSize: '12px', |
||||
}), |
||||
hrBottomSpace: css({ |
||||
marginBottom: '56px', |
||||
}), |
||||
hrTopSpace: css({ |
||||
marginTop: '50px', |
||||
}), |
||||
textUnderline: css({ |
||||
textDecoration: 'underline', |
||||
}), |
||||
versionMargin: css({ |
||||
marginBottom: '12px', |
||||
}), |
||||
advancedHTTPSettingsMargin: css({ |
||||
margin: '24px 0 8px 0', |
||||
}), |
||||
advancedSettings: css({ |
||||
paddingTop: '32px', |
||||
}), |
||||
alertingTop: css({ |
||||
marginTop: '40px !important', |
||||
}), |
||||
overhaulPageHeading: css({ |
||||
fontWeight: '400', |
||||
}), |
||||
container: css({ |
||||
maxwidth: '578', |
||||
}), |
||||
}; |
||||
} |
@ -0,0 +1,175 @@ |
||||
import React, { ReactElement, useState } from 'react'; |
||||
|
||||
import { DataSourceSettings } from '@grafana/data'; |
||||
import { Auth, ConnectionSettings, convertLegacyAuthProps, AuthMethod } from '@grafana/experimental'; |
||||
import { PromOptions, docsTip, overhaulStyles } from '@grafana/prometheus'; |
||||
import { SecureSocksProxySettings, useTheme2 } from '@grafana/ui'; |
||||
// NEED TO EXPORT THIS FROM GRAFANA/UI FOR EXTERNAL DS
|
||||
import { AzureAuthSettings } from '@grafana/ui/src/components/DataSourceSettings/types'; |
||||
|
||||
type Props = { |
||||
options: DataSourceSettings<PromOptions, {}>; |
||||
onOptionsChange: (options: DataSourceSettings<PromOptions, {}>) => void; |
||||
azureAuthSettings: AzureAuthSettings; |
||||
sigV4AuthToggleEnabled: boolean | undefined; |
||||
renderSigV4Editor: React.ReactNode; |
||||
secureSocksDSProxyEnabled: boolean; |
||||
}; |
||||
|
||||
// these are not available yet in grafana
|
||||
export type CustomMethodId = `custom-${string}`; |
||||
|
||||
export type CustomMethod = { |
||||
id: CustomMethodId; |
||||
label: string; |
||||
description: string; |
||||
component: ReactElement; |
||||
}; |
||||
|
||||
export const DataSourcehttpSettingsOverhaul = (props: Props) => { |
||||
const { |
||||
options, |
||||
onOptionsChange, |
||||
azureAuthSettings, |
||||
sigV4AuthToggleEnabled, |
||||
renderSigV4Editor, |
||||
secureSocksDSProxyEnabled, |
||||
} = props; |
||||
|
||||
const newAuthProps = convertLegacyAuthProps({ |
||||
config: options, |
||||
onChange: onOptionsChange, |
||||
}); |
||||
|
||||
const theme = useTheme2(); |
||||
const styles = overhaulStyles(theme); |
||||
|
||||
// for custom auth methods sigV4 and azure auth
|
||||
let customMethods: CustomMethod[] = []; |
||||
|
||||
const [sigV4Selected, setSigV4Selected] = useState<boolean>(options.jsonData.sigV4Auth || false); |
||||
|
||||
const sigV4Id = 'custom-sigV4Id'; |
||||
|
||||
const sigV4Option: CustomMethod = { |
||||
id: sigV4Id, |
||||
label: 'SigV4 auth', |
||||
description: 'This is SigV4 auth description', |
||||
component: <>{renderSigV4Editor}</>, |
||||
}; |
||||
|
||||
if (sigV4AuthToggleEnabled) { |
||||
customMethods.push(sigV4Option); |
||||
} |
||||
|
||||
const azureAuthEnabled: boolean = |
||||
(azureAuthSettings?.azureAuthSupported && azureAuthSettings.getAzureAuthEnabled(options)) || false; |
||||
|
||||
const [azureAuthSelected, setAzureAuthSelected] = useState<boolean>(azureAuthEnabled); |
||||
|
||||
const azureAuthId = 'custom-azureAuthId'; |
||||
|
||||
const azureAuthOption: CustomMethod = { |
||||
id: azureAuthId, |
||||
label: 'Azure auth', |
||||
description: 'This is Azure auth description', |
||||
component: ( |
||||
<> |
||||
{azureAuthSettings.azureSettingsUI && ( |
||||
<azureAuthSettings.azureSettingsUI dataSourceConfig={options} onChange={onOptionsChange} /> |
||||
)} |
||||
</> |
||||
), |
||||
}; |
||||
|
||||
// allow the option to show in the dropdown
|
||||
if (azureAuthSettings?.azureAuthSupported) { |
||||
customMethods.push(azureAuthOption); |
||||
} |
||||
|
||||
function returnSelectedMethod() { |
||||
if (sigV4Selected) { |
||||
return sigV4Id; |
||||
} |
||||
|
||||
if (azureAuthSelected) { |
||||
return azureAuthId; |
||||
} |
||||
|
||||
return newAuthProps.selectedMethod; |
||||
} |
||||
|
||||
// Do we need this switch anymore? Update the language.
|
||||
let urlTooltip; |
||||
switch (options.access) { |
||||
case 'direct': |
||||
urlTooltip = ( |
||||
<> |
||||
Your access method is <em>Browser</em>, this means the URL needs to be accessible from the browser. |
||||
{docsTip()} |
||||
</> |
||||
); |
||||
break; |
||||
case 'proxy': |
||||
urlTooltip = ( |
||||
<> |
||||
Your access method is <em>Server</em>, this means the URL needs to be accessible from the grafana |
||||
backend/server. |
||||
{docsTip()} |
||||
</> |
||||
); |
||||
break; |
||||
default: |
||||
urlTooltip = <>Specify a complete HTTP URL (for example http://your_server:8080) {docsTip()}</>;
|
||||
} |
||||
|
||||
return ( |
||||
<> |
||||
<ConnectionSettings |
||||
urlPlaceholder="http://localhost:9090" |
||||
config={options} |
||||
onChange={onOptionsChange} |
||||
urlLabel="Prometheus server URL" |
||||
urlTooltip={urlTooltip} |
||||
/> |
||||
<hr className={`${styles.hrTopSpace} ${styles.hrBottomSpace}`} /> |
||||
<Auth |
||||
{...newAuthProps} |
||||
customMethods={customMethods} |
||||
onAuthMethodSelect={(method) => { |
||||
// sigV4Id
|
||||
if (sigV4AuthToggleEnabled) { |
||||
setSigV4Selected(method === sigV4Id); |
||||
} |
||||
|
||||
// Azure
|
||||
if (azureAuthSettings?.azureAuthSupported) { |
||||
setAzureAuthSelected(method === azureAuthId); |
||||
azureAuthSettings.setAzureAuthEnabled(options, method === azureAuthId); |
||||
} |
||||
|
||||
onOptionsChange({ |
||||
...options, |
||||
basicAuth: method === AuthMethod.BasicAuth, |
||||
withCredentials: method === AuthMethod.CrossSiteCredentials, |
||||
jsonData: { |
||||
...options.jsonData, |
||||
sigV4Auth: method === sigV4Id, |
||||
oauthPassThru: method === AuthMethod.OAuthForward, |
||||
}, |
||||
}); |
||||
}} |
||||
// If your method is selected pass its id to `selectedMethod`,
|
||||
// otherwise pass the id from converted legacy data
|
||||
selectedMethod={returnSelectedMethod()} |
||||
/> |
||||
<div className={styles.sectionBottomPadding} /> |
||||
{secureSocksDSProxyEnabled && ( |
||||
<> |
||||
<SecureSocksProxySettings options={options} onOptionsChange={onOptionsChange} /> |
||||
<div className={styles.sectionBottomPadding} /> |
||||
</> |
||||
)} |
||||
</> |
||||
); |
||||
}; |
@ -1,11 +1,27 @@ |
||||
import { DataSourcePlugin } from '@grafana/data'; |
||||
import { |
||||
PrometheusDatasource as PrometheusDatasourcePackage, |
||||
PromQueryEditorByApp as PromQueryEditorByAppPackage, |
||||
PromCheatSheet as PromCheatSheetPackage, |
||||
} from '@grafana/prometheus'; |
||||
import { config } from '@grafana/runtime'; |
||||
|
||||
import PromCheatSheet from './components/PromCheatSheet'; |
||||
import PromQueryEditorByApp from './components/PromQueryEditorByApp'; |
||||
import { ConfigEditor } from './configuration/ConfigEditor'; |
||||
import { ConfigEditor as ConfigEditorPackage } from './configuration/ConfigEditorPackage'; |
||||
import { PrometheusDatasource } from './datasource'; |
||||
|
||||
export const plugin = new DataSourcePlugin(PrometheusDatasource) |
||||
.setQueryEditor(PromQueryEditorByApp) |
||||
.setConfigEditor(ConfigEditor) |
||||
.setQueryEditorHelp(PromCheatSheet); |
||||
const usePackage = config.featureToggles.usePrometheusFrontendPackage; |
||||
|
||||
const PrometheusDataSourceUsed = usePackage ? PrometheusDatasource : PrometheusDatasourcePackage; |
||||
const PromQueryEditorByAppUsed = usePackage ? PromQueryEditorByApp : PromQueryEditorByAppPackage; |
||||
const ConfigEditorUsed = usePackage ? ConfigEditor : ConfigEditorPackage; |
||||
const PromCheatSheetUsed = usePackage ? PromCheatSheet : PromCheatSheetPackage; |
||||
|
||||
// @ts-ignore These type errors will be removed when we fully migrate to the @grafana/prometheus package
|
||||
export const plugin = new DataSourcePlugin(PrometheusDataSourceUsed) |
||||
// @ts-ignore These type errors will be removed when we fully migrate to the @grafana/prometheus package
|
||||
.setQueryEditor(PromQueryEditorByAppUsed) |
||||
.setConfigEditor(ConfigEditorUsed) |
||||
.setQueryEditorHelp(PromCheatSheetUsed); |
||||
|
Loading…
Reference in new issue