diff --git a/public/app/features/admin/ldap/LdapDrawer.tsx b/public/app/features/admin/ldap/LdapDrawer.tsx index 42b3abdc660..caa5edefa1f 100644 --- a/public/app/features/admin/ldap/LdapDrawer.tsx +++ b/public/app/features/admin/ldap/LdapDrawer.tsx @@ -60,7 +60,7 @@ export const LdapDrawerComponent = ({ useEffect(() => { const { client_cert, client_key, root_ca_cert } = getValues(serverConfig); setEncryptionProvider( - !client_cert.length && !client_key.length && !root_ca_cert?.length + !client_cert?.length && !client_key?.length && !root_ca_cert?.length ? EncryptionProvider.Base64 : EncryptionProvider.FilePath ); @@ -83,19 +83,21 @@ export const LdapDrawerComponent = ({ ); const useTlsDescription = ( - - For a complete list of supported ciphers and TLS versions, refer to:{' '} - { - - https://go.dev/src/crypto/tls/cipher_suites.go - - } - + <> + + For a complete list of supported ciphers and TLS versions, refer to: + {' '} + {/* eslint-disable-next-line @grafana/no-untranslated-strings */} + + https://go.dev/src/crypto/tls/cipher_suites.go + + ); const onAddGroupMapping = () => { + const groupMappings = getValues(`${serverConfig}.group_mappings`) || []; setValue(`${serverConfig}.group_mappings`, [ - ...getValues(`${serverConfig}.group_mappings`), + ...groupMappings, { group_dn: '', org_id: 1, @@ -338,10 +340,12 @@ export const LdapDrawerComponent = ({ ( + render={({ field: { onChange, ref, value, ...field } }) => ( onChange(v.map(({ value }) => String(value)))} value={value?.map((v) => ({ label: renderMultiSelectLabel(v), value: v }))} /> @@ -447,5 +451,10 @@ function getStyles(theme: GrafanaTheme2) { button: css({ marginBottom: theme.spacing(4), }), + multiSelect: css({ + svg: { + display: 'none', + }, + }), }; } diff --git a/public/app/features/admin/ldap/LdapSettingsPage.tsx b/public/app/features/admin/ldap/LdapSettingsPage.tsx index 7b7335cc649..736a40a76c5 100644 --- a/public/app/features/admin/ldap/LdapSettingsPage.tsx +++ b/public/app/features/admin/ldap/LdapSettingsPage.tsx @@ -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({ // values @@ -107,14 +110,25 @@ export const LdapSettingsPage = () => { }); const methods = useForm({ 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 = ( 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}
+ {isLoading && } {!isLoading && (
@@ -266,7 +288,7 @@ export const LdapSettingsPage = () => { Basic Settings { /> { ( + render={({ field: { onChange, ref, ...field } }) => ( onChange(v.map(({ value }) => String(value)))} /> )} @@ -346,20 +370,20 @@ export const LdapSettingsPage = () => { - Discard + Discard { + setIsModalOpen(false)} + > + + + Are you sure you want to abandon the changes you‘ve made to the LDAP configuration? All changes will + be lost. + + + + + + + ); }; @@ -401,6 +445,11 @@ function getStyles(theme: GrafanaTheme2) { form: css({ width: theme.spacing(68), }), + multiSelect: css({ + svg: { + display: 'none', + }, + }), }; } diff --git a/public/app/features/auth-config/AuthProvidersListPage.tsx b/public/app/features/auth-config/AuthProvidersListPage.tsx index 560c1a3a79a..717906f0f3a 100644 --- a/public/app/features/auth-config/AuthProvidersListPage.tsx +++ b/public/app/features/auth-config/AuthProvidersListPage.tsx @@ -57,7 +57,13 @@ export const AuthConfigPageUnconnected = ({ providers = providers.map((p) => { if (p.provider === 'ldap') { - p.settings.type = p.provider; + return { + ...p, + settings: { + ...p.settings, + type: 'LDAP', + }, + }; } return p; }); diff --git a/public/locales/en-US/grafana.json b/public/locales/en-US/grafana.json index b20956af416..66dd73190d3 100644 --- a/public/locales/en-US/grafana.json +++ b/public/locales/en-US/grafana.json @@ -1091,7 +1091,7 @@ "tls-ciphers-placeholder": "e.g. [\"TLS_AES_256_GCM_SHA384\"]", "use-ssl-description": "Set to true if LDAP server should use TLS connection (either with STARTTLS or LDAPS)", "use-ssl-label": "Use SSL", - "use-ssl-tooltip": "For a complete list of supported ciphers and TLS versions, refer to: {\n \n https://go.dev/src/crypto/tls/cipher_suites.go\n }" + "use-ssl-tooltip": "For a complete list of supported ciphers and TLS versions, refer to:" }, "group-mapping": { "grafana-admin": { @@ -1141,9 +1141,7 @@ }, "ldap-settings-page": { "advanced-settings-section": { - "edit": { - "button": "Edit" - }, + "edit-button": "Edit", "subtitle": "Mappings, extra security measures, and more.", "title": "Advanced Settings" }, @@ -1164,20 +1162,20 @@ "label": "Bind password" }, "buttons-section": { - "discard": { - "button": "Discard" - }, - "save": { - "button": "Save" - }, - "save-and-enable": { - "button": "Save and enable" - } + "discard-button": "Discard", + "save-and-enable-button": "Save and enable", + "save-button": "Save" + }, + "discard-modal": { + "cancel-button": "Back to editing", + "description": "Are you sure you want to abandon the changes you‘ve made to the LDAP configuration? All changes will be lost.", + "discard-button": "Abandon LDAP", + "title": "Leave LDAP configuration?" }, "documentation": "documentation", "host": { "description": "Hostname or IP address of the LDAP server you wish to connect to.", - "label": "Server host", + "label": "Server host *", "placeholder": "example: 127.0.0.1" }, "login-form-alert": { @@ -1186,7 +1184,7 @@ }, "search_filter": { "description": "LDAP search filter used to locate specific entries within the directory.", - "label": "Search filter*", + "label": "Search filter *", "placeholder": "example: cn=%s" }, "search-base-dns": { diff --git a/public/locales/pseudo-LOCALE/grafana.json b/public/locales/pseudo-LOCALE/grafana.json index 8ac07e0c62d..9cb08bd3fc4 100644 --- a/public/locales/pseudo-LOCALE/grafana.json +++ b/public/locales/pseudo-LOCALE/grafana.json @@ -1091,7 +1091,7 @@ "tls-ciphers-placeholder": "ę.ģ. [\"ŦĿŜ_ÅĒŜ_256_ĞCM_ŜĦÅ384\"]", "use-ssl-description": "Ŝęŧ ŧő ŧřūę įƒ ĿĐÅP şęřvęř şĥőūľđ ūşę ŦĿŜ čőʼnʼnęčŧįőʼn (ęįŧĥęř ŵįŧĥ ŜŦÅŖŦŦĿŜ őř ĿĐÅPŜ)", "use-ssl-label": "Ůşę ŜŜĿ", - "use-ssl-tooltip": "Főř ä čőmpľęŧę ľįşŧ őƒ şūppőřŧęđ čįpĥęřş äʼnđ ŦĿŜ vęřşįőʼnş, řęƒęř ŧő: {\n <ŦęχŧĿįʼnĸ şŧyľę={{ fontSize: 'inherit' }} ĥřęƒ=\"ĥŧŧpş://ģő.đęv/şřč/čřypŧő/ŧľş/čįpĥęř_şūįŧęş.ģő\" ęχŧęřʼnäľ>\n ĥŧŧpş://ģő.đęv/şřč/čřypŧő/ŧľş/čįpĥęř_şūįŧęş.ģő\n }" + "use-ssl-tooltip": "Főř ä čőmpľęŧę ľįşŧ őƒ şūppőřŧęđ čįpĥęřş äʼnđ ŦĿŜ vęřşįőʼnş, řęƒęř ŧő:" }, "group-mapping": { "grafana-admin": { @@ -1141,9 +1141,7 @@ }, "ldap-settings-page": { "advanced-settings-section": { - "edit": { - "button": "Ēđįŧ" - }, + "edit-button": "Ēđįŧ", "subtitle": "Mäppįʼnģş, ęχŧřä şęčūřįŧy męäşūřęş, äʼnđ mőřę.", "title": "Åđväʼnčęđ Ŝęŧŧįʼnģş" }, @@ -1164,20 +1162,20 @@ "label": "ßįʼnđ päşşŵőřđ" }, "buttons-section": { - "discard": { - "button": "Đįşčäřđ" - }, - "save": { - "button": "Ŝävę" - }, - "save-and-enable": { - "button": "Ŝävę äʼnđ ęʼnäþľę" - } + "discard-button": "Đįşčäřđ", + "save-and-enable-button": "Ŝävę äʼnđ ęʼnäþľę", + "save-button": "Ŝävę" + }, + "discard-modal": { + "cancel-button": "ßäčĸ ŧő ęđįŧįʼnģ", + "description": "Åřę yőū şūřę yőū ŵäʼnŧ ŧő äþäʼnđőʼn ŧĥę čĥäʼnģęş yőū&ľşqūő;vę mäđę ŧő ŧĥę ĿĐÅP čőʼnƒįģūřäŧįőʼn? Åľľ čĥäʼnģęş ŵįľľ þę ľőşŧ.", + "discard-button": "Åþäʼnđőʼn ĿĐÅP", + "title": "Ŀęävę ĿĐÅP čőʼnƒįģūřäŧįőʼn?" }, "documentation": "đőčūmęʼnŧäŧįőʼn", "host": { "description": "Ħőşŧʼnämę őř ĨP äđđřęşş őƒ ŧĥę ĿĐÅP şęřvęř yőū ŵįşĥ ŧő čőʼnʼnęčŧ ŧő.", - "label": "Ŝęřvęř ĥőşŧ", + "label": "Ŝęřvęř ĥőşŧ *", "placeholder": "ęχämpľę: 127.0.0.1" }, "login-form-alert": { @@ -1186,7 +1184,7 @@ }, "search_filter": { "description": "ĿĐÅP şęäřčĥ ƒįľŧęř ūşęđ ŧő ľőčäŧę şpęčįƒįč ęʼnŧřįęş ŵįŧĥįʼn ŧĥę đįřęčŧőřy.", - "label": "Ŝęäřčĥ ƒįľŧęř*", + "label": "Ŝęäřčĥ ƒįľŧęř *", "placeholder": "ęχämpľę: čʼn=%ş" }, "search-base-dns": {