@ -4,7 +4,7 @@ import { Controller, FormProvider, useForm } from 'react-hook-form';
import { connect } from 'react-redux' ;
import { AppEvents , GrafanaTheme2 , NavModelItem } from '@grafana/data' ;
import { getBackendSrv , getAppEvents } from '@grafana/runtime' ;
import { getBackendSrv , getAppEvents , reportInteraction } from '@grafana/runtime' ;
import {
useStyles2 ,
Alert ,
@ -15,12 +15,14 @@ import {
Input ,
LinkButton ,
Menu ,
Modal ,
Stack ,
Text ,
TextLink ,
Dropdown ,
MultiSelect ,
} from '@grafana/ui' ;
import { FormPrompt } from 'app/core/components/FormPrompt/FormPrompt' ;
import { Page } from 'app/core/components/Page/Page' ;
import config from 'app/core/config' ;
import { t , Trans } from 'app/core/internationalization' ;
@ -94,6 +96,7 @@ const emptySettings: LdapPayload = {
export const LdapSettingsPage = ( ) = > {
const [ isLoading , setIsLoading ] = useState ( true ) ;
const [ isDrawerOpen , setIsDrawerOpen ] = useState ( false ) ;
const [ isModalOpen , setIsModalOpen ] = useState ( false ) ;
const [ mapKeyCertConfigured , setMapKeyCertConfigured ] = useState < MapKeyCertConfigured > ( {
// values
@ -107,14 +110,25 @@ export const LdapSettingsPage = () => {
} ) ;
const methods = useForm < LdapPayload > ( { defaultValues : emptySettings } ) ;
const { control , getValues , handleSubmit , register , reset , watch } = methods ;
const {
control ,
formState : { isDirty } ,
getValues ,
handleSubmit ,
register ,
reset ,
watch ,
} = methods ;
const styles = useStyles2 ( getStyles ) ;
useEffect ( ( ) = > {
async function init() {
const payload = await getSettings ( ) ;
const serverConfig = payload . settings . config . servers [ 0 ] ;
let serverConfig = emptySettings . settings . config . servers [ 0 ] ;
if ( payload . settings . config . servers ? . length > 0 ) {
serverConfig = payload . settings . config . servers [ 0 ] ;
}
setMapKeyCertConfigured ( {
rootCaCertValue : serverConfig.root_ca_cert_value?.length > 0 ,
clientCertValue : serverConfig.client_cert_value !== '' ,
@ -203,12 +217,14 @@ export const LdapSettingsPage = () => {
/ * *
* Button ' s Actions
* /
const submitAndEnableLdapSettings = ( payload : LdapPayload ) = > {
const submitAndEnableLdapSettings = async ( payload : LdapPayload ) = > {
payload . settings . enabled = true ;
putPayload ( payload ) ;
await putPayload ( payload ) ;
reportInteraction ( 'authentication_ldap_enabled' ) ;
} ;
const saveForm = ( ) = > {
putPayload ( getValues ( ) ) ;
const saveForm = async ( ) = > {
await putPayload ( getValues ( ) ) ;
reportInteraction ( 'authentication_ldap_saved' ) ;
} ;
const deleteLDAPConfig = async ( ) = > {
try {
@ -220,6 +236,7 @@ export const LdapSettingsPage = () => {
payload : [ t ( 'ldap-settings-page.alert.discard-success' , 'LDAP settings discarded' ) ] ,
} ) ;
reset ( payload ) ;
reportInteraction ( 'authentication_ldap_deleted' ) ;
} catch ( error ) {
appEvents . publish ( {
type : AppEvents . alertError . name ,
@ -230,6 +247,10 @@ export const LdapSettingsPage = () => {
}
} ;
const onDiscard = ( ) = > {
reportInteraction ( 'authentication_ldap_abandoned' ) ;
} ;
const subTitle = (
< Trans i18nKey = "ldap-settings-page.subtitle" >
The LDAP integration in Grafana allows your Grafana users to log in with their LDAP credentials . Find out more in
@ -259,6 +280,7 @@ export const LdapSettingsPage = () => {
{ config . disableLoginForm && disabledFormAlert }
< FormProvider { ...methods } >
< form onSubmit = { handleSubmit ( submitAndEnableLdapSettings , onErrors ) } >
< FormPrompt confirmRedirect = { isDirty } onDiscard = { onDiscard } / >
{ isLoading && < Loader / > }
{ ! isLoading && (
< section className = { styles . form } >
@ -266,7 +288,7 @@ export const LdapSettingsPage = () => {
< Trans i18nKey = "ldap-settings-page.title" > Basic Settings < / Trans >
< / h3 >
< Field
label = { t ( 'ldap-settings-page.host.label' , 'Server host' ) }
label = { t ( 'ldap-settings-page.host.label' , 'Server host * ' ) }
description = { t (
'ldap-settings-page.host.description' ,
'Hostname or IP address of the LDAP server you wish to connect to.'
@ -301,7 +323,7 @@ export const LdapSettingsPage = () => {
/ >
< / Field >
< Field
label = { t ( 'ldap-settings-page.search_filter.label' , 'Search filter*' ) }
label = { t ( 'ldap-settings-page.search_filter.label' , 'Search filter *' ) }
description = { t (
'ldap-settings-page.search_filter.description' ,
'LDAP search filter used to locate specific entries within the directory.'
@ -324,10 +346,12 @@ export const LdapSettingsPage = () => {
< Controller
name = { ` ${ serverConfig } .search_base_dns ` }
control = { control }
render = { ( { field : { onChange , . . . field } } ) = > (
render = { ( { field : { onChange , ref , . . . field } } ) = > (
< MultiSelect
{ . . . field }
allowCustomValue
className = { styles . multiSelect }
noOptionsMessage = { '' }
onChange = { ( v ) = > onChange ( v . map ( ( { value } ) = > String ( value ) ) ) }
/ >
) }
@ -346,20 +370,20 @@ export const LdapSettingsPage = () => {
< / Text >
< / Stack >
< Button variant = "secondary" onClick = { ( ) = > setIsDrawerOpen ( true ) } >
< Trans i18nKey = "ldap-settings-page.advanced-settings-section.edit. button" > Edit < / Trans >
< Trans i18nKey = "ldap-settings-page.advanced-settings-section.edit- button" > Edit < / Trans >
< / Button >
< / Stack >
< / Box >
< Box display = "flex" gap = { 2 } marginTop = { 5 } >
< Stack alignItems = "center" gap = { 2 } >
< Button type = "submit" >
< Trans i18nKey = "ldap-settings-page.buttons-section.save-and-enable. button" > Save and enable < / Trans >
< Trans i18nKey = "ldap-settings-page.buttons-section.save-and-enable- button" > Save and enable < / Trans >
< / Button >
< Button variant = "secondary" onClick = { saveForm } >
< Trans i18nKey = "ldap-settings-page.buttons-section.save. button" > Save < / Trans >
< Trans i18nKey = "ldap-settings-page.buttons-section.save- button" > Save < / Trans >
< / Button >
< LinkButton href = "/admin/authentication" variant = "secondary" >
< Trans i18nKey = "ldap-settings-page.buttons-section.discard. button" > Discard < / Trans >
< Trans i18nKey = "ldap-settings-page.buttons-section.discard- button" > Discard < / Trans >
< / LinkButton >
< Dropdown
overlay = {
@ -392,6 +416,26 @@ export const LdapSettingsPage = () => {
< / form >
< / FormProvider >
< / Page.Contents >
< Modal
title = { t ( 'ldap-settings-page.discard-modal.title' , 'Leave LDAP configuration?' ) }
isOpen = { isModalOpen }
onDismiss = { ( ) = > setIsModalOpen ( false ) }
>
< Stack direction = { 'column' } gap = { 2 } >
< Trans i18nKey = "ldap-settings-page.discard-modal.description" >
Are you sure you want to abandon the changes you & lsquo ; ve made to the LDAP configuration ? All changes will
be lost .
< / Trans >
< Stack direction = "row" gap = { 2 } justifyContent = "flex-end" >
< Button variant = "secondary" >
< Trans i18nKey = "ldap-settings-page.discard-modal.cancel-button" > Back to editing < / Trans >
< / Button >
< Button variant = "destructive" >
< Trans i18nKey = "ldap-settings-page.discard-modal.discard-button" > Abandon LDAP < / Trans >
< / Button >
< / Stack >
< / Stack >
< / Modal >
< / Page >
) ;
} ;
@ -401,6 +445,11 @@ function getStyles(theme: GrafanaTheme2) {
form : css ( {
width : theme.spacing ( 68 ) ,
} ) ,
multiSelect : css ( {
svg : {
display : 'none' ,
} ,
} ) ,
} ;
}