Auth Drawer: Use redux store to load settings (#85110)

* use actions instead of importing the backend service

* Replace the test render for redux-rtl
This commit is contained in:
linoman
2024-03-26 07:56:31 -06:00
committed by GitHub
parent da1ef0e1fa
commit 4e5bff0ada
4 changed files with 64 additions and 38 deletions

View File

@@ -1,17 +1,21 @@
import { render, screen } from '@testing-library/react'; import { screen } from '@testing-library/react';
import React from 'react'; import React from 'react';
import { render } from 'test/redux-rtl';
import { AuthDrawer, Props } from './AuthDrawer'; import { AuthDrawerUnconnected, Props } from './AuthDrawer';
const defaultProps: Props = { const defaultProps: Props = {
onClose: jest.fn(), onClose: jest.fn(),
allowInsecureEmail: false,
loadSettings: jest.fn(),
saveSettings: jest.fn(),
}; };
async function getTestContext(overrides: Partial<Props> = {}) { async function getTestContext(overrides: Partial<Props> = {}) {
jest.clearAllMocks(); jest.clearAllMocks();
const props = { ...defaultProps, ...overrides }; const props = { ...defaultProps, ...overrides };
const { rerender } = render(<AuthDrawer {...props} />); const { rerender } = render(<AuthDrawerUnconnected {...props} />);
return { rerender, props }; return { rerender, props };
} }

View File

@@ -1,53 +1,71 @@
import { css } from '@emotion/css'; import { css } from '@emotion/css';
import React, { useState } from 'react'; import React, { JSX } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { GrafanaTheme2 } from '@grafana/data'; import { GrafanaTheme2 } from '@grafana/data';
import { getBackendSrv } from '@grafana/runtime';
import { Button, Drawer, Text, TextLink, Switch, useStyles2 } from '@grafana/ui'; import { Button, Drawer, Text, TextLink, Switch, useStyles2 } from '@grafana/ui';
import { useAppNotification } from 'app/core/copy/appNotification';
import { StoreState } from 'app/types';
export interface Props { import { loadSettings, saveSettings } from './state/actions';
interface OwnProps {
onClose: () => void; onClose: () => void;
} }
const SETTINGS_URL = '/api/admin/settings'; export type Props = OwnProps & ConnectedProps<typeof connector>;
export const AuthDrawer = ({ onClose }: Props) => { const mapStateToProps = (state: StoreState) => {
const [isOauthAllowInsecureEmailLookup, setOauthAllowInsecureEmailLookup] = useState(false); const allowInsecureEmail =
state.authConfig.settings?.auth?.oauth_allow_insecure_email_lookup.toLowerCase() === 'true';
const getSettings = async () => { return {
try { allowInsecureEmail,
const response = await getBackendSrv().get(SETTINGS_URL);
setOauthAllowInsecureEmailLookup(response.auth.oauth_allow_insecure_email_lookup?.toLowerCase?.() === 'true');
} catch (error) {}
}; };
const updateSettings = async (property: boolean) => { };
const mapActionsToProps = {
loadSettings,
saveSettings,
};
const connector = connect(mapStateToProps, mapActionsToProps);
export const AuthDrawerUnconnected = ({
allowInsecureEmail,
loadSettings,
onClose,
saveSettings,
}: Props): JSX.Element => {
const notifyApp = useAppNotification();
const oauthAllowInsecureEmailLookupOnChange = async () => {
try { try {
const body = { await saveSettings({
updates: { updates: {
auth: { auth: {
oauth_allow_insecure_email_lookup: '' + property, oauth_allow_insecure_email_lookup: '' + !allowInsecureEmail,
}, },
}, },
}; });
await getBackendSrv().put(SETTINGS_URL, body); await loadSettings(false);
} catch (error) {} notifyApp.success('Settings saved');
} catch (error) {
notifyApp.error('Failed to save settings');
}
}; };
const resetButtonOnClick = async () => { const resetButtonOnClick = async () => {
try { try {
const body = { await saveSettings({
removals: { removals: {
auth: ['oauth_allow_insecure_email_lookup'], auth: ['oauth_allow_insecure_email_lookup'],
}, },
}; });
await getBackendSrv().put(SETTINGS_URL, body); await loadSettings(false);
getSettings(); notifyApp.success('Settings saved');
} catch (error) {} } catch (error) {
}; notifyApp.error('Failed to save settings');
}
const oauthAllowInsecureEmailLookupOnChange = async () => {
updateSettings(!isOauthAllowInsecureEmailLookup);
setOauthAllowInsecureEmailLookup(!isOauthAllowInsecureEmailLookup);
}; };
const subtitle = ( const subtitle = (
@@ -65,8 +83,6 @@ export const AuthDrawer = ({ onClose }: Props) => {
const styles = useStyles2(getStyles); const styles = useStyles2(getStyles);
getSettings();
return ( return (
<Drawer title="Auth Settings" subtitle={subtitle} size="md" onClose={onClose}> <Drawer title="Auth Settings" subtitle={subtitle} size="md" onClose={onClose}>
<div className={styles.advancedAuth}> <div className={styles.advancedAuth}>
@@ -75,7 +91,7 @@ export const AuthDrawer = ({ onClose }: Props) => {
<Text variant="body" color="secondary"> <Text variant="body" color="secondary">
Allow users to use the same email address to log into Grafana with different identity providers. Allow users to use the same email address to log into Grafana with different identity providers.
</Text> </Text>
<Switch value={isOauthAllowInsecureEmailLookup} onChange={oauthAllowInsecureEmailLookupOnChange} /> <Switch value={allowInsecureEmail} onChange={oauthAllowInsecureEmailLookupOnChange} />
</div> </div>
<Button <Button
size="md" size="md"
@@ -90,6 +106,8 @@ export const AuthDrawer = ({ onClose }: Props) => {
); );
}; };
export default connector(AuthDrawerUnconnected);
const getStyles = (theme: GrafanaTheme2) => { const getStyles = (theme: GrafanaTheme2) => {
return { return {
advancedAuth: css({ advancedAuth: css({

View File

@@ -8,7 +8,7 @@ import { Page } from 'app/core/components/Page/Page';
import { config } from 'app/core/config'; import { config } from 'app/core/config';
import { StoreState } from 'app/types'; import { StoreState } from 'app/types';
import { AuthDrawer } from './AuthDrawer'; import AuthDrawer from './AuthDrawer';
import ConfigureAuthCTA from './components/ConfigureAuthCTA'; import ConfigureAuthCTA from './components/ConfigureAuthCTA';
import { ProviderCard } from './components/ProviderCard'; import { ProviderCard } from './components/ProviderCard';
import { loadSettings } from './state/actions'; import { loadSettings } from './state/actions';

View File

@@ -17,15 +17,19 @@ import {
settingsUpdated, settingsUpdated,
} from './reducers'; } from './reducers';
export function loadSettings(): ThunkResult<Promise<Settings>> { export function loadSettings(showSpinner = true): ThunkResult<Promise<Settings>> {
return async (dispatch) => { return async (dispatch) => {
if (contextSrv.hasPermission(AccessControlAction.SettingsRead)) { if (contextSrv.hasPermission(AccessControlAction.SettingsRead)) {
dispatch(loadingBegin()); if (showSpinner) {
dispatch(loadingBegin());
}
dispatch(loadProviders()); dispatch(loadProviders());
const result = await getBackendSrv().get('/api/admin/settings'); const result = await getBackendSrv().get('/api/admin/settings');
dispatch(settingsUpdated(result)); dispatch(settingsUpdated(result));
await dispatch(loadProviderStatuses()); await dispatch(loadProviderStatuses());
dispatch(loadingEnd()); if (showSpinner) {
dispatch(loadingEnd());
}
return result; return result;
} }
}; };