fix selection in table view

This commit is contained in:
Elyor Djalilov 2024-01-12 16:54:58 +05:00
parent 604087db5a
commit 6eda31a9a2
3 changed files with 321 additions and 157 deletions

View File

@ -1,5 +1,4 @@
import { useEffect, useState } from "react";
import { inject, observer } from "mobx-react";
import TableHeader from "@docspace/components/table-container/TableHeader";
@ -31,7 +30,7 @@ const SessionsTableHeader = (props) => {
userId,
sectionWidth,
setHideColumns,
tableRef,
containerRef,
columnStorageName,
columnInfoPanelStorageName,
} = props;
@ -101,7 +100,7 @@ const SessionsTableHeader = (props) => {
return (
<TableHeader
checkboxSize="48px"
containerRef={tableRef}
containerRef={containerRef}
columns={columns}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}

View File

@ -1,33 +1,113 @@
import { useRef } from "react";
import { useCallback } from "react";
import { Base } from "@docspace/components/themes";
import styled, { css } from "styled-components";
import withContent from "SRC_DIR/HOCs/withPeopleContent";
import TableRow from "@docspace/components/table-container/TableRow";
import TableCell from "@docspace/components/table-container/TableCell";
import Text from "@docspace/components/text";
import Avatar from "@docspace/components/avatar";
import Checkbox from "@docspace/components/checkbox";
import HistoryFinalizedReactSvgUrl from "PUBLIC_DIR/images/history-finalized.react.svg?url";
import RemoveSvgUrl from "PUBLIC_DIR/images/remove.session.svg?url";
import TrashReactSvgUrl from "PUBLIC_DIR/images/trash.react.svg?url";
const Wrapper = styled.div`
display: contents;
`;
const StyledTableRow = styled(TableRow)`
:hover {
.table-container_cell {
cursor: pointer;
background: ${(props) =>
`${props.theme.filesSection.tableView.row.backgroundActive} !important`};
border-top: ${(props) =>
`1px solid ${props.theme.filesSection.tableView.row.borderColor}`};
margin-top: -1px;
}
.table-container_user-name-cell {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-right: -24px;
padding-right: 24px;
`
: css`
margin-left: -24px;
padding-left: 24px;
`}
}
.table-container_row-context-menu-wrapper {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: -20px;
padding-left: 20px;
`
: css`
margin-right: -20px;
padding-right: 20px;
`}
}
}
.table-container_cell {
text-overflow: ellipsis;
height: 48px;
max-height: 48px;
background: ${(props) =>
(props.checked || props.isActive) &&
`${props.theme.filesSection.tableView.row.backgroundActive} !important`};
}
.table-container_row-checkbox {
padding: 16px 8px 16px 12px;
}
.avatar {
.table-container_row-checkbox-wrapper {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: 8px;
padding-left: 0px;
`
: css`
margin-right: 8px;
padding-right: 0px;
`}
min-width: 48px;
.table-container_row-checkbox {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-right: -4px;
padding: 16px 12px 16px 8px;
`
: css`
margin-left: -4px;
padding: 16px 8px 16px 12px;
`}
}
}
.table-cell_username {
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: 12px;
`
: css`
margin-right: 12px;
`}
}
.table-container_row-context-menu-wrapper {
justify-content: flex-end;
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
padding-left: 0px;
`
: css`
padding-right: 0px;
`}
}
@ -42,22 +122,26 @@ const StyledTableRow = styled(TableRow)`
}
`;
const SessionsTableRow = ({
t,
avatar,
role,
displayName,
status,
browser,
platform,
country,
city,
ip,
hideColumns,
isChecked,
toggleSession,
}) => {
const tableRef = useRef();
StyledTableRow.defaultProps = { theme: Base };
const SessionsTableRow = (props) => {
const {
t,
item,
element,
checkedProps,
onContentRowSelect,
onContentRowClick,
isActive,
hideColumns,
displayName,
status,
browser,
platform,
country,
city,
ip,
} = props;
const contextOptions = [
{
@ -84,72 +168,101 @@ const SessionsTableRow = ({
},
];
const handleSessionToggle = (e) => {
e.preventDefault();
e.stopPropagation();
tableRef.current?.contains(e.target) || toggleSession(e);
};
const isChecked = checkedProps.checked;
const isOnline = status === "Online";
const onChange = (e) => {
onContentRowSelect && onContentRowSelect(e.target.checked, item);
};
const onRowContextClick = useCallback(() => {
onContentRowClick && onContentRowClick(!isChecked, item, false);
}, [isChecked, item, onContentRowClick]);
const onRowClick = (e) => {
if (
e.target.closest(".checkbox") ||
e.target.closest(".table-container_row-checkbox") ||
e.target.closest(".paid-badge") ||
e.target.closest(".pending-badge") ||
e.target.closest(".disabled-badge") ||
e.detail === 0
) {
return;
}
onContentRowClick && onContentRowClick(!isChecked, item);
};
return (
<StyledTableRow
hideColumns={hideColumns}
contextOptions={contextOptions}
checked={isChecked}
onClick={handleSessionToggle}
<Wrapper
className={`user-item ${
isChecked || isActive ? "table-row-selected" : ""
}`}
>
<TableCell hasAccess={true}>
<div className="table-container_element">
<Avatar
className="avatar"
userName={displayName}
role={role}
source={avatar}
size={"small"}
/>
</div>
<StyledTableRow
key={item.id}
className="table-row"
checked={isChecked}
isActive={isActive}
onClick={onRowClick}
fileContextClick={onRowContextClick}
hideColumns={hideColumns}
contextOptions={contextOptions}
>
<TableCell className="table-container_user-name-cell">
<TableCell
hasAccess={true}
className="table-container_row-checkbox-wrapper"
checked={isChecked}
>
<div className="table-container_element">{element}</div>
<Checkbox
className="table-container_row-checkbox"
isChecked={isChecked}
onChange={onChange}
/>
</TableCell>
<Text className="table-cell_username" fontWeight="600">
{displayName}
</Text>
</TableCell>
<Checkbox
className="table-container_row-checkbox"
isChecked={isChecked}
onChange={handleSessionToggle}
/>
<TableCell>
<Text
className={isOnline ? "session-online" : "session-info"}
truncate
>
{status}
</Text>
</TableCell>
<Text fontWeight="600">{displayName}</Text>
</TableCell>
<TableCell>
<Text className="session-info" truncate>
{platform},&nbsp;
</Text>
<Text className="session-info" truncate>
{browser}
</Text>
</TableCell>
<TableCell>
<Text className={isOnline ? "session-online" : "session-info"} truncate>
{status}
</Text>
</TableCell>
<TableCell>
<Text className="session-info" truncate>
{country},&nbsp;
</Text>
<Text className="session-info" truncate>
{city}
</Text>
</TableCell>
<TableCell>
<Text className="session-info" truncate>
{platform},&nbsp;
</Text>
<Text className="session-info" truncate>
{browser}
</Text>
</TableCell>
<TableCell>
<Text className="session-info" truncate>
{country},&nbsp;
</Text>
<Text className="session-info" truncate>
{city}
</Text>
</TableCell>
<TableCell>
<Text className="session-info" truncate>
{ip}
</Text>
</TableCell>
</StyledTableRow>
<TableCell>
<Text className="session-info" truncate>
{ip}
</Text>
</TableCell>
</StyledTableRow>
</Wrapper>
);
};
export default SessionsTableRow;
export default withContent(SessionsTableRow);

View File

@ -14,6 +14,46 @@ import TableContainer from "@docspace/components/table-container/TableContainer"
import TableGroupMenu from "@docspace/components/table-container/TableGroupMenu";
import TableBody from "@docspace/components/table-container/TableBody";
const TABLE_VERSION = "5";
const COLUMNS_SIZE = `sessionsColumnsSize_ver-${TABLE_VERSION}`;
const INFO_PANEL_COLUMNS_SIZE = `infoPanelSessionsColumnsSize_ver-${TABLE_VERSION}`;
const marginCss = css`
margin-top: -1px;
border-top: ${(props) =>
`1px solid ${props.theme.filesSection.tableView.row.borderColor}`};
`;
const userNameCss = css`
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-right: -24px;
padding-right: 24px;
`
: css`
margin-left: -24px;
padding-left: 24px;
`}
${marginCss}
`;
const contextCss = css`
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
margin-left: -20px;
padding-left: 20px;
`
: css`
margin-right: -20px;
padding-right: 20px;
`}
${marginCss}
`;
const StyledTableContainer = styled(TableContainer)`
margin: 0 0 24px;
@ -21,7 +61,7 @@ const StyledTableContainer = styled(TableContainer)`
height: 69px;
position: absolute;
z-index: 201;
top: 0;
top: -25px;
left: 0px;
width: 100%;
@ -49,76 +89,91 @@ const StyledTableContainer = styled(TableContainer)`
font-size: ${(props) => props.theme.getCorrectFontSize("12px")};
}
.table-list-item {
cursor: pointer;
:has(
.table-container_body
.table-list-item:first-child:first-child
> .table-row-selected
) {
.table-container_header {
border-image-slice: 1;
border-image-source: ${(props) =>
props.theme.tableContainer.header.lengthenBorderImageSource};
}
}
&:hover {
background-color: ${(props) =>
props.theme.filesSection.tableView.row.backgroundActive};
.table-row-selected {
.table-container_user-name-cell {
${userNameCss}
}
.table-container_cell {
margin-top: -1px;
border-top: ${(props) =>
`1px solid ${props.theme.filesSection.tableView.row.borderColor}`};
margin-left: -24px;
padding-left: 24px;
}
.table-container_row-context-menu-wrapper {
${contextCss}
}
}
.table-row-selected + .table-row-selected {
.table-row {
.table-container_user-name-cell,
.table-container_row-context-menu-wrapper {
margin-right: -20px;
padding-right: 20px;
margin-top: -1px;
border-image-slice: 1;
border-top: 1px solid;
}
.table-container_user-name-cell {
${userNameCss}
border-left: 0; //for Safari macOS
border-right: 0; //for Safari macOS
border-image-source: ${(props) =>
`linear-gradient(to right, ${props.theme.filesSection.tableView.row.borderColorTransition} 17px, ${props.theme.filesSection.tableView.row.borderColor} 31px)`};
}
.table-container_row-context-menu-wrapper {
${contextCss}
border-image-source: ${(props) =>
`linear-gradient(to left, ${props.theme.filesSection.tableView.row.borderColorTransition} 17px, ${props.theme.filesSection.tableView.row.borderColor} 31px)`};
}
}
}
.table-list-item:has(.selected-table-row) {
background-color: ${(props) =>
props.theme.filesSection.tableView.row.backgroundActive};
}
.user-item:not(.table-row-selected) + .table-row-selected {
.table-row {
.table-container_user-name-cell {
${userNameCss}
}
.table-container_row-context-menu-wrapper {
justify-content: flex-end;
.table-container_row-context-menu-wrapper {
${contextCss}
}
${(props) =>
props.theme.interfaceDirection === "rtl"
? css`
padding-left: 0px;
`
: css`
padding-right: 0px;
`}
.table-container_user-name-cell,
.table-container_row-context-menu-wrapper {
border-bottom: ${(props) =>
`1px solid ${props.theme.filesSection.tableView.row.borderColor}`};
}
}
}
`;
StyledTableContainer.defaultProps = { theme: Base };
const TABLE_VERSION = "5";
const COLUMNS_SIZE = `sessionsColumnsSize_ver-${TABLE_VERSION}`;
const INFO_PANEL_COLUMNS_SIZE = `infoPanelSessionsColumnsSize_ver-${TABLE_VERSION}`;
const TableView = ({
t,
sectionWidth,
userId,
sessionsData,
allSessions,
checkedSessions,
toggleSession,
toggleAllSessions,
isSessionChecked,
// allSessions,
// checkedSessions,
// toggleSession,
// toggleAllSessions,
// isSessionChecked,
}) => {
const [hideColumns, setHideColumns] = useState(false);
const tableRef = useRef(null);
const ref = useRef(null);
const handleToggle = (e, id) => {
e.stopPropagation();
toggleSession(id);
};
const handleAllToggles = (checked) => {
toggleAllSessions(checked, allSessions);
};
// const handleAllToggles = (checked) => {
// toggleAllSessions(checked, allSessions);
// };
const columnStorageName = `${COLUMNS_SIZE}=${userId}`;
const columnInfoPanelStorageName = `${INFO_PANEL_COLUMNS_SIZE}=${userId}`;
@ -147,14 +202,14 @@ const TableView = ({
},
];
const isChecked = checkedSessions.length === allSessions.length;
// const isChecked = checkedSessions.length === allSessions.length;
const isIndeterminate =
checkedSessions.length > 0 && checkedSessions.length !== allSessions.length;
// const isIndeterminate =
// checkedSessions.length > 0 && checkedSessions.length !== allSessions.length;
return (
<StyledTableContainer forwardedRef={tableRef} useReactWindow>
{checkedSessions.length > 0 && (
<StyledTableContainer forwardedRef={ref} useReactWindow>
{/* {checkedSessions.length > 0 && (
<div className="table-group-menu">
<TableGroupMenu
sectionWidth={sectionWidth}
@ -167,17 +222,15 @@ const TableView = ({
onChange={handleAllToggles}
/>
</div>
)}
)} */}
<SessionsTableHeader
t={t}
userId={userId}
sectionWidth={sectionWidth}
setHideColumns={setHideColumns}
userId={userId}
tableRef={tableRef}
containerRef={ref}
columnStorageName={columnStorageName}
columnInfoPanelStorageName={columnInfoPanelStorageName}
isChecked={isChecked}
isIndeterminate={isIndeterminate}
/>
<TableBody
itemHeight={49}
@ -190,21 +243,20 @@ const TableView = ({
itemCount={sessionsData.length}
fetchMoreFiles={() => {}}
>
{sessionsData.map((session) => (
{sessionsData.map((item) => (
<SessionsTableRow
t={t}
key={session.userId}
avatar={session.avatar}
displayName={session.displayName}
status={session.status}
platform={session.platform}
browser={session.browser}
country={session.country}
city={session.city}
ip={session.ip}
key={item.userId}
item={item}
userId={userId}
hideColumns={hideColumns}
isChecked={isSessionChecked(session.userId)}
toggleSession={(e) => handleToggle(e, session.userId)}
displayName={item.displayName}
status={item.status}
browser={item.browser}
platform={item.platform}
country={item.country}
city={item.city}
ip={item.ip}
/>
))}
</TableBody>