1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-18 20:59:44 +02:00
This commit is contained in:
Symon Baikov 2025-07-18 04:03:48 +02:00 committed by GitHub
commit 05458d629a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 84 additions and 0 deletions

View file

@ -147,6 +147,14 @@ const Filters = React.memo(() => {
const isSearchActive = search || isSearchFocused; const isSearchActive = search || isSearchFocused;
const handleNoMemberClick = useCallback(() => {
if (board.filterNoMember) {
dispatch(entryActions.removeNoMemberFromFilterInCurrentBoard());
} else {
dispatch(entryActions.setNoMemberToFilterInCurrentBoard());
}
}, [dispatch, board.filterNoMember]);
return ( return (
<> <>
<span className={styles.filter}> <span className={styles.filter}>
@ -161,6 +169,13 @@ const Filters = React.memo(() => {
{userIds.length === 0 && <span className={styles.filterLabel}>{t('common.all')}</span>} {userIds.length === 0 && <span className={styles.filterLabel}>{t('common.all')}</span>}
</button> </button>
</BoardMembershipsPopup> </BoardMembershipsPopup>
<button
type="button"
className={classNames(styles.filterButton, styles.filterLabel)}
onClick={handleNoMemberClick}
>
{t('common.noMember')}
</button>
{userIds.length === 0 && withCurrentUserSelector && ( {userIds.length === 0 && withCurrentUserSelector && (
<button type="button" className={styles.filterButton} onClick={handleCurrentUserSelect}> <button type="button" className={styles.filterButton} onClick={handleCurrentUserSelect}>
<span className={styles.filterLabel}> <span className={styles.filterLabel}>

View file

@ -216,6 +216,9 @@ export default {
LABEL_TO_BOARD_FILTER_ADD: 'LABEL_TO_BOARD_FILTER_ADD', LABEL_TO_BOARD_FILTER_ADD: 'LABEL_TO_BOARD_FILTER_ADD',
LABEL_FROM_BOARD_FILTER_REMOVE: 'LABEL_FROM_BOARD_FILTER_REMOVE', LABEL_FROM_BOARD_FILTER_REMOVE: 'LABEL_FROM_BOARD_FILTER_REMOVE',
NO_MEMBER_TO_BOARD_FILTER_SET: 'NO_MEMBER_TO_BOARD_FILTER_SET',
NO_MEMBER_FROM_BOARD_FILTER_REMOVE: 'NO_MEMBER_FROM_BOARD_FILTER_REMOVE',
/* Lists */ /* Lists */
LIST_CREATE: 'LIST_CREATE', LIST_CREATE: 'LIST_CREATE',

View file

@ -285,4 +285,9 @@ export default {
NOTIFICATION_SERVICE_TEST: `${PREFIX}/NOTIFICATION_SERVICE_TEST`, NOTIFICATION_SERVICE_TEST: `${PREFIX}/NOTIFICATION_SERVICE_TEST`,
NOTIFICATION_SERVICE_DELETE: `${PREFIX}/NOTIFICATION_SERVICE_DELETE`, NOTIFICATION_SERVICE_DELETE: `${PREFIX}/NOTIFICATION_SERVICE_DELETE`,
NOTIFICATION_SERVICE_DELETE_HANDLE: `${PREFIX}/NOTIFICATION_SERVICE_DELETE_HANDLE`, NOTIFICATION_SERVICE_DELETE_HANDLE: `${PREFIX}/NOTIFICATION_SERVICE_DELETE_HANDLE`,
/* New member types */
NO_MEMBER_TO_FILTER_IN_CURRENT_BOARD_SET: `${PREFIX}/NO_MEMBER_TO_FILTER_IN_CURRENT_BOARD_SET`,
NO_MEMBER_FROM_FILTER_IN_CURRENT_BOARD_REMOVE: `${PREFIX}/NO_MEMBER_FROM_FILTER_IN_CURRENT_BOARD_REMOVE`,
}; };

View file

@ -93,6 +93,14 @@ const handleBoardDelete = (board) => ({
}, },
}); });
const setNoMemberToFilterInCurrentBoard = () => ({
type: EntryActionTypes.NO_MEMBER_TO_FILTER_IN_CURRENT_BOARD_SET,
});
const removeNoMemberFromFilterInCurrentBoard = () => ({
type: EntryActionTypes.NO_MEMBER_FROM_FILTER_IN_CURRENT_BOARD_REMOVE,
});
export default { export default {
createBoardInCurrentProject, createBoardInCurrentProject,
handleBoardCreate, handleBoardCreate,
@ -106,4 +114,6 @@ export default {
searchInCurrentBoard, searchInCurrentBoard,
deleteBoard, deleteBoard,
handleBoardDelete, handleBoardDelete,
setNoMemberToFilterInCurrentBoard,
removeNoMemberFromFilterInCurrentBoard,
}; };

View file

@ -222,6 +222,7 @@ export default {
noCardsFound: 'No cards found.', noCardsFound: 'No cards found.',
noConnectionToServer: 'No connection to server', noConnectionToServer: 'No connection to server',
noLists: 'No lists', noLists: 'No lists',
noMember: 'No member',
noProjects: 'No projects', noProjects: 'No projects',
noUnreadNotifications: 'No unread notifications.', noUnreadNotifications: 'No unread notifications.',
notifications: 'Notifications', notifications: 'Notifications',

View file

@ -61,6 +61,9 @@ export default class extends BaseModel {
}), }),
filterUsers: many('User', 'filterBoards'), filterUsers: many('User', 'filterBoards'),
filterLabels: many('Label', 'filterBoards'), filterLabels: many('Label', 'filterBoards'),
filterNoMember: attr({
getDefault: () => false,
}),
}; };
static reducer({ type, payload }, Board) { static reducer({ type, payload }, Board) {
@ -268,6 +271,17 @@ export default class extends BaseModel {
}); });
break; break;
case ActionTypes.NO_MEMBER_TO_BOARD_FILTER_SET: {
const boardModel = Board.withId(payload.boardId);
boardModel.filterUsers.clear();
boardModel.update({ filterNoMember: true });
break;
}
case ActionTypes.NO_MEMBER_FROM_BOARD_FILTER_REMOVE: {
const boardModel = Board.withId(payload.boardId);
boardModel.update({ filterNoMember: false });
break;
}
default: default:
} }
} }
@ -387,6 +401,11 @@ export default class extends BaseModel {
}); });
} }
if (this.filterNoMember) {
cardModels = cardModels.filter((cardModel) => cardModel.users.toRefArray().length === 0);
return cardModels;
}
return cardModels; return cardModels;
} }

