1import React, { PureComponent } from 'react'; 2import { connect, ConnectedProps } from 'react-redux'; 3import { NavModel } from '@grafana/data'; 4import { Alert, Button, LegacyForms } from '@grafana/ui'; 5const { FormField } = LegacyForms; 6import { getNavModel } from 'app/core/selectors/navModel'; 7import config from 'app/core/config'; 8import Page from 'app/core/components/Page/Page'; 9import { LdapConnectionStatus } from './LdapConnectionStatus'; 10import { LdapSyncInfo } from './LdapSyncInfo'; 11import { LdapUserInfo } from './LdapUserInfo'; 12import { 13 AppNotificationSeverity, 14 LdapError, 15 LdapUser, 16 StoreState, 17 SyncInfo, 18 LdapConnectionInfo, 19 AccessControlAction, 20} from 'app/types'; 21import { 22 loadLdapState, 23 loadLdapSyncStatus, 24 loadUserMapping, 25 clearUserError, 26 clearUserMappingInfo, 27} from '../state/actions'; 28import { GrafanaRouteComponentProps } from 'app/core/navigation/types'; 29import { contextSrv } from 'app/core/core'; 30 31interface OwnProps extends GrafanaRouteComponentProps<{}, { username?: string }> { 32 navModel: NavModel; 33 ldapConnectionInfo: LdapConnectionInfo; 34 ldapUser?: LdapUser; 35 ldapSyncInfo?: SyncInfo; 36 ldapError?: LdapError; 37 userError?: LdapError; 38} 39 40interface State { 41 isLoading: boolean; 42} 43 44export class LdapPage extends PureComponent<Props, State> { 45 state = { 46 isLoading: true, 47 }; 48 49 async componentDidMount() { 50 const { clearUserMappingInfo, queryParams } = this.props; 51 await clearUserMappingInfo(); 52 await this.fetchLDAPStatus(); 53 54 if (queryParams.username) { 55 await this.fetchUserMapping(queryParams.username); 56 } 57 58 this.setState({ isLoading: false }); 59 } 60 61 async fetchLDAPStatus() { 62 const { loadLdapState, loadLdapSyncStatus } = this.props; 63 return Promise.all([loadLdapState(), loadLdapSyncStatus()]); 64 } 65 66 async fetchUserMapping(username: string) { 67 const { loadUserMapping } = this.props; 68 return await loadUserMapping(username); 69 } 70 71 search = (event: any) => { 72 event.preventDefault(); 73 const username = event.target.elements['username'].value; 74 if (username) { 75 this.fetchUserMapping(username); 76 } 77 }; 78 79 onClearUserError = () => { 80 this.props.clearUserError(); 81 }; 82 83 render() { 84 const { ldapUser, userError, ldapError, ldapSyncInfo, ldapConnectionInfo, navModel, queryParams } = this.props; 85 const { isLoading } = this.state; 86 const canReadLDAPUser = contextSrv.hasPermission(AccessControlAction.LDAPUsersRead); 87 88 return ( 89 <Page navModel={navModel}> 90 <Page.Contents isLoading={isLoading}> 91 <> 92 {ldapError && ldapError.title && ( 93 <div className="gf-form-group"> 94 <Alert title={ldapError.title} severity={AppNotificationSeverity.Error}> 95 {ldapError.body} 96 </Alert> 97 </div> 98 )} 99 100 <LdapConnectionStatus ldapConnectionInfo={ldapConnectionInfo} /> 101 102 {config.licenseInfo.hasLicense && ldapSyncInfo && <LdapSyncInfo ldapSyncInfo={ldapSyncInfo} />} 103 104 {canReadLDAPUser && ( 105 <> 106 <h3 className="page-heading">Test user mapping</h3> 107 <div className="gf-form-group"> 108 <form onSubmit={this.search} className="gf-form-inline"> 109 <FormField 110 label="Username" 111 labelWidth={8} 112 inputWidth={30} 113 type="text" 114 id="username" 115 name="username" 116 defaultValue={queryParams.username} 117 /> 118 <Button type="submit">Run</Button> 119 </form> 120 </div> 121 {userError && userError.title && ( 122 <div className="gf-form-group"> 123 <Alert 124 title={userError.title} 125 severity={AppNotificationSeverity.Error} 126 onRemove={this.onClearUserError} 127 > 128 {userError.body} 129 </Alert> 130 </div> 131 )} 132 {ldapUser && <LdapUserInfo ldapUser={ldapUser} showAttributeMapping={true} />} 133 </> 134 )} 135 </> 136 </Page.Contents> 137 </Page> 138 ); 139 } 140} 141 142const mapStateToProps = (state: StoreState) => ({ 143 navModel: getNavModel(state.navIndex, 'ldap'), 144 ldapConnectionInfo: state.ldap.connectionInfo, 145 ldapUser: state.ldap.user, 146 ldapSyncInfo: state.ldap.syncInfo, 147 userError: state.ldap.userError, 148 ldapError: state.ldap.ldapError, 149}); 150 151const mapDispatchToProps = { 152 loadLdapState, 153 loadLdapSyncStatus, 154 loadUserMapping, 155 clearUserError, 156 clearUserMappingInfo, 157}; 158 159const connector = connect(mapStateToProps, mapDispatchToProps); 160type Props = OwnProps & ConnectedProps<typeof connector>; 161 162export default connector(LdapPage); 163