Merge branch 'test' into AURORA-1057
This commit is contained in:
commit
b27b8f3143
@ -7,9 +7,9 @@ export const UsersApi = {
|
|||||||
getById(userId) {
|
getById(userId) {
|
||||||
return api.get(`/users/${userId}`).then((r) => r.data);
|
return api.get(`/users/${userId}`).then((r) => r.data);
|
||||||
},
|
},
|
||||||
getAll() {
|
getAll(params = {}) {
|
||||||
return api
|
return api
|
||||||
.get("/users/", { params: { limit: 1000, skip: 0, load_orgs: true } })
|
.get("/users/", { params: { limit: 1000, skip: 0, ...params } })
|
||||||
.then((r) => r.data);
|
.then((r) => r.data);
|
||||||
},
|
},
|
||||||
update(idUser, data) {
|
update(idUser, data) {
|
||||||
|
|||||||
@ -22,9 +22,10 @@ import {
|
|||||||
} from './constants/tableConfig';
|
} from './constants/tableConfig';
|
||||||
import { useRealtime } from './contexts/RealtimeContext';
|
import { useRealtime } from './contexts/RealtimeContext';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
import { CircularProgress } from '@mui/material';
|
||||||
|
|
||||||
const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
||||||
const { data, setData } = useRealtimeData(formId, sheetName, direction);
|
const { data, setData, isLoading: isTableLoading } = useRealtimeData(formId, sheetName, direction);
|
||||||
const [globalFilter, setGlobalFilter] = useState('');
|
const [globalFilter, setGlobalFilter] = useState('');
|
||||||
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
const [showColumnFilters, setShowColumnFilters] = useState(false);
|
||||||
const [selectedColumn, setSelectedColumn] = useState();
|
const [selectedColumn, setSelectedColumn] = useState();
|
||||||
@ -65,7 +66,7 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
const { headerPortalRef, containerRef } = useHeaderPortal();
|
const { headerPortalRef, containerRef } = useHeaderPortal();
|
||||||
|
|
||||||
const { sizeMult, setSizeMult, tableScaleStyle, tableWrapperStyle } =
|
const { sizeMult, setSizeMult, tableScaleStyle, tableWrapperStyle } =
|
||||||
useTableScale(containerRef);
|
useTableScale();
|
||||||
|
|
||||||
const [columnsConfig, setColumnsConfig] = useState(null);
|
const [columnsConfig, setColumnsConfig] = useState(null);
|
||||||
|
|
||||||
@ -125,11 +126,19 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
columns,
|
columns,
|
||||||
data: data,
|
data: data,
|
||||||
enableRowVirtualization: true,
|
enableRowVirtualization: true,
|
||||||
|
enableColumnVirtualization: true,
|
||||||
rowVirtualizerOptions: {
|
rowVirtualizerOptions: {
|
||||||
overscan: 50,
|
overscan: 30,
|
||||||
scrollPaddingStart: 0,
|
scrollPaddingStart: 0,
|
||||||
scrollPaddingEnd: 0,
|
scrollPaddingEnd: 0,
|
||||||
},
|
},
|
||||||
|
columnVirtualizerOptions: ({ table }) => ({
|
||||||
|
overscan: 5,
|
||||||
|
measureElement: (el) => {
|
||||||
|
const index = Number(el?.getAttribute?.('data-index'));
|
||||||
|
return table.getVisibleLeafColumns()[index]?.getSize() ?? 0;
|
||||||
|
},
|
||||||
|
}),
|
||||||
enableRowSelection: true,
|
enableRowSelection: true,
|
||||||
onRowSelectionChange: setRowSelection,
|
onRowSelectionChange: setRowSelection,
|
||||||
onColumnSizingChange: setColumnSizing,
|
onColumnSizingChange: setColumnSizing,
|
||||||
@ -141,20 +150,15 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
columnVisibility,
|
columnVisibility,
|
||||||
globalFilter,
|
globalFilter,
|
||||||
showColumnFilters,
|
showColumnFilters,
|
||||||
rowSelection
|
rowSelection,
|
||||||
},
|
},
|
||||||
initialState: {
|
initialState: {
|
||||||
expanded: true
|
expanded: true
|
||||||
},
|
},
|
||||||
meta: tableMeta,
|
meta: tableMeta,
|
||||||
muiTableHeadCellProps: ({ column }) => ({
|
muiTableHeadCellProps: {
|
||||||
sx: {
|
sx: { boxSizing: 'border-box' },
|
||||||
width: column.getSize(),
|
|
||||||
minWidth: column.getSize(),
|
|
||||||
maxWidth: column.getSize(),
|
|
||||||
boxSizing: 'border-box',
|
|
||||||
},
|
},
|
||||||
}),
|
|
||||||
muiTableBodyCellProps: getTableHeadCellStyles,
|
muiTableBodyCellProps: getTableHeadCellStyles,
|
||||||
muiTableHeadProps: {
|
muiTableHeadProps: {
|
||||||
sx: {
|
sx: {
|
||||||
@ -231,10 +235,6 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
setRowSelection({});
|
setRowSelection({});
|
||||||
}, [rowSelection, table])
|
}, [rowSelection, table])
|
||||||
|
|
||||||
if (!data) {
|
|
||||||
return <div>Загрузка...</div>;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SettingsPanel
|
<SettingsPanel
|
||||||
@ -266,6 +266,22 @@ const RealtimeTable = ({ formType, formId, sheetName, direction }) => {
|
|||||||
>
|
>
|
||||||
<MaterialReactTable table={table} />
|
<MaterialReactTable table={table} />
|
||||||
|
|
||||||
|
{isTableLoading && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
position: 'absolute',
|
||||||
|
inset: 0,
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
background: 'rgba(255, 255, 255, 0.6)',
|
||||||
|
zIndex: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CircularProgress />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{headerPortalRef.current &&
|
{headerPortalRef.current &&
|
||||||
createPortal(
|
createPortal(
|
||||||
<TableHead
|
<TableHead
|
||||||
|
|||||||
@ -6,15 +6,20 @@ import { UsersApi } from '../../../api/users';
|
|||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { AutocompleteForChangeOptions } from '../components/AutocompleteForChangeOptions';
|
import { AutocompleteForChangeOptions } from '../components/AutocompleteForChangeOptions';
|
||||||
|
|
||||||
export const ModalChangeUsersInSsp = ({ open, onClose, ssp, onEdit }) => {
|
export const ModalChangeUsersInSsp = ({
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
ssp,
|
||||||
|
onUsersCountChange,
|
||||||
|
}) => {
|
||||||
const [users, setUsers] = useState([]);
|
const [users, setUsers] = useState([]);
|
||||||
const [usersDataForUpdate, setUsersDataForUpdate] = useState({
|
const [usersDataForUpdate, setUsersDataForUpdate] = useState({
|
||||||
update: [],
|
update: [],
|
||||||
delete: [],
|
delete: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
const [allUsers, setAllUsers] = useState([]);
|
const [allUsers, setAllUsers] = useState([]);
|
||||||
const [loadingUsers, setLoadingUsers] = useState(false);
|
const [loadingUsers, setLoadingUsers] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
UsersApi.getAll()
|
UsersApi.getAll()
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
@ -58,14 +63,66 @@ export const ModalChangeUsersInSsp = ({ open, onClose, ssp, onEdit }) => {
|
|||||||
});
|
});
|
||||||
}, [open, ssp]);
|
}, [open, ssp]);
|
||||||
|
|
||||||
const handleClickSave = () => {
|
const deleteUserFromSsp = async (user) => {
|
||||||
onEdit?.(ssp, usersDataForUpdate);
|
try {
|
||||||
|
const data = await SspApi.deleteManySsps(user.id, { ssp_ids: [ssp.id] });
|
||||||
|
if (!data.success) {
|
||||||
|
toast.error(data?.message || 'Ошибка удаления пользователя из ССП');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
const msg =
|
||||||
|
error?.response?.data?.message || error?.response?.data?.detail;
|
||||||
|
toast.error(msg || 'Ошибка удаления пользователя из ССП');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const addUserToSsp = async (user) => {
|
||||||
|
try {
|
||||||
|
const data = await SspApi.putManySsps(user.id, { ssp_ids: [ssp.id] });
|
||||||
|
if (!data.success) {
|
||||||
|
toast.error(data?.message || 'Ошибка добавления пользователя');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
const msg =
|
||||||
|
error?.response?.data?.message || error?.response?.data?.detail;
|
||||||
|
toast.error(msg || 'Ошибка добавления пользователя');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleClickSave = async () => {
|
||||||
|
let added = 0;
|
||||||
|
let removed = 0;
|
||||||
|
|
||||||
|
for (const user of usersDataForUpdate.update) {
|
||||||
|
if (await addUserToSsp(user)) {
|
||||||
|
added += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const user of usersDataForUpdate.delete) {
|
||||||
|
if (await deleteUserFromSsp(user)) {
|
||||||
|
removed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const delta = added - removed;
|
||||||
|
if (delta !== 0) {
|
||||||
|
onUsersCountChange?.(ssp.id, delta);
|
||||||
|
}
|
||||||
|
|
||||||
onClose?.();
|
onClose?.();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeUsersList = (dataForUpdate) => {
|
const handleChangeUsersList = (updater) => {
|
||||||
setUsersDataForUpdate(dataForUpdate);
|
setUsersDataForUpdate(updater);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!ssp) return;
|
if (!ssp) return;
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@ -376,7 +376,7 @@ const SspsPage = () => {
|
|||||||
open={openModalUsersinSspChange}
|
open={openModalUsersinSspChange}
|
||||||
onClose={handleCloseModalUsersInSspChange}
|
onClose={handleCloseModalUsersInSspChange}
|
||||||
ssp={sspForChangeUsers}
|
ssp={sspForChangeUsers}
|
||||||
onEdit={handleUpdateUsers}
|
onUsersCountChange={adjustSspUsersCount}
|
||||||
/>
|
/>
|
||||||
<ModalEditSsp
|
<ModalEditSsp
|
||||||
open={openModalEdit}
|
open={openModalEdit}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ const UsersPage = () => {
|
|||||||
const loadUsers = async () => {
|
const loadUsers = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
const data = await UsersApi.getAll();
|
const data = await UsersApi.getAll({ load_orgs: true });
|
||||||
if (!data.success) {
|
if (!data.success) {
|
||||||
toast.error('Ошибка получения пользователей ' + data.message);
|
toast.error('Ошибка получения пользователей ' + data.message);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -37,7 +37,7 @@ export const AutocompleteForChangeOptions = ({
|
|||||||
if (value) {
|
if (value) {
|
||||||
const newSelected = [...selected, value];
|
const newSelected = [...selected, value];
|
||||||
setSelected(newSelected);
|
setSelected(newSelected);
|
||||||
onChange?.((prev) => ({ ...prev, update: newSelected }));
|
onChange?.((prev) => ({ ...prev, update: [...prev.update, value] }));
|
||||||
|
|
||||||
const newAvailable = available.filter((item) => item.id !== value.id);
|
const newAvailable = available.filter((item) => item.id !== value.id);
|
||||||
setAvailable(newAvailable);
|
setAvailable(newAvailable);
|
||||||
@ -49,16 +49,23 @@ export const AutocompleteForChangeOptions = ({
|
|||||||
|
|
||||||
const handleRemove = (id) => {
|
const handleRemove = (id) => {
|
||||||
const itemToRemove = selected.find((s) => s.id === id);
|
const itemToRemove = selected.find((s) => s.id === id);
|
||||||
if (itemToRemove) {
|
if (!itemToRemove) return;
|
||||||
|
|
||||||
const newSelected = selected.filter((s) => s.id !== id);
|
const newSelected = selected.filter((s) => s.id !== id);
|
||||||
setSelected(newSelected);
|
setSelected(newSelected);
|
||||||
|
|
||||||
setAvailable([...available, itemToRemove]);
|
setAvailable([...available, itemToRemove]);
|
||||||
|
|
||||||
|
const wasInitial = values.some((v) => v.id === id);
|
||||||
|
|
||||||
|
if (wasInitial) {
|
||||||
onChange?.((prev) => ({
|
onChange?.((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
delete: [...prev.delete, itemToRemove],
|
delete: [...prev.delete, itemToRemove],
|
||||||
update: [...newSelected],
|
}));
|
||||||
|
} else {
|
||||||
|
onChange?.((prev) => ({
|
||||||
|
...prev,
|
||||||
|
update: prev.update.filter((u) => u.id !== id),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -130,7 +137,7 @@ export const AutocompleteForChangeOptions = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
renderOption={(props, option) => (
|
renderOption={(props, option) => (
|
||||||
<li {...props} style={{ padding: '4px 12px', minHeight: '36px' }}>
|
<li {...props} style={{ padding: '4px 12px', minHeight: '36px' }} key={option.id}>
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user