View file

@ -379,6 +379,11 @@ export default class extends BaseModel {
}); });
} }
if (this.board.filterNoMember) {
cardModels = cardModels.filter((cardModel) => cardModel.users.toRefArray().length === 0);
return cardModels;
}
return cardModels; return cardModels;
} }

View file

@ -245,6 +245,22 @@ export function* handleBoardDelete(board) {
} }
} }
export function* setNoMemberToFilterInCurrentBoard() {
const { boardId } = yield select(selectors.selectPath);
yield put({
type: ActionTypes.NO_MEMBER_TO_BOARD_FILTER_SET,
payload: { boardId },
});
}
export function* removeNoMemberFromFilterInCurrentBoard() {
const { boardId } = yield select(selectors.selectPath);
yield put({
type: ActionTypes.NO_MEMBER_FROM_BOARD_FILTER_REMOVE,
payload: { boardId },
});
}
export default { export default {
createBoard, createBoard,
createBoardInCurrentProject, createBoardInCurrentProject,
@ -261,4 +277,6 @@ export default {
searchInCurrentBoard, searchInCurrentBoard,
deleteBoard, deleteBoard,
handleBoardDelete, handleBoardDelete,
setNoMemberToFilterInCurrentBoard,
removeNoMemberFromFilterInCurrentBoard,
}; };

View file

@ -44,5 +44,13 @@ export default function* boardsWatchers() {
takeEvery(EntryActionTypes.BOARD_DELETE_HANDLE, ({ payload: { board } }) => takeEvery(EntryActionTypes.BOARD_DELETE_HANDLE, ({ payload: { board } }) =>
services.handleBoardDelete(board), services.handleBoardDelete(board),
), ),
takeEvery(
EntryActionTypes.NO_MEMBER_TO_FILTER_IN_CURRENT_BOARD_SET,
services.setNoMemberToFilterInCurrentBoard,
),
takeEvery(
EntryActionTypes.NO_MEMBER_FROM_FILTER_IN_CURRENT_BOARD_REMOVE,
services.removeNoMemberFromFilterInCurrentBoard,
),
]); ]);
} }