mirror of
https://github.com/sct/overseerr.git
synced 2025-09-26 20:12:33 +02:00
feat: ability to edit user settings in bulk (#597)
This commit is contained in:
@@ -6,7 +6,7 @@ import Badge from '../Common/Badge';
|
||||
import { FormattedDate, defineMessages, useIntl } from 'react-intl';
|
||||
import Button from '../Common/Button';
|
||||
import { hasPermission } from '../../../server/lib/permissions';
|
||||
import { Permission, UserType } from '../../hooks/useUser';
|
||||
import { Permission, UserType, useUser } from '../../hooks/useUser';
|
||||
import { useRouter } from 'next/router';
|
||||
import Header from '../Common/Header';
|
||||
import Table from '../Common/Table';
|
||||
@@ -19,6 +19,7 @@ import { Field, Form, Formik } from 'formik';
|
||||
import * as Yup from 'yup';
|
||||
import AddUserIcon from '../../assets/useradd.svg';
|
||||
import Alert from '../Common/Alert';
|
||||
import BulkEditModal from './BulkEditModal';
|
||||
|
||||
const messages = defineMessages({
|
||||
userlist: 'User List',
|
||||
@@ -33,6 +34,7 @@ const messages = defineMessages({
|
||||
created: 'Created',
|
||||
lastupdated: 'Last Updated',
|
||||
edit: 'Edit',
|
||||
bulkedit: 'Bulk Edit',
|
||||
delete: 'Delete',
|
||||
admin: 'Admin',
|
||||
user: 'User',
|
||||
@@ -78,6 +80,39 @@ const UserList: React.FC = () => {
|
||||
}>({
|
||||
isOpen: false,
|
||||
});
|
||||
const [showBulkEditModal, setShowBulkEditModal] = useState(false);
|
||||
const [selectedUsers, setSelectedUsers] = useState<number[]>([]);
|
||||
const { user: currentUser } = useUser();
|
||||
|
||||
const isUserPermsEditable = (userId: number) =>
|
||||
userId !== 1 && userId !== currentUser?.id;
|
||||
const isAllUsersSelected = () => {
|
||||
return (
|
||||
selectedUsers.length ===
|
||||
data?.filter((user) => user.id !== currentUser?.id).length
|
||||
);
|
||||
};
|
||||
const isUserSelected = (userId: number) => selectedUsers.includes(userId);
|
||||
const toggleAllUsers = () => {
|
||||
if (
|
||||
data &&
|
||||
selectedUsers.length >= 0 &&
|
||||
selectedUsers.length < data?.length - 1
|
||||
) {
|
||||
setSelectedUsers(
|
||||
data.filter((user) => isUserPermsEditable(user.id)).map((u) => u.id)
|
||||
);
|
||||
} else {
|
||||
setSelectedUsers([]);
|
||||
}
|
||||
};
|
||||
const toggleUser = (userId: number) => {
|
||||
if (selectedUsers.includes(userId)) {
|
||||
setSelectedUsers((users) => users.filter((u) => u !== userId));
|
||||
} else {
|
||||
setSelectedUsers((users) => [...users, userId]);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteUser = async () => {
|
||||
setDeleting(true);
|
||||
@@ -183,6 +218,7 @@ const UserList: React.FC = () => {
|
||||
{intl.formatMessage(messages.deleteconfirm)}
|
||||
</Modal>
|
||||
</Transition>
|
||||
|
||||
<Transition
|
||||
enter="opacity-0 transition duration-300"
|
||||
enterFrom="opacity-0"
|
||||
@@ -313,6 +349,27 @@ const UserList: React.FC = () => {
|
||||
}}
|
||||
</Formik>
|
||||
</Transition>
|
||||
|
||||
<Transition
|
||||
enter="opacity-0 transition duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="opacity-100 transition duration-300"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
show={showBulkEditModal}
|
||||
>
|
||||
<BulkEditModal
|
||||
onCancel={() => setShowBulkEditModal(false)}
|
||||
onComplete={() => {
|
||||
setShowBulkEditModal(false);
|
||||
revalidate();
|
||||
}}
|
||||
selectedUserIds={selectedUsers}
|
||||
users={data}
|
||||
/>
|
||||
</Transition>
|
||||
|
||||
<div className="flex flex-col justify-between sm:flex-row">
|
||||
<Header>{intl.formatMessage(messages.userlist)}</Header>
|
||||
<div className="flex">
|
||||
@@ -333,21 +390,57 @@ const UserList: React.FC = () => {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Table>
|
||||
<thead>
|
||||
<tr>
|
||||
<Table.TH>
|
||||
<input
|
||||
type="checkbox"
|
||||
id="selectAll"
|
||||
name="selectAll"
|
||||
checked={isAllUsersSelected()}
|
||||
onChange={() => {
|
||||
toggleAllUsers();
|
||||
}}
|
||||
className="w-6 h-6 text-indigo-600 transition duration-150 ease-in-out rounded-md form-checkbox"
|
||||
/>
|
||||
</Table.TH>
|
||||
<Table.TH>{intl.formatMessage(messages.username)}</Table.TH>
|
||||
<Table.TH>{intl.formatMessage(messages.totalrequests)}</Table.TH>
|
||||
<Table.TH>{intl.formatMessage(messages.usertype)}</Table.TH>
|
||||
<Table.TH>{intl.formatMessage(messages.role)}</Table.TH>
|
||||
<Table.TH>{intl.formatMessage(messages.created)}</Table.TH>
|
||||
<Table.TH>{intl.formatMessage(messages.lastupdated)}</Table.TH>
|
||||
<Table.TH></Table.TH>
|
||||
<Table.TH className="text-right">
|
||||
<Button
|
||||
buttonSize="sm"
|
||||
buttonType="warning"
|
||||
onClick={() => setShowBulkEditModal(true)}
|
||||
disabled={selectedUsers.length === 0}
|
||||
>
|
||||
{intl.formatMessage(messages.bulkedit)}
|
||||
</Button>
|
||||
</Table.TH>
|
||||
</tr>
|
||||
</thead>
|
||||
<Table.TBody>
|
||||
{data?.map((user) => (
|
||||
<tr key={`user-list-${user.id}`}>
|
||||
<Table.TD>
|
||||
{isUserPermsEditable(user.id) && (
|
||||
<input
|
||||
type="checkbox"
|
||||
id={`user-list-select-${user.id}`}
|
||||
name={`user-list-select-${user.id}`}
|
||||
checked={isUserSelected(user.id)}
|
||||
onChange={() => {
|
||||
toggleUser(user.id);
|
||||
}}
|
||||
className="w-6 h-6 text-indigo-600 transition duration-150 ease-in-out rounded-md form-checkbox"
|
||||
/>
|
||||
)}
|
||||
</Table.TD>
|
||||
<Table.TD>
|
||||
<div className="flex items-center">
|
||||
<div className="flex-shrink-0 w-10 h-10">
|
||||
|
Reference in New Issue
Block a user