@ -1,5 +1,5 @@
import { css , cx } from '@emotion/css' ;
import { useState , useCallback , useId } from 'react' ;
import { css } from '@emotion/css' ;
import { useState , useCallback , useId , useMemo } from 'react' ;
import { SelectableValue } from '@grafana/data' ;
import { selectors } from '@grafana/e2e-selectors' ;
@ -7,12 +7,13 @@ import { selectors } from '@grafana/e2e-selectors';
import { useTheme2 } from '../../themes' ;
import { t , Trans } from '../../utils/i18n' ;
import { Alert } from '../Alert/Alert' ;
import { FormField } from '../FormField/FormField ';
import { InlineFormLabel } from '../FormLabel/FormLabel ';
import { Button } from '../Button ';
import { Field } from '../Forms/Field ';
import { InlineField } from '../Forms/InlineField' ;
import { Input } from '../Forms/Legacy/Input/Input ';
import { RadioButtonGroup } from '../Forms/RadioButtonGroup/RadioButtonGroup ';
import { Icon } from '../Icon/Icon' ;
import { Select } from '../Select/Select' ;
import { Input } from '../Input/Input' ;
import { Stack } from '../Layout/Stack/Stack' ;
import { InlineSwitch } from '../Switch/Switch' ;
import { TagsInput } from '../TagsInput/TagsInput' ;
import { Text } from '../Text/Text' ;
@ -24,26 +25,16 @@ import { SecureSocksProxySettings } from './SecureSocksProxySettings';
import { TLSAuthSettings } from './TLSAuthSettings' ;
import { HttpSettingsProps } from './types' ;
const ACCESS_OPTIONS : Array < SelectableValue < string > > = [
{
label : t ( 'grafana-ui.data-source-http-settings.access-options-proxy' , 'Server (default)' ) ,
value : 'proxy' ,
} ,
{
label : t ( 'grafana-ui.data-source-http-settings.access-options-browser' , 'Browser' ) ,
value : 'direct' ,
} ,
] ;
const DEFAULT_ACCESS_OPTION = {
label : t ( 'grafana-ui.data-source-http-settings.access-options-proxy' , 'Server (default)' ) ,
value : 'proxy' ,
} ;
const ACCESS_HELP_ID = 'grafana-http-access-help' ;
const HttpAccessHelp = ( ) = > {
return (
// eslint-disable-next-line @grafana/no-untranslated-strings
< Alert severity = "info" title = "" topSpacing = { 3 } >
< Alert
severity = "info"
title = { t ( 'grafana-ui.data-source-http-settings.access-help-title' , 'Access help' ) }
topSpacing = { 3 }
id = { ACCESS_HELP_ID }
>
< p >
< Trans i18nKey = "grafana-ui.data-source-http-settings.access-help-details" >
Access mode controls how requests to the data source will be handled .
@ -79,6 +70,9 @@ const HttpAccessHelp = () => {
const LABEL_WIDTH = 26 ;
/ * *
* @deprecated Use components from ` @grafana/plugin-ui ` instead , according to the [ migration guide ] ( https : //github.com/grafana/plugin-ui/blob/main/src/components/ConfigEditor/migrating-from-datasource-http-settings.md).
* /
export const DataSourceHttpSettings = ( props : HttpSettingsProps ) = > {
const {
defaultUrl ,
@ -94,6 +88,22 @@ export const DataSourceHttpSettings = (props: HttpSettingsProps) => {
urlDocs ,
} = props ;
const ACCESS_OPTIONS : Array < SelectableValue < string > > = useMemo (
( ) = > [
{
label : t ( 'grafana-ui.data-source-http-settings.server-mode-label' , 'Server (default)' ) ,
value : 'proxy' ,
} ,
{
label : t ( 'grafana-ui.data-source-http-settings.browser-mode-label' , 'Browser' ) ,
value : 'direct' ,
} ,
] ,
[ ]
) ;
const DEFAULT_ACCESS_OPTION = useMemo ( ( ) = > ACCESS_OPTIONS [ 0 ] , [ ACCESS_OPTIONS ] ) ;
const [ isAccessHelpVisible , setIsAccessHelpVisible ] = useState ( false ) ;
const [ azureAuthEnabled , setAzureAuthEnabled ] = useState ( false ) ;
const theme = useTheme2 ( ) ;
@ -160,246 +170,235 @@ export const DataSourceHttpSettings = (props: HttpSettingsProps) => {
) ;
}
const accessSelect = (
< Select
aria - label = { t ( 'grafana-ui.data-source-http-settings.default-url-access-select' , 'Access' ) }
className = "width-20 gf-form-input"
options = { ACCESS_OPTIONS }
value = { ACCESS_OPTIONS . filter ( ( o ) = > o . value === dataSourceConfig . access ) [ 0 ] || DEFAULT_ACCESS_OPTION }
onChange = { ( selectedValue ) = > onSettingsChange ( { access : selectedValue.value } ) }
disabled = { dataSourceConfig . readOnly }
/ >
) ;
const isValidUrl = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/ . test (
dataSourceConfig . url
) ;
const notValidStyle = css ( {
boxShadow : ` inset 0 0px 5px ${ theme . v1 . palette . red } ` ,
const gridLayout = css ( {
display : 'grid' ,
gridTemplateColumns : 'auto 1fr' ,
gap : theme.spacing ( 0.5 ) ,
} ) ;
const inputStyle = cx ( { [ ` width-20 ` ] : true , [ notValidStyle ] : ! isValidUrl } ) ;
const fromFieldId = useId ( ) ;
const urlInput = (
< Input
id = { fromFieldId }
className = { inputStyle }
placeholder = { defaultUrl }
value = { dataSourceConfig . url }
data - testid = { selectors . components . DataSource . DataSourceHttpSettings . urlInput }
onChange = { ( event ) = > onSettingsChange ( { url : event.currentTarget.value } ) }
disabled = { dataSourceConfig . readOnly }
/ >
) ;
return (
< div className = "gf-form-group" >
< >
< Stack direction = "column" gap = { 5 } >
< section >
< h3 className = "page-heading" >
< Trans i18nKey = "grafana-ui.data-source-http-settings.heading" > HTTP < / Trans >
< / h3 >
< div className = "gf-form-group" >
< div className = "gf-form" >
< FormField
interactive = { urlDocs ? true : false }
label = { urlLabel ? ? t ( 'grafana-ui.data-source-http-settings.url-label' , 'URL' ) }
labelWidth = { 13 }
tooltip = { urlTooltip }
inputEl = { urlInput }
/ >
< / div >
{ showAccessOptions && (
< >
< div className = "gf-form-inline" >
< div className = "gf-form" >
< FormField
label = { t ( 'grafana-ui.data-source-http-settings.access-label' , 'Access' ) }
labelWidth = { 13 }
inputWidth = { 20 }
inputEl = { accessSelect }
/ >
< / div >
< div className = "gf-form" >
< button
type = "button"
className = "gf-form-label query-keyword pointer"
onClick = { ( ) = > setIsAccessHelpVisible ( ( isVisible ) = > ! isVisible ) }
>
< Trans i18nKey = "grafana-ui.data-source-http-settings.access-help" >
Help & nbsp ;
< Icon name = { isAccessHelpVisible ? 'angle-down' : 'angle-right' } style = { { marginBottom : 0 } } / >
< / Trans >
< / button >
< / div >
< / div >
{ isAccessHelpVisible && < HttpAccessHelp / > }
< / >
) }
{ dataSourceConfig . access === 'proxy' && (
< div className = "gf-form-group" >
< div className = "gf-form" >
< InlineFormLabel
width = { 13 }
tooltip = { t (
'grafana-ui.data-source-http-settings.allowed-cookies-tooltip' ,
'Grafana proxy deletes forwarded cookies by default. Specify cookies by name that should be forwarded to the data source.'
) }
>
< Trans i18nKey = "grafana-ui.data-source-http-settings.allowed-cookies" > Allowed cookies < / Trans >
< / InlineFormLabel >
< TagsInput
tags = { dataSourceConfig . jsonData . keepCookies }
width = { 40 }
onChange = { ( cookies ) = >
onSettingsChange ( { jsonData : { . . . dataSourceConfig . jsonData , keepCookies : cookies } } )
< Field
label = { urlLabel ? ? 'URL' }
description = { urlTooltip }
invalid = { ! isValidUrl }
error = { ! isValidUrl && t ( 'grafana-ui.data-source-http-settings.invalid-url-error' , 'Invalid URL' ) }
disabled = { dataSourceConfig . readOnly }
>
< Input
id = { fromFieldId }
width = { 40 }
placeholder = { defaultUrl }
value = { dataSourceConfig . url }
data - testid = { selectors . components . DataSource . DataSourceHttpSettings . urlInput }
onChange = { ( event ) = > onSettingsChange ( { url : event.currentTarget.value } ) }
/ >
< / Field >
{ showAccessOptions && (
< >
< Field
label = { t ( 'grafana-ui.data-source-http-settings.access-label' , 'Access' ) }
disabled = { dataSourceConfig . readOnly }
>
< Stack direction = "row" gap = { 0.5 } >
< RadioButtonGroup
aria - label = { t ( 'grafana-ui.data-source-http-settings.access-label' , 'Access' ) }
options = { ACCESS_OPTIONS }
value = {
ACCESS_OPTIONS . find ( ( o ) = > o . value === dataSourceConfig . access ) ? . value ||
DEFAULT_ACCESS_OPTION . value
}
disabled = { dataSourceConfig . readOnly }
onChange = { ( selectedValue ) = > onSettingsChange ( { access : selectedValue } ) }
/ >
< / div >
< div className = "gf-form" >
< FormField
label = { t ( 'grafana-ui.data-source-http-settings.timeout-form-label' , 'Timeout' ) }
type = "number"
labelWidth = { 13 }
inputWidth = { 20 }
tooltip = { t ( 'grafana-ui.data-source-http-settings.timeout-tooltip' , 'HTTP request timeout in seconds' ) }
placeholder = { t ( 'grafana-ui.data-source-http-settings.timeout-label' , 'Timeout in seconds' ) }
aria - label = { t ( 'grafana-ui.data-source-http-settings.timeout-label' , 'Timeout in seconds' ) }
value = { dataSourceConfig . jsonData . timeout }
onChange = { ( event ) = > {
onSettingsChange ( {
jsonData : { . . . dataSourceConfig . jsonData , timeout : parseInt ( event . currentTarget . value , 10 ) } ,
} ) ;
} }
disabled = { dataSourceConfig . readOnly }
/ >
< / div >
< / div >
) }
< / div >
< / >
< Button
type = "button"
variant = "secondary"
size = "md"
fill = "outline"
onClick = { ( ) = > setIsAccessHelpVisible ( ( isVisible ) = > ! isVisible ) }
aria - expanded = { isAccessHelpVisible }
aria - controls = { ACCESS_HELP_ID }
>
< Trans i18nKey = "grafana-ui.data-source-http-settings.access-help" >
Help & nbsp ;
< Icon name = { isAccessHelpVisible ? 'angle-down' : 'angle-right' } / >
< / Trans >
< / Button >
< / Stack >
< / Field >
< >
< h3 className = "page-heading" >
< Trans i18nKey = "grafana-ui.data-source-http-settings.auth" > Auth < / Trans >
< / h3 >
< div className = "gf-form-group" >
< div className = "gf-form-inline" >
< InlineField
label = { t ( 'grafana-ui.data-source-http-settings.basic-auth-label' , 'Basic auth' ) }
labelWidth = { LABEL_WIDTH }
disabled = { dataSourceConfig . readOnly }
{ isAccessHelpVisible && < HttpAccessHelp / > }
< / >
) }
{ dataSourceConfig . access === 'proxy' && (
< >
< Field
label = { t ( 'grafana-ui.data-source-http-settings.allowed-cookies' , 'Allowed cookies' ) }
description = { t (
'grafana-ui.data-source-http-settings.allowed-cookies-description' ,
'Grafana proxy deletes forwarded cookies by default. Specify cookies by name that should be forwarded to the data source.'
) }
>
< InlineSwitch
id = "http-settings-basic-auth"
value = { dataSourceConfig . basicAuth }
onChange = { ( event ) = > {
onSettingsChange ( { basicAuth : event ! . currentTarget . checked } ) ;
} }
< TagsInput
tags = { dataSourceConfig . jsonData . keepCookies }
width = { 40 }
onChange = { ( cookies ) = >
onSettingsChange ( { jsonData : { . . . dataSourceConfig . jsonData , keepCookies : cookies } } )
}
disabled = { dataSourceConfig . readOnly }
/ >
< / Inline Field>
< / Field >
< Inline Field
label = { t ( 'grafana-ui.data-source-http-settings.with-credential-label' , 'With Credentials ' ) }
tooltip = { t (
'grafana-ui.data-source-http-settings.with-credential-tooltip ' ,
'Whether credentials such as cookies or auth headers should be sent with cross-site requests. '
< Field
label = { t ( 'grafana-ui.data-source-http-settings.timeout-label' , 'Timeout ' ) }
description = { t (
'grafana-ui.data-source-http-settings.timeout-description ' ,
'HTTP request timeout in seconds '
) }
labelWidth = { LABEL_WIDTH }
disabled = { dataSourceConfig . readOnly }
>
< InlineSwitch
id = "http-settings-with-credentials"
value = { dataSourceConfig . withCredentials }
< Input
type = "number"
width = { 40 }
placeholder = { t ( 'grafana-ui.data-source-http-settings.timeout-placeholder' , 'Timeout in seconds' ) }
value = { dataSourceConfig . jsonData . timeout }
onChange = { ( event ) = > {
onSettingsChange ( { withCredentials : event ! . currentTarget . checked } ) ;
onSettingsChange ( {
jsonData : { . . . dataSourceConfig . jsonData , timeout : parseInt ( event . currentTarget . value , 10 ) } ,
} ) ;
} }
/ >
< / InlineField >
< / div >
< / Field >
< / >
) }
< / section >
{ azureAuthSettings ? . azureAuthSupported && (
< div className = "gf-form-inline" >
< section >
< h3 className = "page-heading" >
< Trans i18nKey = "grafana-ui.data-source-http-settings.auth" > Auth < / Trans >
< / h3 >
< Stack direction = "column" gap = { 4 } >
< div >
< div className = { gridLayout } >
< InlineField
label = { t ( 'grafana-ui.data-source-http-settings.azure-auth-label' , 'Azure Authentication' ) }
tooltip = { t (
'grafana-ui.data-source-http-settings.azure-auth-tooltip' ,
'Use Azure authentication for Azure endpoint.'
) }
label = { t ( 'grafana-ui.data-source-http-settings.basic-auth-label' , 'Basic auth' ) }
labelWidth = { LABEL_WIDTH }
disabled = { dataSourceConfig . readOnly }
>
< InlineSwitch
id = "http-settings-azure -auth"
value = { azureAuthEnabled }
id = "http-settings-basic -auth"
value = { dataSourceConfig . basicAuth }
onChange = { ( event ) = > {
onSettingsChange (
azureAuthSettings . setAzureAuthEnabled ( dataSourceConfig , event ! . currentTarget . checked )
) ;
onSettingsChange ( { basicAuth : event ! . currentTarget . checked } ) ;
} }
/ >
< / InlineField >
< / div >
) }
{ sigV4AuthToggleEnabled && (
< div className = "gf-form-inline" >
< InlineField
// eslint-disable-next-line @grafana/no-untranslated-strings
label = "SigV4 auth"
label = { t ( 'grafana-ui.data-source-http-settings.with-credentials-label' , 'With Credentials' ) }
tooltip = { t (
'grafana-ui.data-source-http-settings.with-credentials-tooltip' ,
'Whether credentials such as cookies or auth headers should be sent with cross-site requests.'
) }
labelWidth = { LABEL_WIDTH }
disabled = { dataSourceConfig . readOnly }
>
< InlineSwitch
id = "http-settings-sigv4-auth "
value = { dataSourceConfig . jsonData . sigV4Auth || false }
id = "http-settings-with-credentials "
value = { dataSourceConfig . withCredentials }
onChange = { ( event ) = > {
onSettingsChange ( {
jsonData : { . . . dataSourceConfig . jsonData , sigV4Auth : event ! . currentTarget . checked } ,
} ) ;
onSettingsChange ( { withCredentials : event ! . currentTarget . checked } ) ;
} }
/ >
< / InlineField >
{ azureAuthSettings ? . azureAuthSupported && (
< InlineField
label = { t ( 'grafana-ui.data-source-http-settings.azure-auth-label' , 'Azure Authentication' ) }
tooltip = { t (
'grafana-ui.data-source-http-settings.azure-auth-tooltip' ,
'Use Azure authentication for Azure endpoint.'
) }
labelWidth = { LABEL_WIDTH }
disabled = { dataSourceConfig . readOnly }
>
< InlineSwitch
id = "http-settings-azure-auth"
value = { azureAuthEnabled }
onChange = { ( event ) = > {
onSettingsChange (
azureAuthSettings . setAzureAuthEnabled ( dataSourceConfig , event ! . currentTarget . checked )
) ;
} }
/ >
< / InlineField >
) }
{ sigV4AuthToggleEnabled && (
< InlineField
label = { t ( 'grafana-ui.data-source-http-settings.sigv4-auth-label' , 'SigV4 auth' ) }
labelWidth = { LABEL_WIDTH }
disabled = { dataSourceConfig . readOnly }
>
< InlineSwitch
id = "http-settings-sigv4-auth"
value = { dataSourceConfig . jsonData . sigV4Auth || false }
onChange = { ( event ) = > {
onSettingsChange ( {
jsonData : { . . . dataSourceConfig . jsonData , sigV4Auth : event ! . currentTarget . checked } ,
} ) ;
} }
/ >
< / InlineField >
) }
< / div >
) }
{ dataSourceConfig . access === 'proxy' && (
< HttpProxySettings
dataSourceConfig = { dataSourceConfig }
onChange = { ( jsonData ) = > onSettingsChange ( { jsonData } ) }
showForwardOAuthIdentityOption = { azureAuthEnabled ? false : showForwardOAuthIdentityOption }
/ >
) }
< / div >
{ dataSourceConfig . basicAuth && (
< >
< h6 >
< Trans i18nKey = "grafana-ui.data-source-http-settings.basic-auth" > Basic Auth Details < / Trans >
< / h6 >
< div className = "gf-form-group" >
{ dataSourceConfig . access === 'proxy' && (
< HttpProxySettings
dataSourceConfig = { dataSourceConfig }
onChange = { ( jsonData ) = > onSettingsChange ( { jsonData } ) }
showForwardOAuthIdentityOption = { azureAuthEnabled ? false : showForwardOAuthIdentityOption }
/ >
) }
< / div >
{ dataSourceConfig . basicAuth && (
< section >
< Text variant = "h6" element = "h4" >
< Trans i18nKey = "grafana-ui.data-source-http-settings.basic-auth" > Basic Auth Details < / Trans >
< / Text >
< BasicAuthSettings { ...props } / >
< / div >
< / >
) }
< / section >
) }
{ azureAuthSettings ? . azureAuthSupported && azureAuthEnabled && azureAuthSettings . azureSettingsUI && (
< azureAuthSettings.azureSettingsUI dataSourceConfig = { dataSourceConfig } onChange = { onChange } / >
) }
{ azureAuthSettings ? . azureAuthSupported && azureAuthEnabled && azureAuthSettings . azureSettingsUI && (
< azureAuthSettings.azureSettingsUI dataSourceConfig = { dataSourceConfig } onChange = { onChange } / >
) }
{ dataSourceConfig . jsonData . sigV4Auth && sigV4AuthToggleEnabled && renderSigV4Editor }
{ ( dataSourceConfig . jsonData . tlsAuth || dataSourceConfig . jsonData . tlsAuthWithCACert ) && (
< TLSAuthSettings dataSourceConfig = { dataSourceConfig } onChange = { onChange } / >
) }
{ dataSourceConfig . jsonData . sigV4Auth && sigV4AuthToggleEnabled && renderSigV4Editor }
{ ( dataSourceConfig . jsonData . tlsAuth || dataSourceConfig . jsonData . tlsAuthWithCACert ) && (
< TLSAuthSettings dataSourceConfig = { dataSourceConfig } onChange = { onChange } / >
) }
{ dataSourceConfig . access === 'proxy' && (
< CustomHeadersSettings dataSourceConfig = { dataSourceConfig } onChange = { onChange } / >
) }
< / >
{ dataSourceConfig . access === 'proxy' && (
< CustomHeadersSettings dataSourceConfig = { dataSourceConfig } onChange = { onChange } / >
) }
< / Stack >
< / section >
{ secureSocksDSProxyEnabled && < SecureSocksProxySettings options = { dataSourceConfig } onOptionsChange = { onChange } / > }
< / div >
< / Stack >
) ;
} ;