web: People: Optimization of People list rendering
Added new packages: react-window and react-virtualized-auto-sizer; Added changes to Scrollbar, PageLayout and PageSection
This commit is contained in:
parent
f308c669e1
commit
b0d5d1ea72
@ -26,6 +26,8 @@
|
||||
"react-router": "5.0.1",
|
||||
"react-router-dom": "5.0.1",
|
||||
"react-scripts": "3.0.1",
|
||||
"react-virtualized-auto-sizer": "^1.0.2",
|
||||
"react-window": "^1.8.5",
|
||||
"reactstrap": "8.0.0",
|
||||
"redux": "4.0.1",
|
||||
"redux-form": "^8.2.4",
|
||||
|
@ -1,76 +1,151 @@
|
||||
import React from "react";
|
||||
import React, { memo, useCallback } from "react";
|
||||
import { withRouter } from "react-router";
|
||||
import { connect } from "react-redux";
|
||||
import { ContentRow, toastr } from "asc-web-components";
|
||||
import { ContentRow, toastr, Scrollbar } from "asc-web-components";
|
||||
import UserContent from "./userContent";
|
||||
//import config from "../../../../../../package.json";
|
||||
import { selectUser, deselectUser, setSelection } from "../../../../../store/people/actions";
|
||||
import { isUserSelected, getUserStatus, getUserRole, isUserDisabled } from '../../../../../store/people/selectors';
|
||||
import { isAdmin } from '../../../../../store/auth/selectors';
|
||||
import {
|
||||
selectUser,
|
||||
deselectUser,
|
||||
setSelection
|
||||
} from "../../../../../store/people/actions";
|
||||
import {
|
||||
isUserSelected,
|
||||
getUserStatus,
|
||||
getUserRole,
|
||||
isUserDisabled
|
||||
} from "../../../../../store/people/selectors";
|
||||
import { isAdmin } from "../../../../../store/auth/selectors";
|
||||
import { FixedSizeList as List, areEqual } from "react-window";
|
||||
import AutoSizer from "react-virtualized-auto-sizer";
|
||||
|
||||
|
||||
const CustomScrollbars = ({ onScroll, forwardedRef, style, children }) => {
|
||||
const refSetter = useCallback(scrollbarsRef => {
|
||||
if (scrollbarsRef) {
|
||||
forwardedRef(scrollbarsRef.view);
|
||||
} else {
|
||||
forwardedRef(null);
|
||||
}
|
||||
}, [forwardedRef]);
|
||||
|
||||
return (
|
||||
<Scrollbar
|
||||
ref={refSetter}
|
||||
style={{ ...style, overflow: "hidden" }}
|
||||
onScroll={onScroll}
|
||||
stype="mediumBlack"
|
||||
>
|
||||
{children}
|
||||
</Scrollbar>
|
||||
);
|
||||
};
|
||||
|
||||
const CustomScrollbarsVirtualList = React.forwardRef((props, ref) => (
|
||||
<CustomScrollbars {...props} forwardedRef={ref} />
|
||||
));
|
||||
|
||||
const Row = memo(
|
||||
({
|
||||
data,
|
||||
index,
|
||||
style,
|
||||
onContentRowSelect,
|
||||
history,
|
||||
settings,
|
||||
selection,
|
||||
getUserContextOptions
|
||||
}) => {
|
||||
// Data passed to List as "itemData" is available as props.data
|
||||
const user = data[index];
|
||||
|
||||
// console.log("Row user", user);
|
||||
const contextOptions = getUserContextOptions(user);
|
||||
|
||||
return (
|
||||
<ContentRow
|
||||
key={user.id}
|
||||
status={getUserStatus(user)}
|
||||
data={user}
|
||||
avatarRole={getUserRole(user)}
|
||||
avatarSource={user.avatar}
|
||||
avatarName={user.displayName}
|
||||
contextOptions={contextOptions}
|
||||
checked={isUserSelected(selection, user.id)}
|
||||
onSelect={onContentRowSelect}
|
||||
style={style}
|
||||
>
|
||||
<UserContent user={user} history={history} settings={settings} />
|
||||
</ContentRow>
|
||||
);
|
||||
},
|
||||
areEqual
|
||||
);
|
||||
|
||||
class SectionBodyContent extends React.PureComponent {
|
||||
|
||||
onEmailSentClick = () => {
|
||||
toastr.success("Context action: Send e-mail");
|
||||
}
|
||||
};
|
||||
|
||||
onSendMessageClick = () => {
|
||||
toastr.success("Context action: Send message");
|
||||
}
|
||||
};
|
||||
|
||||
onEditClick = (user) => {
|
||||
onEditClick = user => {
|
||||
const { history, settings } = this.props;
|
||||
history.push(`${settings.homepage}/edit/${user.userName}`);
|
||||
}
|
||||
};
|
||||
|
||||
onChangePasswordClick = () => {
|
||||
toastr.success("Context action: Change password");
|
||||
}
|
||||
};
|
||||
|
||||
onChangeEmailClick = () => {
|
||||
toastr.success("Context action: Change e-mail");
|
||||
}
|
||||
};
|
||||
|
||||
onDisableClick = () => {
|
||||
toastr.success("Context action: Disable");
|
||||
}
|
||||
};
|
||||
|
||||
getUserContextOptions = (user) => {
|
||||
|
||||
const options = [{
|
||||
key: "key1",
|
||||
label: "Send e-mail",
|
||||
onClick: this.onEmailSentClick
|
||||
getUserContextOptions = user => {
|
||||
const options = [
|
||||
{
|
||||
key: "key1",
|
||||
label: "Send e-mail",
|
||||
onClick: this.onEmailSentClick
|
||||
},
|
||||
{
|
||||
key: "key2",
|
||||
label: "Send message",
|
||||
onClick: this.onSendMessageClick
|
||||
key: "key2",
|
||||
label: "Send message",
|
||||
onClick: this.onSendMessageClick
|
||||
},
|
||||
{ key: "key3", isSeparator: true },
|
||||
{
|
||||
key: "key4",
|
||||
label: "Edit",
|
||||
onClick: this.onEditClick.bind(this, user)
|
||||
key: "key4",
|
||||
label: "Edit",
|
||||
onClick: this.onEditClick.bind(this, user)
|
||||
},
|
||||
{
|
||||
key: "key5",
|
||||
label: "Change password",
|
||||
onClick: this.onChangePasswordClick
|
||||
key: "key5",
|
||||
label: "Change password",
|
||||
onClick: this.onChangePasswordClick
|
||||
},
|
||||
{
|
||||
key: "key6",
|
||||
label: "Change e-mail",
|
||||
onClick: this.onChangeEmailClick
|
||||
}];
|
||||
key: "key6",
|
||||
label: "Change e-mail",
|
||||
onClick: this.onChangeEmailClick
|
||||
}
|
||||
];
|
||||
|
||||
return [...options,
|
||||
!isUserDisabled(user)
|
||||
return [
|
||||
...options,
|
||||
!isUserDisabled(user)
|
||||
? {
|
||||
key: "key7",
|
||||
label: "Disable",
|
||||
onClick: this.onDisableClick
|
||||
}
|
||||
}
|
||||
: {}
|
||||
];
|
||||
};
|
||||
@ -79,58 +154,46 @@ class SectionBodyContent extends React.PureComponent {
|
||||
console.log("ContentRow onSelect", checked, user);
|
||||
if (checked) {
|
||||
this.props.selectUser(user);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.props.deselectUser(user);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
console.log("Home SectionBodyContent render()");
|
||||
const { users, isAdmin, selection, history, settings} = this.props;
|
||||
const { users, isAdmin, selection, history, settings } = this.props;
|
||||
|
||||
return (
|
||||
<>
|
||||
{users.map(user => {
|
||||
const contextOptions = this.getUserContextOptions(user);
|
||||
return isAdmin ? (
|
||||
<ContentRow
|
||||
key={user.id}
|
||||
status={getUserStatus(user)}
|
||||
data={user}
|
||||
avatarRole={getUserRole(user)}
|
||||
avatarSource={user.avatar}
|
||||
avatarName={user.displayName}
|
||||
contextOptions={contextOptions}
|
||||
checked={isUserSelected(selection, user.id)}
|
||||
onSelect={this.onContentRowSelect}
|
||||
>
|
||||
<UserContent
|
||||
user={user}
|
||||
<AutoSizer>
|
||||
{({ height, width }) => (
|
||||
<List
|
||||
className="List"
|
||||
height={height}
|
||||
width={width}
|
||||
itemSize={46} // ContentRow height
|
||||
itemCount={users.length}
|
||||
itemData={users}
|
||||
ref={this.refList}
|
||||
outerElementType={CustomScrollbarsVirtualList}
|
||||
>
|
||||
{({ data, index, style }) => (
|
||||
<Row
|
||||
data={data}
|
||||
index={index}
|
||||
style={style}
|
||||
onContentRowSelect={this.onContentRowSelect}
|
||||
history={history}
|
||||
settings={settings}
|
||||
selection={selection}
|
||||
getUserContextOptions={this.getUserContextOptions}
|
||||
/>
|
||||
</ContentRow>
|
||||
) : (
|
||||
<ContentRow
|
||||
key={user.id}
|
||||
status={getUserStatus(user)}
|
||||
avatarRole={getUserRole(user)}
|
||||
avatarSource={user.avatar}
|
||||
avatarName={user.userName}
|
||||
>
|
||||
<UserContent
|
||||
user={user}
|
||||
history={history}
|
||||
settings={settings}
|
||||
/>
|
||||
</ContentRow>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</List>
|
||||
)}
|
||||
</AutoSizer>
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
|
@ -110,6 +110,7 @@ class Home extends React.Component {
|
||||
fontColor={"#999"}
|
||||
/>
|
||||
<PageLayout
|
||||
withBodyScroll={false}
|
||||
articleHeaderContent={<ArticleHeaderContent />}
|
||||
articleMainButtonContent={<ArticleMainButtonContent />}
|
||||
articleBodyContent={<ArticleBodyContent />}
|
||||
|
@ -6653,7 +6653,7 @@ mem@^4.0.0:
|
||||
mimic-fn "^2.0.0"
|
||||
p-is-promise "^2.0.0"
|
||||
|
||||
memoize-one@^5.0.0:
|
||||
"memoize-one@>=3.1.1 <6", memoize-one@^5.0.0:
|
||||
version "5.0.5"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.0.5.tgz#8cd3809555723a07684afafcd6f756072ac75d7e"
|
||||
integrity sha512-ey6EpYv0tEaIbM/nTDOpHciXUvd+ackQrJgEzBwemhZZIWZjcyodqEcrmqDy2BKRTM3a65kKBV4WtLXJDt26SQ==
|
||||
@ -8942,6 +8942,19 @@ react-transition-group@^2.3.1, react-transition-group@^2.6.1:
|
||||
prop-types "^15.6.2"
|
||||
react-lifecycles-compat "^3.0.4"
|
||||
|
||||
react-virtualized-auto-sizer@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
|
||||
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
|
||||
|
||||
react-window@^1.8.5:
|
||||
version "1.8.5"
|
||||
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1"
|
||||
integrity sha512-HeTwlNa37AFa8MDZFZOKcNEkuF2YflA0hpGPiTT9vR7OawEt+GZbfM6wqkBahD3D3pUjIabQYzsnY/BSJbgq6Q==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.0.0"
|
||||
memoize-one ">=3.1.1 <6"
|
||||
|
||||
react@^16.8.6:
|
||||
version "16.8.6"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-16.8.6.tgz#ad6c3a9614fd3a4e9ef51117f54d888da01f2bbe"
|
||||
|
@ -149,7 +149,7 @@ class PageLayout extends React.PureComponent {
|
||||
}
|
||||
{
|
||||
this.state.isSectionBodyAvailable &&
|
||||
<SectionBody>{this.state.sectionBodyContent}</SectionBody>
|
||||
<SectionBody withScroll={this.props.withBodyScroll}>{this.state.sectionBodyContent}</SectionBody>
|
||||
}
|
||||
{
|
||||
this.state.isSectionPagingAvailable &&
|
||||
@ -177,13 +177,16 @@ PageLayout.propTypes = {
|
||||
sectionHeaderContent: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
|
||||
sectionFilterContent: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
|
||||
sectionBodyContent: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
|
||||
sectionPagingContent: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node])
|
||||
sectionPagingContent: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
|
||||
|
||||
withBodyScroll: PropTypes.bool
|
||||
}
|
||||
|
||||
PageLayout.defaultProps = {
|
||||
isBackdropVisible: false,
|
||||
isArticleVisible: false,
|
||||
isArticlePinned: false
|
||||
isArticlePinned: false,
|
||||
withBodyScroll: true
|
||||
}
|
||||
|
||||
export default PageLayout
|
@ -1,6 +1,7 @@
|
||||
import React from 'react'
|
||||
import styled from 'styled-components'
|
||||
import Scrollbar from '../../scrollbar'
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import styled from "styled-components";
|
||||
import Scrollbar from "../../scrollbar";
|
||||
|
||||
const StyledSectionBody = styled.div`
|
||||
margin: 16px 0;
|
||||
@ -8,17 +9,26 @@ const StyledSectionBody = styled.div`
|
||||
flex-grow: 1;
|
||||
`;
|
||||
|
||||
const SectionBody = React.memo(props => {
|
||||
const SectionBody = React.memo(props => {
|
||||
console.log("PageLayout SectionBody render");
|
||||
const { children } = props;
|
||||
const { children, withScroll } = props;
|
||||
|
||||
return (
|
||||
<StyledSectionBody>
|
||||
<Scrollbar stype="mediumBlack">
|
||||
{children}
|
||||
</Scrollbar>
|
||||
{withScroll
|
||||
? <Scrollbar stype="mediumBlack">{children}</Scrollbar>
|
||||
: <>{children}</>
|
||||
}
|
||||
</StyledSectionBody>
|
||||
);
|
||||
});
|
||||
|
||||
export default SectionBody;
|
||||
SectionBody.propTypes = {
|
||||
withScroll: PropTypes.bool
|
||||
};
|
||||
|
||||
SectionBody.defaultProps = {
|
||||
withScroll: true
|
||||
};
|
||||
|
||||
export default SectionBody;
|
||||
|
@ -2,7 +2,7 @@ import React from 'react'
|
||||
import { Scrollbars } from 'react-custom-scrollbars';
|
||||
|
||||
|
||||
const Scrollbar = (props) => {
|
||||
const Scrollbar = React.forwardRef((props, ref) => {
|
||||
//console.log("Scrollbar render");
|
||||
const scrollbarType = {
|
||||
smallWhite: {
|
||||
@ -37,9 +37,9 @@ const Scrollbar = (props) => {
|
||||
);
|
||||
|
||||
return (
|
||||
<Scrollbars renderThumbVertical={renderNavThumbVertical} renderThumbHorizontal={renderNavThumbHorizontal} {...props} />
|
||||
<Scrollbars renderThumbVertical={renderNavThumbVertical} renderThumbHorizontal={renderNavThumbHorizontal} {...props} ref={ref} />
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Scrollbar.defaultProps = {
|
||||
stype: "smallBlack"
|
||||
|
Loading…
Reference in New Issue
Block a user