mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
LDAP: Use InteractiveTable and remove gf-form usage (#80291)
* Use InteractiveTable * Remove unused return * Fix icon alignment * InteractiveTable in LdapUserMappingInfo * Update no teams text * InteractiveTable in LdapUserGroups * Remove unused code * Cleanup * LdapSyncInfo to InteractiveTable * Update more tables * Memoize * Fix connection status * Update lockfile * Refactor LdapSyncInfo * Fix lockfile * Remove showAttributeMapping as it is always true
This commit is contained in:
parent
5195e5347e
commit
add5a5c01e
@ -6718,35 +6718,6 @@ exports[`no gf-form usage`] = {
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/ldap/LdapConnectionStatus.tsx:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/ldap/LdapSyncInfo.tsx:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/ldap/LdapUserGroups.tsx:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/ldap/LdapUserInfo.tsx:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/ldap/LdapUserMappingInfo.tsx:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/ldap/LdapUserPermissions.tsx:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/ldap/LdapUserTeams.tsx:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||
],
|
||||
"public/app/features/admin/partials/edit_org.html:5381": [
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||
|
@ -1,48 +1,65 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Alert, Icon } from '@grafana/ui';
|
||||
import { Alert, CellProps, Column, Icon, InteractiveTable, Stack, Text, Tooltip } from '@grafana/ui';
|
||||
import { AppNotificationSeverity, LdapConnectionInfo, LdapServerInfo } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
ldapConnectionInfo: LdapConnectionInfo;
|
||||
}
|
||||
|
||||
interface ServerInfo {
|
||||
host: string;
|
||||
port: number;
|
||||
available: boolean;
|
||||
}
|
||||
|
||||
export const LdapConnectionStatus = ({ ldapConnectionInfo }: Props) => {
|
||||
const columns = useMemo<Array<Column<ServerInfo>>>(
|
||||
() => [
|
||||
{
|
||||
id: 'host',
|
||||
header: 'Host',
|
||||
disableGrow: true,
|
||||
},
|
||||
{
|
||||
id: 'port',
|
||||
header: 'Port',
|
||||
disableGrow: true,
|
||||
},
|
||||
{
|
||||
id: 'available',
|
||||
cell: (serverInfo: CellProps<ServerInfo>) => {
|
||||
return serverInfo.cell.value ? (
|
||||
<Stack justifyContent="end">
|
||||
<Tooltip content="Connection is available">
|
||||
<Icon name="check" className="pull-right" />
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
) : (
|
||||
<Stack justifyContent="end">
|
||||
<Tooltip content="Connection is not available">
|
||||
<Icon name="exclamation-triangle" />
|
||||
</Tooltip>
|
||||
</Stack>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const data = useMemo<ServerInfo[]>(() => ldapConnectionInfo, [ldapConnectionInfo]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">LDAP Connection</h3>
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<table className="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Host</th>
|
||||
<th colSpan={2}>Port</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{ldapConnectionInfo &&
|
||||
ldapConnectionInfo.map((serverInfo, index) => (
|
||||
<tr key={index}>
|
||||
<td>{serverInfo.host}</td>
|
||||
<td>{serverInfo.port}</td>
|
||||
<td>
|
||||
{serverInfo.available ? (
|
||||
<Icon name="check" className="pull-right" />
|
||||
) : (
|
||||
<Icon name="exclamation-triangle" className="pull-right" />
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="gf-form-group">
|
||||
<LdapErrorBox ldapConnectionInfo={ldapConnectionInfo} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
<section>
|
||||
<Stack direction="column" gap={2}>
|
||||
<Text color="primary" element="h3">
|
||||
LDAP Connection
|
||||
</Text>
|
||||
<InteractiveTable data={data} columns={columns} getRowId={(serverInfo) => serverInfo.host + serverInfo.port} />
|
||||
<LdapErrorBox ldapConnectionInfo={ldapConnectionInfo} />
|
||||
</Stack>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -3,7 +3,7 @@ import { connect, ConnectedProps } from 'react-redux';
|
||||
|
||||
import { NavModelItem } from '@grafana/data';
|
||||
import { featureEnabled } from '@grafana/runtime';
|
||||
import { Alert, Button, Field, Form, HorizontalGroup, Input } from '@grafana/ui';
|
||||
import { Alert, Button, Field, Form, Input, Stack } from '@grafana/ui';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
import { contextSrv } from 'app/core/core';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
@ -97,7 +97,7 @@ export class LdapPage extends PureComponent<Props, State> {
|
||||
return (
|
||||
<Page navId="authentication" pageNav={pageNav}>
|
||||
<Page.Contents isLoading={isLoading}>
|
||||
<>
|
||||
<Stack direction="column" gap={4}>
|
||||
{ldapError && ldapError.title && (
|
||||
<Alert title={ldapError.title} severity={AppNotificationSeverity.Error}>
|
||||
{ldapError.body}
|
||||
@ -109,23 +109,24 @@ export class LdapPage extends PureComponent<Props, State> {
|
||||
{featureEnabled('ldapsync') && ldapSyncInfo && <LdapSyncInfo ldapSyncInfo={ldapSyncInfo} />}
|
||||
|
||||
{canReadLDAPUser && (
|
||||
<>
|
||||
<section>
|
||||
<h3>Test user mapping</h3>
|
||||
<Form onSubmit={(data: FormModel) => this.search(data.username)}>
|
||||
{({ register }) => (
|
||||
<HorizontalGroup>
|
||||
<Field label="Username">
|
||||
<Input
|
||||
{...register('username', { required: true })}
|
||||
id="username"
|
||||
type="text"
|
||||
defaultValue={queryParams.username}
|
||||
/>
|
||||
</Field>
|
||||
<Button variant="primary" type="submit">
|
||||
Run
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
<Field label="Username">
|
||||
<Input
|
||||
{...register('username', { required: true })}
|
||||
width={34}
|
||||
id="username"
|
||||
type="text"
|
||||
defaultValue={queryParams.username}
|
||||
addonAfter={
|
||||
<Button variant="primary" type="submit">
|
||||
Run
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
</Form>
|
||||
{userError && userError.title && (
|
||||
@ -137,10 +138,10 @@ export class LdapPage extends PureComponent<Props, State> {
|
||||
{userError.body}
|
||||
</Alert>
|
||||
)}
|
||||
{ldapUser && <LdapUserInfo ldapUser={ldapUser} showAttributeMapping={true} />}
|
||||
</>
|
||||
{ldapUser && <LdapUserInfo ldapUser={ldapUser} />}
|
||||
</section>
|
||||
)}
|
||||
</>
|
||||
</Stack>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
|
@ -1,63 +1,38 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { dateTimeFormat } from '@grafana/data';
|
||||
import { Button, Spinner } from '@grafana/ui';
|
||||
import { InteractiveTable, Text } from '@grafana/ui';
|
||||
import { SyncInfo } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
ldapSyncInfo: SyncInfo;
|
||||
}
|
||||
|
||||
interface State {
|
||||
isSyncing: boolean;
|
||||
}
|
||||
|
||||
const format = 'dddd YYYY-MM-DD HH:mm zz';
|
||||
|
||||
export class LdapSyncInfo extends PureComponent<Props, State> {
|
||||
state = {
|
||||
isSyncing: false,
|
||||
};
|
||||
export const LdapSyncInfo = ({ ldapSyncInfo }: Props) => {
|
||||
const nextSyncTime = dateTimeFormat(ldapSyncInfo.nextSync, { format });
|
||||
|
||||
handleSyncClick = () => {
|
||||
this.setState({ isSyncing: !this.state.isSyncing });
|
||||
};
|
||||
const columns = [{ id: 'syncAttribute' }, { id: 'syncValue' }];
|
||||
const data = [
|
||||
{
|
||||
syncAttribute: 'Active synchronization',
|
||||
syncValue: ldapSyncInfo.enabled ? 'Enabled' : 'Disabled',
|
||||
},
|
||||
{
|
||||
syncAttribute: 'Scheduled',
|
||||
syncValue: ldapSyncInfo.schedule,
|
||||
},
|
||||
{
|
||||
syncAttribute: 'Next synchronization',
|
||||
syncValue: nextSyncTime,
|
||||
},
|
||||
];
|
||||
|
||||
render() {
|
||||
const { ldapSyncInfo } = this.props;
|
||||
const { isSyncing } = this.state;
|
||||
const nextSyncTime = dateTimeFormat(ldapSyncInfo.nextSync, { format });
|
||||
|
||||
return (
|
||||
<>
|
||||
<h3 className="page-heading">
|
||||
LDAP Synchronisation
|
||||
<Button className="pull-right" onClick={this.handleSyncClick} hidden>
|
||||
<span className="btn-title">Bulk-sync now</span>
|
||||
{isSyncing && <Spinner inline={true} />}
|
||||
</Button>
|
||||
</h3>
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<table className="filter-table form-inline">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Active synchronisation</td>
|
||||
<td colSpan={2}>{ldapSyncInfo.enabled ? 'Enabled' : 'Disabled'}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Scheduled</td>
|
||||
<td>{ldapSyncInfo.schedule}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Next scheduled synchronisation</td>
|
||||
<td>{nextSyncTime}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<section>
|
||||
<Text element="h3">LDAP Synchronization</Text>
|
||||
<InteractiveTable data={data} columns={columns} getRowId={(sync) => sync.syncAttribute} />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
@ -1,54 +1,52 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Tooltip, Icon } from '@grafana/ui';
|
||||
import { Tooltip, Icon, InteractiveTable, type CellProps, Column } from '@grafana/ui';
|
||||
import { LdapRole } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
groups: LdapRole[];
|
||||
showAttributeMapping?: boolean;
|
||||
}
|
||||
|
||||
export const LdapUserGroups = ({ groups, showAttributeMapping }: Props) => {
|
||||
const items = showAttributeMapping ? groups : groups.filter((item) => item.orgRole);
|
||||
export const LdapUserGroups = ({ groups }: Props) => {
|
||||
const items = useMemo(() => groups, [groups]);
|
||||
|
||||
const columns = useMemo<Array<Column<LdapRole>>>(
|
||||
() => [
|
||||
{
|
||||
id: 'groupDN',
|
||||
header: 'LDAP Group',
|
||||
},
|
||||
{
|
||||
id: 'orgName',
|
||||
header: 'Organization',
|
||||
cell: (props: CellProps<LdapRole, string | undefined>) =>
|
||||
props.value && props.row.original.orgRole ? props.value : '',
|
||||
},
|
||||
{
|
||||
id: 'orgRole',
|
||||
header: 'Role',
|
||||
cell: (props: CellProps<LdapRole, string | undefined>) =>
|
||||
props.value || (
|
||||
<>
|
||||
No match{' '}
|
||||
<Tooltip content="No matching organizations found">
|
||||
<Icon name="info-circle" />
|
||||
</Tooltip>
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<table className="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
{showAttributeMapping && <th>LDAP Group</th>}
|
||||
<th>
|
||||
Organization
|
||||
<Tooltip placement="top" content="Only the first match for an Organization will be used" theme={'info'}>
|
||||
<Icon name="info-circle" />
|
||||
</Tooltip>
|
||||
</th>
|
||||
<th>Role</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((group, index) => {
|
||||
return (
|
||||
<tr key={`${group.orgId}-${index}`}>
|
||||
{showAttributeMapping && <td>{group.groupDN}</td>}
|
||||
{group.orgName && group.orgRole ? <td>{group.orgName}</td> : <td />}
|
||||
{group.orgRole ? (
|
||||
<td>{group.orgRole}</td>
|
||||
) : (
|
||||
<td>
|
||||
<span className="text-warning">No match</span>
|
||||
<Tooltip placement="top" content="No matching groups found" theme={'info'}>
|
||||
<Icon name="info-circle" />
|
||||
</Tooltip>
|
||||
</td>
|
||||
)}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<InteractiveTable
|
||||
headerTooltips={{
|
||||
orgName: { content: 'Only the first match for an Organization will be used', iconName: 'info-circle' },
|
||||
}}
|
||||
columns={columns}
|
||||
data={items}
|
||||
getRowId={(row) => row.orgId + row.orgRole}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React from 'react';
|
||||
|
||||
import { Box, Stack, Text } from '@grafana/ui';
|
||||
import { LdapUser } from 'app/types';
|
||||
|
||||
import { LdapUserGroups } from './LdapUserGroups';
|
||||
@ -9,33 +10,22 @@ import { LdapUserTeams } from './LdapUserTeams';
|
||||
|
||||
interface Props {
|
||||
ldapUser: LdapUser;
|
||||
showAttributeMapping?: boolean;
|
||||
}
|
||||
|
||||
export const LdapUserInfo = ({ ldapUser, showAttributeMapping }: Props) => {
|
||||
export const LdapUserInfo = ({ ldapUser }: Props) => {
|
||||
return (
|
||||
<>
|
||||
<LdapUserMappingInfo info={ldapUser.info} showAttributeMapping={showAttributeMapping} />
|
||||
<Stack direction="column" gap={4}>
|
||||
<LdapUserMappingInfo info={ldapUser.info} />
|
||||
<LdapUserPermissions permissions={ldapUser.permissions} />
|
||||
{ldapUser.roles && ldapUser.roles.length > 0 && (
|
||||
<LdapUserGroups groups={ldapUser.roles} showAttributeMapping={showAttributeMapping} />
|
||||
)}
|
||||
{ldapUser.roles && ldapUser.roles.length > 0 && <LdapUserGroups groups={ldapUser.roles} />}
|
||||
|
||||
{ldapUser.teams && ldapUser.teams.length > 0 ? (
|
||||
<LdapUserTeams teams={ldapUser.teams} showAttributeMapping={showAttributeMapping} />
|
||||
<LdapUserTeams teams={ldapUser.teams} />
|
||||
) : (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<table className="filter-table form-inline">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>No teams found via LDAP</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<Box>
|
||||
<Text>No teams found via LDAP</Text>
|
||||
</Box>
|
||||
)}
|
||||
</>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
|
@ -1,47 +1,56 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { InteractiveTable } from '@grafana/ui';
|
||||
import { LdapUserInfo } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
info: LdapUserInfo;
|
||||
showAttributeMapping?: boolean;
|
||||
}
|
||||
|
||||
export const LdapUserMappingInfo = ({ info, showAttributeMapping }: Props) => {
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<table className="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={2}>User information</th>
|
||||
{showAttributeMapping && <th>LDAP attribute</th>}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="width-16">First name</td>
|
||||
<td>{info.name.ldapValue}</td>
|
||||
{showAttributeMapping && <td>{info.name.cfgAttrValue}</td>}
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="width-16">Surname</td>
|
||||
<td>{info.surname.ldapValue}</td>
|
||||
{showAttributeMapping && <td>{info.surname.cfgAttrValue}</td>}
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="width-16">Username</td>
|
||||
<td>{info.login.ldapValue}</td>
|
||||
{showAttributeMapping && <td>{info.login.cfgAttrValue}</td>}
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="width-16">Email</td>
|
||||
<td>{info.email.ldapValue}</td>
|
||||
{showAttributeMapping && <td>{info.email.cfgAttrValue}</td>}
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
export const LdapUserMappingInfo = ({ info }: Props) => {
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: 'userInfo',
|
||||
header: 'User Information',
|
||||
disableGrow: true,
|
||||
},
|
||||
{
|
||||
id: 'ldapValue',
|
||||
},
|
||||
{
|
||||
id: 'cfgAttrValue',
|
||||
header: 'LDAP attribute',
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const rows = useMemo(
|
||||
() => [
|
||||
{
|
||||
userInfo: 'First name',
|
||||
ldapValue: info.name.ldapValue,
|
||||
cfgAttrValue: info.name.cfgAttrValue,
|
||||
},
|
||||
{
|
||||
userInfo: 'Surname',
|
||||
ldapValue: info.surname.ldapValue,
|
||||
cfgAttrValue: info.surname.cfgAttrValue,
|
||||
},
|
||||
{
|
||||
userInfo: 'Username',
|
||||
ldapValue: info.login.ldapValue,
|
||||
cfgAttrValue: info.login.cfgAttrValue,
|
||||
},
|
||||
{
|
||||
userInfo: 'Email',
|
||||
ldapValue: info.email.ldapValue,
|
||||
cfgAttrValue: info.email.cfgAttrValue,
|
||||
},
|
||||
],
|
||||
[info]
|
||||
);
|
||||
|
||||
return <InteractiveTable columns={columns} data={rows} getRowId={(row) => row.userInfo} />;
|
||||
};
|
||||
|
@ -1,52 +1,59 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Icon } from '@grafana/ui';
|
||||
import { Column, Icon, InteractiveTable } from '@grafana/ui';
|
||||
import { LdapPermissions } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
permissions: LdapPermissions;
|
||||
}
|
||||
|
||||
interface TableRow {
|
||||
permission: string;
|
||||
value: React.ReactNode;
|
||||
}
|
||||
|
||||
export const LdapUserPermissions = ({ permissions }: Props) => {
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<table className="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colSpan={1}>Permissions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="width-16"> Grafana admin</td>
|
||||
<td>
|
||||
{permissions.isGrafanaAdmin ? (
|
||||
<>
|
||||
<Icon name="shield" /> Yes
|
||||
</>
|
||||
) : (
|
||||
'No'
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="width-16">Status</td>
|
||||
<td>
|
||||
{permissions.isDisabled ? (
|
||||
<>
|
||||
<Icon name="times" /> Inactive
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Icon name="check" /> Active
|
||||
</>
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
const columns = useMemo<Array<Column<TableRow>>>(
|
||||
() => [
|
||||
{
|
||||
id: 'permission',
|
||||
header: 'Permissions',
|
||||
disableGrow: true,
|
||||
},
|
||||
{
|
||||
id: 'value',
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
const data = useMemo<TableRow[]>(
|
||||
() => [
|
||||
{
|
||||
permission: 'Grafana admin',
|
||||
value: permissions.isGrafanaAdmin ? (
|
||||
<>
|
||||
<Icon name="shield" /> Yes
|
||||
</>
|
||||
) : (
|
||||
'No'
|
||||
),
|
||||
},
|
||||
{
|
||||
permission: 'Status',
|
||||
value: permissions.isDisabled ? (
|
||||
<>
|
||||
<Icon name="times" /> Inactive
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Icon name="check" /> Active
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
[permissions]
|
||||
);
|
||||
|
||||
return <InteractiveTable data={data} columns={columns} getRowId={(row) => row.permission} />;
|
||||
};
|
||||
|
@ -1,59 +1,40 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
|
||||
import { Tooltip, Icon } from '@grafana/ui';
|
||||
import { Column, InteractiveTable, CellProps } from '@grafana/ui';
|
||||
import { LdapTeam } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
teams: LdapTeam[];
|
||||
showAttributeMapping?: boolean;
|
||||
}
|
||||
|
||||
export const LdapUserTeams = ({ teams, showAttributeMapping }: Props) => {
|
||||
const items = showAttributeMapping ? teams : teams.filter((item) => item.teamName);
|
||||
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form">
|
||||
<table className="filter-table form-inline">
|
||||
<thead>
|
||||
<tr>
|
||||
{showAttributeMapping && <th>LDAP Group</th>}
|
||||
<th>Organisation</th>
|
||||
<th>Team</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{items.map((team, index) => {
|
||||
return (
|
||||
<tr key={`${team.teamName}-${index}`}>
|
||||
{showAttributeMapping && (
|
||||
<>
|
||||
<td>{team.groupDN}</td>
|
||||
{!team.orgName && (
|
||||
<>
|
||||
<td />
|
||||
<td>
|
||||
<span className="text-warning">No match</span>
|
||||
<Tooltip placement="top" content="No matching teams found" theme={'info'}>
|
||||
<Icon name="info-circle" />
|
||||
</Tooltip>
|
||||
</td>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
{team.orgName && (
|
||||
<>
|
||||
<td>{team.orgName}</td>
|
||||
<td>{team.teamName}</td>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
export const LdapUserTeams = ({ teams }: Props) => {
|
||||
const columns = useMemo<Array<Column<LdapTeam>>>(
|
||||
() => [
|
||||
{
|
||||
id: 'groupDN',
|
||||
header: 'LDAP Group',
|
||||
},
|
||||
{
|
||||
id: 'orgName',
|
||||
header: 'Organization',
|
||||
cell: ({
|
||||
row: {
|
||||
original: { orgName },
|
||||
},
|
||||
}: CellProps<LdapTeam, void>) => <>{orgName || 'No matching teams found'}</>,
|
||||
},
|
||||
{
|
||||
id: 'teamName',
|
||||
header: 'Team',
|
||||
cell: ({
|
||||
row: {
|
||||
original: { teamName, orgName },
|
||||
},
|
||||
}: CellProps<LdapTeam, void>) => (teamName && orgName ? teamName : ''),
|
||||
},
|
||||
],
|
||||
[]
|
||||
);
|
||||
|
||||
return <InteractiveTable data={teams} columns={columns} getRowId={(row) => row.teamName} />;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user