From 4c735030ad6a51705590e72a6c4e6c235feb25dc Mon Sep 17 00:00:00 2001 From: RAR Date: Tue, 10 Jan 2023 19:47:26 +0100 Subject: [PATCH 1/8] feat: Added column card counts Please don't "fix" the " cards" alignment, after adding column collapsing feature it will look good :D --- client/src/components/List/List.jsx | 4 ++++ client/src/components/List/List.module.scss | 5 +++++ client/src/locales/en/core.js | 2 ++ 3 files changed, 11 insertions(+) diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index 00d1b10..5a72b00 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -117,6 +117,10 @@ const List = React.memo( )} +
+ {cardIds.length}  + {cardIds.length !== 1 ? t('common.cards') : t('common.card')} +
Date: Wed, 11 Jan 2023 01:08:15 +0100 Subject: [PATCH 2/8] feat: Improved column card counts - added filtering --- client/src/components/List/List.jsx | 20 +++++++++++++++----- client/src/containers/ListContainer.js | 4 +++- client/src/locales/en/core.js | 1 + client/src/models/List.js | 9 +++++---- client/src/selectors/lists.js | 8 ++++++-- 5 files changed, 30 insertions(+), 12 deletions(-) diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index 5a72b00..5396f1b 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -15,7 +15,8 @@ import { ReactComponent as PlusMathIcon } from '../../assets/images/plus-math-ic import styles from './List.module.scss'; const List = React.memo( - ({ id, index, name, isPersisted, cardIds, canEdit, onUpdate, onDelete, onCardCreate }) => { + // eslint-disable-next-line prettier/prettier + ({ id, index, name, isPersisted, isFiltered, cardIds, cardIdsFull, canEdit, onUpdate, onDelete, onCardCreate }) => { const [t] = useTranslation(); const [isAddCardOpened, setIsAddCardOpened] = useState(false); @@ -86,6 +87,16 @@ const List = React.memo( ); + const cardsCountText = () => { + return ( + [ + isFiltered + ? `${cardIds.length} ${t('common.of')} ${cardIdsFull.length} ` + : `${cardIdsFull.length} `, + ] + [cardIdsFull.length !== 1 ? t('common.cards') : t('common.card')] + ); + }; + return ( {({ innerRef, draggableProps, dragHandleProps }) => ( @@ -117,10 +128,7 @@ const List = React.memo( )} -
- {cardIds.length}  - {cardIds.length !== 1 ? t('common.cards') : t('common.card')} -
+
{cardsCountText()}
{ return (state, { id, index }) => { const { name, isPersisted } = selectListById(state, id); - const cardIds = selectCardIdsByListId(state, id); + const [cardIds, cardIdsFull, isFiltered] = selectCardIdsByListId(state, id); const currentUserMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); const isCurrentUserEditor = @@ -23,7 +23,9 @@ const makeMapStateToProps = () => { index, name, isPersisted, + isFiltered, cardIds, + cardIdsFull, canEdit: isCurrentUserEditor, }; }; diff --git a/client/src/locales/en/core.js b/client/src/locales/en/core.js index 7a0f5b2..32f9801 100644 --- a/client/src/locales/en/core.js +++ b/client/src/locales/en/core.js @@ -160,6 +160,7 @@ export default { writeComment: 'Write a comment...', card: 'card', cards: 'cards', + of: 'of', }, action: { diff --git a/client/src/models/List.js b/client/src/models/List.js index b634a66..7fbef26 100755 --- a/client/src/models/List.js +++ b/client/src/models/List.js @@ -86,14 +86,15 @@ export default class extends BaseModel { getFilteredOrderedCardsModelArray() { let cardModels = this.getOrderedCardsQuerySet().toModelArray(); + const cardModelsFull = cardModels; const filterUserIds = this.board.filterUsers.toRefArray().map((user) => user.id); const filterLabelIds = this.board.filterLabels.toRefArray().map((label) => label.id); - + let isFiltered = false; if (filterUserIds.length > 0) { cardModels = cardModels.filter((cardModel) => { const users = cardModel.users.toRefArray(); - + isFiltered = true; return users.some((user) => filterUserIds.includes(user.id)); }); } @@ -101,12 +102,12 @@ export default class extends BaseModel { if (filterLabelIds.length > 0) { cardModels = cardModels.filter((cardModel) => { const labels = cardModel.labels.toRefArray(); - + isFiltered = true; return labels.some((label) => filterLabelIds.includes(label.id)); }); } - return cardModels; + return [cardModels, cardModelsFull, isFiltered]; } deleteRelated() { diff --git a/client/src/selectors/lists.js b/client/src/selectors/lists.js index 1eddbd9..29690dc 100644 --- a/client/src/selectors/lists.js +++ b/client/src/selectors/lists.js @@ -33,8 +33,12 @@ export const makeSelectCardIdsByListId = () => if (!listModel) { return listModel; } - - return listModel.getFilteredOrderedCardsModelArray().map((cardModel) => cardModel.id); + const cardsModelArray = listModel.getFilteredOrderedCardsModelArray(); + return [ + cardsModelArray[0].map((cardModel) => cardModel.id), + cardsModelArray[1].map((cardModel) => cardModel.id), + cardsModelArray[2], + ]; }, ); From 66a14a76b1246ad02b0991022263c3b3dd6ff9bb Mon Sep 17 00:00:00 2001 From: RAR Date: Wed, 11 Jan 2023 18:05:31 +0100 Subject: [PATCH 3/8] fix: Fixed bug - wrong card placement after creation, cleanup --- client/src/containers/ListContainer.js | 2 +- client/src/models/List.js | 3 ++- client/src/selectors/core.js | 3 ++- client/src/selectors/lists.js | 11 ++++++----- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/client/src/containers/ListContainer.js b/client/src/containers/ListContainer.js index c3d47a9..e96b0f3 100755 --- a/client/src/containers/ListContainer.js +++ b/client/src/containers/ListContainer.js @@ -12,7 +12,7 @@ const makeMapStateToProps = () => { return (state, { id, index }) => { const { name, isPersisted } = selectListById(state, id); - const [cardIds, cardIdsFull, isFiltered] = selectCardIdsByListId(state, id); + const { cardIds, cardIdsFull, isFiltered } = selectCardIdsByListId(state, id); const currentUserMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); const isCurrentUserEditor = diff --git a/client/src/models/List.js b/client/src/models/List.js index 7fbef26..0e7e45e 100755 --- a/client/src/models/List.js +++ b/client/src/models/List.js @@ -91,6 +91,7 @@ export default class extends BaseModel { const filterUserIds = this.board.filterUsers.toRefArray().map((user) => user.id); const filterLabelIds = this.board.filterLabels.toRefArray().map((label) => label.id); let isFiltered = false; + if (filterUserIds.length > 0) { cardModels = cardModels.filter((cardModel) => { const users = cardModel.users.toRefArray(); @@ -107,7 +108,7 @@ export default class extends BaseModel { }); } - return [cardModels, cardModelsFull, isFiltered]; + return { cardModels, cardModelsFull, isFiltered }; } deleteRelated() { diff --git a/client/src/selectors/core.js b/client/src/selectors/core.js index 0ae4663..65099d3 100755 --- a/client/src/selectors/core.js +++ b/client/src/selectors/core.js @@ -93,7 +93,8 @@ export const selectNextCardPosition = createSelector( return listModel; } - return nextPosition(listModel.getFilteredOrderedCardsModelArray(), index, excludedId); + // eslint-disable-next-line prettier/prettier + return nextPosition(listModel.getFilteredOrderedCardsModelArray().cardModels, index, excludedId); }, ); diff --git a/client/src/selectors/lists.js b/client/src/selectors/lists.js index 29690dc..4ab0abf 100644 --- a/client/src/selectors/lists.js +++ b/client/src/selectors/lists.js @@ -33,12 +33,13 @@ export const makeSelectCardIdsByListId = () => if (!listModel) { return listModel; } + const cardsModelArray = listModel.getFilteredOrderedCardsModelArray(); - return [ - cardsModelArray[0].map((cardModel) => cardModel.id), - cardsModelArray[1].map((cardModel) => cardModel.id), - cardsModelArray[2], - ]; + return { + cardIds: cardsModelArray.cardModels.map((cardModel) => cardModel.id), + cardIdsFull: cardsModelArray.cardModelsFull.map((cardModel) => cardModel.id), + isFiltered: cardsModelArray.isFiltered, + }; }, ); From e009ceaccd63477bd597e818dfda988174cf4010 Mon Sep 17 00:00:00 2001 From: RAR Date: Wed, 11 Jan 2023 23:45:52 +0100 Subject: [PATCH 4/8] feat: Added card counts for boards --- client/src/components/BoardActions/BoardActions.jsx | 9 +++++++++ .../src/components/BoardActions/BoardActions.module.scss | 5 +++++ client/src/containers/BoardActionsContainer.js | 6 ++++++ 3 files changed, 20 insertions(+) diff --git a/client/src/components/BoardActions/BoardActions.jsx b/client/src/components/BoardActions/BoardActions.jsx index 0f1d552..5aa1db7 100644 --- a/client/src/components/BoardActions/BoardActions.jsx +++ b/client/src/components/BoardActions/BoardActions.jsx @@ -1,6 +1,8 @@ import React from 'react'; import PropTypes from 'prop-types'; +import { useTranslation } from 'react-i18next'; +import classNames from 'classnames'; import Filters from './Filters'; import Memberships from '../Memberships'; import BoardMembershipPermissionsSelectStep from '../BoardMembershipPermissionsSelectStep'; @@ -9,6 +11,7 @@ import styles from './BoardActions.module.scss'; const BoardActions = React.memo( ({ + cardCount, memberships, labels, filterUsers, @@ -28,9 +31,14 @@ const BoardActions = React.memo( onLabelMove, onLabelDelete, }) => { + const [t] = useTranslation(); + return (
+
+ {cardCount} {[cardCount !== 1 ? t('common.cards') : t('common.card')]} +
{ + const listIds = selectors.selectListIdsForCurrentBoard(state); + const listCardsCount = listIds.map( + (list) => selectors.selectCardIdsByListId(state, list).cardIdsFull.length, + ); + const cardCount = listCardsCount.reduce((sum, count) => sum + count, 0); const allUsers = selectors.selectUsers(state); const isCurrentUserManager = selectors.selectIsCurrentUserManagerForCurrentProject(state); const memberships = selectors.selectMembershipsForCurrentBoard(state); @@ -19,6 +24,7 @@ const mapStateToProps = (state) => { !!currentUserMembership && currentUserMembership.role === BoardMembershipRoles.EDITOR; return { + cardCount, memberships, labels, filterUsers, From 7cdac9ca9f87bb97939df351ffde30ce4ccaffbd Mon Sep 17 00:00:00 2001 From: RAR Date: Thu, 12 Jan 2023 22:19:17 +0100 Subject: [PATCH 5/8] feat: Added column collapsing with card counts support --- client/src/components/Board/ListAdd.jsx | 1 + client/src/components/List/List.jsx | 79 +++++++++++++++++-- client/src/components/List/List.module.scss | 61 ++++++++++++-- client/src/containers/ListContainer.js | 3 +- client/src/models/List.js | 1 + server/api/controllers/lists/create.js | 6 +- server/api/controllers/lists/update.js | 5 +- server/api/models/List.js | 5 ++ .../20230112022500_add_list_isCollapsed.js | 9 +++ 9 files changed, 152 insertions(+), 18 deletions(-) create mode 100644 server/db/migrations/20230112022500_add_list_isCollapsed.js diff --git a/client/src/components/Board/ListAdd.jsx b/client/src/components/Board/ListAdd.jsx index 7fc1e49..7160b7d 100755 --- a/client/src/components/Board/ListAdd.jsx +++ b/client/src/components/Board/ListAdd.jsx @@ -10,6 +10,7 @@ import styles from './ListAdd.module.scss'; const DEFAULT_DATA = { name: '', + isCollapsed: false, }; const ListAdd = React.memo(({ onCreate, onClose }) => { diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index 5396f1b..6d16ef6 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -16,14 +16,22 @@ import styles from './List.module.scss'; const List = React.memo( // eslint-disable-next-line prettier/prettier - ({ id, index, name, isPersisted, isFiltered, cardIds, cardIdsFull, canEdit, onUpdate, onDelete, onCardCreate }) => { + ({ id, index, name, isPersisted, isCollapsed, isFiltered, cardIds, cardIdsFull, canEdit, onUpdate, onDelete, onCardCreate }) => { const [t] = useTranslation(); const [isAddCardOpened, setIsAddCardOpened] = useState(false); const nameEdit = useRef(null); const listWrapper = useRef(null); - const handleHeaderClick = useCallback(() => { + const handleToggleCollapseClick = useCallback(() => { + if (isPersisted && canEdit) { + onUpdate({ + isCollapsed: !isCollapsed, + }); + } + }, [isPersisted, canEdit, onUpdate, isCollapsed]); + + const handleHeaderNameClick = useCallback(() => { if (isPersisted && canEdit) { nameEdit.current.open(); } @@ -97,6 +105,45 @@ const List = React.memo( ); }; + if (isCollapsed) { + return ( + + {({ innerRef, draggableProps, dragHandleProps }) => ( +
+
+
+ {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, + jsx-a11y/no-static-element-interactions */} +
+ +
+
{name}
+
{cardsCountText()}
+
+
+
+ )} +
+ ); + } return ( {({ innerRef, draggableProps, dragHandleProps }) => ( @@ -107,15 +154,30 @@ const List = React.memo( className={styles.innerWrapper} >
- {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, - jsx-a11y/no-static-element-interactions */}
+ {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, + jsx-a11y/no-static-element-interactions */} +
+ +
-
{name}
+ {/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, + jsx-a11y/no-static-element-interactions */} +
+ {name} +
{isPersisted && canEdit && ( )} -
{cardsCountText()}
+
{cardsCountText()}
{ const selectCardIdsByListId = selectors.makeSelectCardIdsByListId(); return (state, { id, index }) => { - const { name, isPersisted } = selectListById(state, id); + const { name, isPersisted, isCollapsed } = selectListById(state, id); const { cardIds, cardIdsFull, isFiltered } = selectCardIdsByListId(state, id); const currentUserMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); @@ -22,6 +22,7 @@ const makeMapStateToProps = () => { id, index, name, + isCollapsed, isPersisted, isFiltered, cardIds, diff --git a/client/src/models/List.js b/client/src/models/List.js index 0e7e45e..6f61416 100755 --- a/client/src/models/List.js +++ b/client/src/models/List.js @@ -10,6 +10,7 @@ export default class extends BaseModel { id: attr(), position: attr(), name: attr(), + isCollapsed: attr(), boardId: fk({ to: 'Board', as: 'board', diff --git a/server/api/controllers/lists/create.js b/server/api/controllers/lists/create.js index 9383f5b..49a9bce 100755 --- a/server/api/controllers/lists/create.js +++ b/server/api/controllers/lists/create.js @@ -22,6 +22,10 @@ module.exports = { type: 'string', required: true, }, + isCollapsed: { + type: 'boolean', + required: true, + }, }, exits: { @@ -53,7 +57,7 @@ module.exports = { throw Errors.NOT_ENOUGH_RIGHTS; } - const values = _.pick(inputs, ['position', 'name']); + const values = _.pick(inputs, ['position', 'name', 'isCollapsed']); const list = await sails.helpers.lists.createOne.with({ values: { diff --git a/server/api/controllers/lists/update.js b/server/api/controllers/lists/update.js index 2cb34e2..b6e1493 100755 --- a/server/api/controllers/lists/update.js +++ b/server/api/controllers/lists/update.js @@ -21,6 +21,9 @@ module.exports = { type: 'string', isNotEmptyString: true, }, + isCollapsed: { + type: 'boolean', + }, }, exits: { @@ -52,7 +55,7 @@ module.exports = { throw Errors.NOT_ENOUGH_RIGHTS; } - const values = _.pick(inputs, ['position', 'name']); + const values = _.pick(inputs, ['position', 'name', 'isCollapsed']); list = await sails.helpers.lists.updateOne.with({ values, diff --git a/server/api/models/List.js b/server/api/models/List.js index ce785b0..e2ee0ec 100755 --- a/server/api/models/List.js +++ b/server/api/models/List.js @@ -19,6 +19,11 @@ module.exports = { type: 'string', required: true, }, + isCollapsed: { + type: 'boolean', + required: true, + columnName: 'is_collapsed', + }, // ╔═╗╔╦╗╔╗ ╔═╗╔╦╗╔═╗ // ║╣ ║║║╠╩╗║╣ ║║╚═╗ diff --git a/server/db/migrations/20230112022500_add_list_isCollapsed.js b/server/db/migrations/20230112022500_add_list_isCollapsed.js new file mode 100644 index 0000000..00b0a25 --- /dev/null +++ b/server/db/migrations/20230112022500_add_list_isCollapsed.js @@ -0,0 +1,9 @@ +module.exports.up = (knex) => + knex.schema.alterTable('list', (table) => { + table.boolean('is_collapsed').notNullable().defaultTo(false); + }); + +module.exports.down = (knex) => + knex.schema.alterTable('list', (table) => { + table.dropColumn('is_collapsed'); + }); From 85c5e597fe5bf1e595e6518580e701e66f5ec3eb Mon Sep 17 00:00:00 2001 From: RAR Date: Fri, 13 Jan 2023 01:01:06 +0100 Subject: [PATCH 6/8] fix: Removed icon size to make size between small and large --- client/src/components/List/List.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index 6d16ef6..ba22317 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -133,7 +133,7 @@ const List = React.memo( )} onClick={handleToggleCollapseClick} > - +
{name}
{cardsCountText()}
@@ -167,7 +167,7 @@ const List = React.memo( )} onClick={handleToggleCollapseClick} > - +
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events, From fcb4e22f7fb59080f74b6ea029c9ea92087154a5 Mon Sep 17 00:00:00 2001 From: RAR Date: Fri, 13 Jan 2023 01:48:22 +0100 Subject: [PATCH 7/8] fix: Added ... when list name is too long (changed max to 4 lines) --- client/src/components/List/List.module.scss | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/src/components/List/List.module.scss b/client/src/components/List/List.module.scss index f2193d2..a7f6e08 100644 --- a/client/src/components/List/List.module.scss +++ b/client/src/components/List/List.module.scss @@ -119,11 +119,14 @@ color: #17394d; font-weight: bold; line-height: 20px; - max-height: 256px; + max-height: 82px; outline: none; overflow: hidden; overflow-wrap: break-word; word-break: break-word; + display: -webkit-box; + -webkit-line-clamp: 4; + -webkit-box-orient: vertical; } .headerNameCollapsed { From 4f8f4327fd06eb9e294ee3b23e9f3c6b32aa9828 Mon Sep 17 00:00:00 2001 From: RAR Date: Fri, 13 Jan 2023 02:33:21 +0100 Subject: [PATCH 8/8] fix: Separated cardIds, filteredCardIds, IsFiltered selectors --- client/src/components/List/List.jsx | 18 ++++---- .../src/containers/BoardActionsContainer.js | 4 +- client/src/containers/ListContainer.js | 10 +++-- client/src/models/List.js | 16 ++++--- client/src/selectors/core.js | 2 +- client/src/selectors/lists.js | 45 ++++++++++++++++--- 6 files changed, 68 insertions(+), 27 deletions(-) diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index ba22317..f56e1f3 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -16,7 +16,7 @@ import styles from './List.module.scss'; const List = React.memo( // eslint-disable-next-line prettier/prettier - ({ id, index, name, isPersisted, isCollapsed, isFiltered, cardIds, cardIdsFull, canEdit, onUpdate, onDelete, onCardCreate }) => { + ({ id, index, name, isPersisted, isCollapsed, cardIds, isFiltered, filteredCardIds, canEdit, onUpdate, onDelete, onCardCreate }) => { const [t] = useTranslation(); const [isAddCardOpened, setIsAddCardOpened] = useState(false); @@ -66,7 +66,7 @@ const List = React.memo( if (isAddCardOpened) { listWrapper.current.scrollTop = listWrapper.current.scrollHeight; } - }, [cardIds, isAddCardOpened]); + }, [filteredCardIds, isAddCardOpened]); const cardsNode = (
- {cardIds.map((cardId, cardIndex) => ( + {filteredCardIds.map((cardId, cardIndex) => ( ))} {placeholder} @@ -99,9 +99,9 @@ const List = React.memo( return ( [ isFiltered - ? `${cardIds.length} ${t('common.of')} ${cardIdsFull.length} ` - : `${cardIdsFull.length} `, - ] + [cardIdsFull.length !== 1 ? t('common.cards') : t('common.card')] + ? `${filteredCardIds.length} ${t('common.of')} ${cardIds.length} ` + : `${cardIds.length} `, + ] + [cardIds.length !== 1 ? t('common.cards') : t('common.card')] ); }; @@ -210,7 +210,7 @@ const List = React.memo( > - {cardIds.length > 0 ? t('action.addAnotherCard') : t('action.addCard')} + {filteredCardIds.length > 0 ? t('action.addAnotherCard') : t('action.addCard')} )} @@ -228,9 +228,9 @@ List.propTypes = { name: PropTypes.string.isRequired, isCollapsed: PropTypes.bool.isRequired, isPersisted: PropTypes.bool.isRequired, - isFiltered: PropTypes.bool.isRequired, cardIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types - cardIdsFull: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types + isFiltered: PropTypes.bool.isRequired, + filteredCardIds: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types canEdit: PropTypes.bool.isRequired, onUpdate: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired, diff --git a/client/src/containers/BoardActionsContainer.js b/client/src/containers/BoardActionsContainer.js index 76c904d..b7d568e 100644 --- a/client/src/containers/BoardActionsContainer.js +++ b/client/src/containers/BoardActionsContainer.js @@ -8,9 +8,7 @@ import BoardActions from '../components/BoardActions'; const mapStateToProps = (state) => { const listIds = selectors.selectListIdsForCurrentBoard(state); - const listCardsCount = listIds.map( - (list) => selectors.selectCardIdsByListId(state, list).cardIdsFull.length, - ); + const listCardsCount = listIds.map((list) => selectors.selectCardIdsByListId(state, list).length); const cardCount = listCardsCount.reduce((sum, count) => sum + count, 0); const allUsers = selectors.selectUsers(state); const isCurrentUserManager = selectors.selectIsCurrentUserManagerForCurrentProject(state); diff --git a/client/src/containers/ListContainer.js b/client/src/containers/ListContainer.js index 8f1ae22..498fe2b 100755 --- a/client/src/containers/ListContainer.js +++ b/client/src/containers/ListContainer.js @@ -9,10 +9,14 @@ import List from '../components/List'; const makeMapStateToProps = () => { const selectListById = selectors.makeSelectListById(); const selectCardIdsByListId = selectors.makeSelectCardIdsByListId(); + const selectIsFilteredByListId = selectors.makeSelectIsFilteredByListId(); + const selectFilteredCardIdsByListId = selectors.makeSelectFilteredCardIdsByListId(); return (state, { id, index }) => { const { name, isPersisted, isCollapsed } = selectListById(state, id); - const { cardIds, cardIdsFull, isFiltered } = selectCardIdsByListId(state, id); + const cardIds = selectCardIdsByListId(state, id); + const isFiltered = selectIsFilteredByListId(state, id); + const filteredCardIds = selectFilteredCardIdsByListId(state, id); const currentUserMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state); const isCurrentUserEditor = @@ -24,9 +28,9 @@ const makeMapStateToProps = () => { name, isCollapsed, isPersisted, - isFiltered, cardIds, - cardIdsFull, + isFiltered, + filteredCardIds, canEdit: isCurrentUserEditor, }; }; diff --git a/client/src/models/List.js b/client/src/models/List.js index 6f61416..b9973f1 100755 --- a/client/src/models/List.js +++ b/client/src/models/List.js @@ -85,18 +85,25 @@ export default class extends BaseModel { return this.cards.orderBy('position'); } + getOrderedCardsModelArray() { + return this.getOrderedCardsQuerySet().toModelArray(); + } + + getIsFiltered() { + const filterUserIds = this.board.filterUsers.toRefArray().map((user) => user.id); + const filterLabelIds = this.board.filterLabels.toRefArray().map((label) => label.id); + return filterUserIds.length > 0 || filterLabelIds.length > 0; + } + getFilteredOrderedCardsModelArray() { let cardModels = this.getOrderedCardsQuerySet().toModelArray(); - const cardModelsFull = cardModels; const filterUserIds = this.board.filterUsers.toRefArray().map((user) => user.id); const filterLabelIds = this.board.filterLabels.toRefArray().map((label) => label.id); - let isFiltered = false; if (filterUserIds.length > 0) { cardModels = cardModels.filter((cardModel) => { const users = cardModel.users.toRefArray(); - isFiltered = true; return users.some((user) => filterUserIds.includes(user.id)); }); } @@ -104,12 +111,11 @@ export default class extends BaseModel { if (filterLabelIds.length > 0) { cardModels = cardModels.filter((cardModel) => { const labels = cardModel.labels.toRefArray(); - isFiltered = true; return labels.some((label) => filterLabelIds.includes(label.id)); }); } - return { cardModels, cardModelsFull, isFiltered }; + return cardModels; } deleteRelated() { diff --git a/client/src/selectors/core.js b/client/src/selectors/core.js index 65099d3..1d15a1c 100755 --- a/client/src/selectors/core.js +++ b/client/src/selectors/core.js @@ -94,7 +94,7 @@ export const selectNextCardPosition = createSelector( } // eslint-disable-next-line prettier/prettier - return nextPosition(listModel.getFilteredOrderedCardsModelArray().cardModels, index, excludedId); + return nextPosition(listModel.getFilteredOrderedCardsModelArray(), index, excludedId); }, ); diff --git a/client/src/selectors/lists.js b/client/src/selectors/lists.js index 4ab0abf..e918241 100644 --- a/client/src/selectors/lists.js +++ b/client/src/selectors/lists.js @@ -34,20 +34,53 @@ export const makeSelectCardIdsByListId = () => return listModel; } - const cardsModelArray = listModel.getFilteredOrderedCardsModelArray(); - return { - cardIds: cardsModelArray.cardModels.map((cardModel) => cardModel.id), - cardIdsFull: cardsModelArray.cardModelsFull.map((cardModel) => cardModel.id), - isFiltered: cardsModelArray.isFiltered, - }; + return listModel.getOrderedCardsModelArray().map((cardModel) => cardModel.id); }, ); export const selectCardIdsByListId = makeSelectCardIdsByListId(); +export const makeSelectIsFilteredByListId = () => + createSelector( + orm, + (_, id) => id, + ({ List }, id) => { + const listModel = List.withId(id); + + if (!listModel) { + return listModel; + } + + return listModel.getIsFiltered(); + }, + ); + +export const selectIsFilteredByListId = makeSelectIsFilteredByListId(); + +export const makeSelectFilteredCardIdsByListId = () => + createSelector( + orm, + (_, id) => id, + ({ List }, id) => { + const listModel = List.withId(id); + + if (!listModel) { + return listModel; + } + + return listModel.getFilteredOrderedCardsModelArray().map((cardModel) => cardModel.id); + }, + ); + +export const selectFilteredCardIdsByListId = makeSelectFilteredCardIdsByListId(); + export default { makeSelectListById, selectListById, makeSelectCardIdsByListId, selectCardIdsByListId, + makeSelectIsFilteredByListId, + selectIsFilteredByListId, + makeSelectFilteredCardIdsByListId, + selectFilteredCardIdsByListId, };