grafana/public/app/features/users/UsersListPage.tsx
Alex Khomenko 4a692fc82e
Admin: Use backend sort (#75228)
* Admin: Use InteractiveTable

* Admin: Fix pagination

* Admin: Use CellWrapper

* Admin: Split components

* Admin: Separate OrgUsersTable

* Admin: Remove UsersTable

* Admin: Use the new table for TeamList

* Admin: Cleanup TeamList page

* Admin: Add edit team action

* Admin: Use explicit edit action instead of a link wrapper

* Admin: Fix responsive styles

* Cleanup

* Remove redundant sort

* Add item key

* Fix icon styles

* Set loading by default

* Use separate pagination component

* Use default sorting functionality

* Fix merge conflicts

* Update betterer

* Add controlled sort

* Revert pagination changes

* Move pagination inside OrgUsersTable.tsx

* Add missing prop

* Sort users table

* Fix tests

* Remove loader

* Add sort to Teams

* Cleanup

* Update loadTeams action

* Remove sort condition
2023-09-29 12:48:36 +03:00

120 lines
3.2 KiB
TypeScript

import React, { useEffect, useState } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import { renderMarkdown } from '@grafana/data';
import { Page } from 'app/core/components/Page/Page';
import { contextSrv } from 'app/core/core';
import { OrgUser, OrgRole, StoreState } from 'app/types';
import { OrgUsersTable } from '../admin/Users/OrgUsersTable';
import InviteesTable from '../invites/InviteesTable';
import { fetchInvitees } from '../invites/state/actions';
import { selectInvitesMatchingQuery } from '../invites/state/selectors';
import { UsersActionBar } from './UsersActionBar';
import { loadUsers, removeUser, updateUser, changePage, changeSort } from './state/actions';
import { getUsers, getUsersSearchQuery } from './state/selectors';
function mapStateToProps(state: StoreState) {
const searchQuery = getUsersSearchQuery(state.users);
return {
users: getUsers(state.users),
searchQuery: getUsersSearchQuery(state.users),
page: state.users.page,
totalPages: state.users.totalPages,
perPage: state.users.perPage,
invitees: selectInvitesMatchingQuery(state.invites, searchQuery),
externalUserMngInfo: state.users.externalUserMngInfo,
isLoading: state.users.isLoading,
};
}
const mapDispatchToProps = {
loadUsers,
fetchInvitees,
changePage,
changeSort,
updateUser,
removeUser,
};
const connector = connect(mapStateToProps, mapDispatchToProps);
export type Props = ConnectedProps<typeof connector>;
export interface State {
showInvites: boolean;
}
export const UsersListPageUnconnected = ({
users,
page,
totalPages,
invitees,
externalUserMngInfo,
isLoading,
loadUsers,
fetchInvitees,
changePage,
updateUser,
removeUser,
changeSort,
}: Props) => {
const [showInvites, setShowInvites] = useState(false);
const externalUserMngInfoHtml = externalUserMngInfo ? renderMarkdown(externalUserMngInfo) : '';
useEffect(() => {
loadUsers();
fetchInvitees();
}, [fetchInvitees, loadUsers]);
const onRoleChange = (role: OrgRole, user: OrgUser) => {
updateUser({ ...user, role: role });
};
const onRemoveUser = (user: OrgUser) => removeUser(user.userId);
const onShowInvites = () => {
setShowInvites(!showInvites);
};
const renderTable = () => {
if (showInvites) {
return <InviteesTable invitees={invitees} />;
} else {
return (
<OrgUsersTable
users={users}
orgId={contextSrv.user.orgId}
onRoleChange={onRoleChange}
onRemoveUser={onRemoveUser}
fetchData={changeSort}
changePage={changePage}
page={page}
totalPages={totalPages}
/>
);
}
};
return (
<Page.Contents isLoading={!isLoading}>
<UsersActionBar onShowInvites={onShowInvites} showInvites={showInvites} />
{externalUserMngInfoHtml && (
<div className="grafana-info-box" dangerouslySetInnerHTML={{ __html: externalUserMngInfoHtml }} />
)}
{isLoading && renderTable()}
</Page.Contents>
);
};
export const UsersListPageContent = connector(UsersListPageUnconnected);
export default function UsersListPage() {
return (
<Page navId="users">
<UsersListPageContent />
</Page>
);
}