mirror of
https://github.com/plankanban/planka.git
synced 2025-12-26 17:25:03 +03:00
34
client/src/selectors/activities.js
Normal file
34
client/src/selectors/activities.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectActivityById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Activity }, id) => {
|
||||
const activityModel = Activity.withId(id);
|
||||
|
||||
if (!activityModel) {
|
||||
return activityModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...activityModel.ref,
|
||||
isPersisted: !isLocalId(activityModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectActivityById = makeSelectActivityById();
|
||||
|
||||
export default {
|
||||
makeSelectActivityById,
|
||||
selectActivityById,
|
||||
};
|
||||
@@ -1,6 +1,32 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectAttachmentById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Attachment }, id) => {
|
||||
const attachmentModel = Attachment.withId(id);
|
||||
|
||||
if (!attachmentModel) {
|
||||
return attachmentModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...attachmentModel.ref,
|
||||
isPersisted: !isLocalId(attachmentModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectAttachmentById = makeSelectAttachmentById();
|
||||
|
||||
export const selectIsAttachmentWithIdExists = createSelector(
|
||||
orm,
|
||||
@@ -9,5 +35,7 @@ export const selectIsAttachmentWithIdExists = createSelector(
|
||||
);
|
||||
|
||||
export default {
|
||||
makeSelectAttachmentById,
|
||||
selectAttachmentById,
|
||||
selectIsAttachmentWithIdExists,
|
||||
};
|
||||
|
||||
41
client/src/selectors/background-images.js
Normal file
41
client/src/selectors/background-images.js
Normal file
@@ -0,0 +1,41 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectBackgroundImageById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ BackgroundImage }, id) => {
|
||||
const backgroundImageModel = BackgroundImage.withId(id);
|
||||
|
||||
if (!backgroundImageModel) {
|
||||
return backgroundImageModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...backgroundImageModel.ref,
|
||||
isPersisted: !isLocalId(backgroundImageModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBackgroundImageById = makeSelectBackgroundImageById();
|
||||
|
||||
export const selectIsBackgroundImageWithIdExists = createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ BackgroundImage }, id) => BackgroundImage.idExists(id),
|
||||
);
|
||||
|
||||
export default {
|
||||
makeSelectBackgroundImageById,
|
||||
selectBackgroundImageById,
|
||||
selectIsBackgroundImageWithIdExists,
|
||||
};
|
||||
57
client/src/selectors/base-custom-field-groups.js
Normal file
57
client/src/selectors/base-custom-field-groups.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectBaseCustomFieldGroupById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ BaseCustomFieldGroup }, id) => {
|
||||
const baseCustomFieldGroupModel = BaseCustomFieldGroup.withId(id);
|
||||
|
||||
if (!baseCustomFieldGroupModel) {
|
||||
return baseCustomFieldGroupModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...baseCustomFieldGroupModel.ref,
|
||||
isPersisted: !isLocalId(baseCustomFieldGroupModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBaseCustomFieldGroupById = makeSelectBaseCustomFieldGroupById();
|
||||
|
||||
export const makeSelectCustomFieldsByBaseGroupId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ BaseCustomFieldGroup }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const baseCustomFieldGroupModel = BaseCustomFieldGroup.withId(id);
|
||||
|
||||
if (!baseCustomFieldGroupModel) {
|
||||
return baseCustomFieldGroupModel;
|
||||
}
|
||||
|
||||
return baseCustomFieldGroupModel.getCustomFieldsQuerySet().toRefArray();
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCustomFieldsByBaseGroupId = makeSelectCustomFieldsByBaseGroupId();
|
||||
|
||||
export default {
|
||||
makeSelectBaseCustomFieldGroupById,
|
||||
selectBaseCustomFieldGroupById,
|
||||
makeSelectCustomFieldsByBaseGroupId,
|
||||
selectCustomFieldsByBaseGroupId,
|
||||
};
|
||||
@@ -1,6 +1,12 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectBoardMembershipById = () =>
|
||||
createSelector(
|
||||
@@ -13,7 +19,10 @@ export const makeSelectBoardMembershipById = () =>
|
||||
return boardMembershipModel;
|
||||
}
|
||||
|
||||
return boardMembershipModel.ref;
|
||||
return {
|
||||
...boardMembershipModel.ref,
|
||||
isPersisted: !isLocalId(boardMembershipModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { selectPath } from './router';
|
||||
import { selectCurrentUserId } from './users';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
import { isListArchiveOrTrash } from '../utils/record-helpers';
|
||||
import { ListTypes } from '../constants/Enums';
|
||||
|
||||
export const makeSelectBoardById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
@@ -16,12 +24,98 @@ export const makeSelectBoardById = () =>
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.ref;
|
||||
return {
|
||||
...boardModel.ref,
|
||||
isPersisted: !isLocalId(boardModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBoardById = makeSelectBoardById();
|
||||
|
||||
export const makeSelectCurrentUserMembershipByBoardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Board }, id, currentUserId) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
const boardMembershipModel = boardModel.getMembershipModelByUserId(currentUserId);
|
||||
|
||||
if (!boardMembershipModel) {
|
||||
return boardMembershipModel;
|
||||
}
|
||||
|
||||
return boardMembershipModel.ref;
|
||||
},
|
||||
);
|
||||
|
||||
const selectCurrentUserMembershipByBoardId = makeSelectCurrentUserMembershipByBoardId();
|
||||
|
||||
export const makeSelectNotificationsTotalByBoardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Board }, id) => {
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.getUnreadNotificationsQuerySet().count();
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationsTotalByBoardId = makeSelectNotificationsTotalByBoardId();
|
||||
|
||||
export const makeSelectNotificationServiceIdsByBoardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Board }, id) => {
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel
|
||||
.getNotificationServicesQuerySet()
|
||||
.toRefArray()
|
||||
.map((notificationService) => notificationService.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationServiceIdsByBoardId = makeSelectNotificationServiceIdsByBoardId();
|
||||
|
||||
export const selectIsBoardWithIdAvailableForCurrentUser = createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Board, User }, id, currentUserId) => {
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
return boardModel.isAvailableForUser(currentUserModel);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
@@ -43,8 +137,7 @@ export const selectCurrentBoard = createSelector(
|
||||
export const selectMembershipsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Board }, id, currentUserId) => {
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
@@ -55,14 +148,35 @@ export const selectMembershipsForCurrentBoard = createSelector(
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.getOrderedMembershipsModelArray().map((boardMembershipModel) => ({
|
||||
...boardMembershipModel.ref,
|
||||
isPersisted: !isLocalId(boardMembershipModel.id),
|
||||
user: {
|
||||
...boardMembershipModel.user.ref,
|
||||
isCurrent: boardMembershipModel.user.id === currentUserId,
|
||||
},
|
||||
}));
|
||||
return boardModel
|
||||
.getMembershipsQuerySet()
|
||||
.toModelArray()
|
||||
.map((boardMembershipModel) => ({
|
||||
...boardMembershipModel.ref,
|
||||
isPersisted: !isLocalId(boardMembershipModel.id),
|
||||
user: boardMembershipModel.user.ref,
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
export const selectMemberUserIdsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel
|
||||
.getMembershipsQuerySet()
|
||||
.toModelArray()
|
||||
.map((boardMembershipModel) => boardMembershipModel.user.id);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -81,7 +195,7 @@ export const selectCurrentUserMembershipForCurrentBoard = createSelector(
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
const boardMembershipModel = boardModel.getMembershipModelForUser(currentUserId);
|
||||
const boardMembershipModel = boardModel.getMembershipModelByUserId(currentUserId);
|
||||
|
||||
if (!boardMembershipModel) {
|
||||
return boardMembershipModel;
|
||||
@@ -105,17 +219,59 @@ export const selectLabelsForCurrentBoard = createSelector(
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel
|
||||
.getOrderedLabelsQuerySet()
|
||||
.toRefArray()
|
||||
.map((label) => ({
|
||||
...label,
|
||||
isPersisted: !isLocalId(label.id),
|
||||
}));
|
||||
return boardModel.getLabelsQuerySet().toRefArray();
|
||||
},
|
||||
);
|
||||
|
||||
export const selectListIdsForCurrentBoard = createSelector(
|
||||
export const selectArchiveListIdForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
const listModel = boardModel.lists
|
||||
.filter({
|
||||
type: ListTypes.ARCHIVE,
|
||||
})
|
||||
.first();
|
||||
|
||||
return listModel.id;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectTrashListIdForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
const listModel = boardModel.lists
|
||||
.filter({
|
||||
type: ListTypes.TRASH,
|
||||
})
|
||||
.first();
|
||||
|
||||
return listModel.id;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFiniteListIdsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
@@ -130,13 +286,14 @@ export const selectListIdsForCurrentBoard = createSelector(
|
||||
}
|
||||
|
||||
return boardModel
|
||||
.getOrderedListsQuerySet()
|
||||
.getFiniteListsQuerySet()
|
||||
.toRefArray()
|
||||
.map((list) => list.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilterUsersForCurrentBoard = createSelector(
|
||||
// TODO: rename?
|
||||
export const selectAvailableListsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
@@ -150,11 +307,14 @@ export const selectFilterUsersForCurrentBoard = createSelector(
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.filterUsers.toRefArray();
|
||||
return boardModel
|
||||
.getListsQuerySet()
|
||||
.toRefArray()
|
||||
.filter((list) => !isListArchiveOrTrash(list));
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilterLabelsForCurrentBoard = createSelector(
|
||||
export const selectFilteredCardIdsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
@@ -168,11 +328,11 @@ export const selectFilterLabelsForCurrentBoard = createSelector(
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.filterLabels.toRefArray();
|
||||
return boardModel.getFilteredCardsModelArray().map((cardModel) => cardModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilterTextForCurrentBoard = createSelector(
|
||||
export const selectCustomFieldGroupIdsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
@@ -186,7 +346,76 @@ export const selectFilterTextForCurrentBoard = createSelector(
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.filterText;
|
||||
return boardModel
|
||||
.getCustomFieldGroupsQuerySet()
|
||||
.toRefArray()
|
||||
.map((customFieldGroup) => customFieldGroup.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCustomFieldGroupsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel
|
||||
.getCustomFieldGroupsQuerySet()
|
||||
.toModelArray()
|
||||
.map((customFieldGroupModel) => {
|
||||
if (!customFieldGroupModel.name) {
|
||||
return {
|
||||
...customFieldGroupModel.ref,
|
||||
name: customFieldGroupModel.baseCustomFieldGroup.name,
|
||||
};
|
||||
}
|
||||
|
||||
return customFieldGroupModel.ref;
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilterUserIdsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.filterUsers.toRefArray().map((user) => user.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilterLabelIdsForCurrentBoard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return boardModel.filterLabels.toRefArray().map((label) => label.id);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -199,13 +428,26 @@ export const selectIsBoardWithIdExists = createSelector(
|
||||
export default {
|
||||
makeSelectBoardById,
|
||||
selectBoardById,
|
||||
makeSelectCurrentUserMembershipByBoardId,
|
||||
selectCurrentUserMembershipByBoardId,
|
||||
makeSelectNotificationsTotalByBoardId,
|
||||
selectNotificationsTotalByBoardId,
|
||||
makeSelectNotificationServiceIdsByBoardId,
|
||||
selectNotificationServiceIdsByBoardId,
|
||||
selectIsBoardWithIdAvailableForCurrentUser,
|
||||
selectCurrentBoard,
|
||||
selectMembershipsForCurrentBoard,
|
||||
selectMemberUserIdsForCurrentBoard,
|
||||
selectCurrentUserMembershipForCurrentBoard,
|
||||
selectLabelsForCurrentBoard,
|
||||
selectListIdsForCurrentBoard,
|
||||
selectFilterUsersForCurrentBoard,
|
||||
selectFilterLabelsForCurrentBoard,
|
||||
selectFilterTextForCurrentBoard,
|
||||
selectArchiveListIdForCurrentBoard,
|
||||
selectTrashListIdForCurrentBoard,
|
||||
selectFiniteListIdsForCurrentBoard,
|
||||
selectAvailableListsForCurrentBoard,
|
||||
selectFilteredCardIdsForCurrentBoard,
|
||||
selectCustomFieldGroupIdsForCurrentBoard,
|
||||
selectCustomFieldGroupsForCurrentBoard,
|
||||
selectFilterUserIdsForCurrentBoard,
|
||||
selectFilterLabelIdsForCurrentBoard,
|
||||
selectIsBoardWithIdExists,
|
||||
};
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { selectRecentCardId } from './core';
|
||||
import { selectPath } from './router';
|
||||
import { selectCurrentUserId } from './users';
|
||||
import { buildCustomFieldValueId } from '../models/CustomFieldValue';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectCardById = () =>
|
||||
@@ -18,7 +25,6 @@ export const makeSelectCardById = () =>
|
||||
|
||||
return {
|
||||
...cardModel.ref,
|
||||
coverUrl: cardModel.coverAttachment && cardModel.coverAttachment.coverUrl,
|
||||
isPersisted: !isLocalId(id),
|
||||
};
|
||||
},
|
||||
@@ -37,14 +43,15 @@ export const makeSelectCardIndexById = () =>
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
const cardModels = cardModel.list.getFilteredOrderedCardsModelArray();
|
||||
return cardModels.findIndex((cardModelItem) => cardModelItem.id === cardModel.id);
|
||||
return cardModel.list
|
||||
.getCardsModelArray()
|
||||
.findIndex((cardModelItem) => cardModelItem.id === cardModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCardIndexById = makeSelectCardIndexById();
|
||||
|
||||
export const makeSelectUsersByCardId = () =>
|
||||
export const makeSelectUserIdsByCardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
@@ -55,13 +62,13 @@ export const makeSelectUsersByCardId = () =>
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel.users.toRefArray();
|
||||
return cardModel.users.toRefArray().map((user) => user.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectUsersByCardId = makeSelectUsersByCardId();
|
||||
export const selectUserIdsByCardId = makeSelectUserIdsByCardId();
|
||||
|
||||
export const makeSelectLabelsByCardId = () =>
|
||||
export const makeSelectLabelIdsByCardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
@@ -72,13 +79,13 @@ export const makeSelectLabelsByCardId = () =>
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel.labels.toRefArray();
|
||||
return cardModel.labels.toRefArray().map((label) => label.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectLabelsByCardId = makeSelectLabelsByCardId();
|
||||
export const selectLabelIdsByCardId = makeSelectLabelIdsByCardId();
|
||||
|
||||
export const makeSelectTaskIdsByCardId = () =>
|
||||
export const makeSelectShownOnFrontOfCardTaskListIdsByCardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
@@ -89,31 +96,12 @@ export const makeSelectTaskIdsByCardId = () =>
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel
|
||||
.getOrderedTasksQuerySet()
|
||||
.toRefArray()
|
||||
.map((task) => task.id);
|
||||
return cardModel.getShownOnFrontOfCardTaskListsModelArray().map((taskList) => taskList.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectTaskIdsByCardId = makeSelectTaskIdsByCardId();
|
||||
|
||||
export const makeSelectTasksByCardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Card }, id) => {
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel.getOrderedTasksQuerySet().toRefArray();
|
||||
},
|
||||
);
|
||||
|
||||
export const selectTasksByCardId = makeSelectTasksByCardId();
|
||||
export const selectShownOnFrontOfCardTaskListIdsByCardId =
|
||||
makeSelectShownOnFrontOfCardTaskListIdsByCardId();
|
||||
|
||||
export const makeSelectAttachmentsTotalByCardId = () =>
|
||||
createSelector(
|
||||
@@ -132,24 +120,64 @@ export const makeSelectAttachmentsTotalByCardId = () =>
|
||||
|
||||
export const selectAttachmentsTotalByCardId = makeSelectAttachmentsTotalByCardId();
|
||||
|
||||
export const makeSelectLastActivityIdByCardId = () =>
|
||||
export const makeSelectShownOnFrontOfCardCustomFieldValueIdsByCardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Card }, id) => {
|
||||
({ Card, CustomFieldValue }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
const lastActivityModel = cardModel.getFilteredOrderedInCardActivitiesQuerySet().last();
|
||||
return [
|
||||
...cardModel.board
|
||||
.getCustomFieldGroupsQuerySet()
|
||||
.toModelArray()
|
||||
.flatMap((customFieldGroupModel) =>
|
||||
customFieldGroupModel
|
||||
.getShownOnFrontOfCardCustomFieldsModelArray()
|
||||
.flatMap((customFieldModel) => {
|
||||
const customFieldValue = CustomFieldValue.withId(
|
||||
buildCustomFieldValueId({
|
||||
cardId: id,
|
||||
customFieldGroupId: customFieldGroupModel.id,
|
||||
customFieldId: customFieldModel.id,
|
||||
}),
|
||||
);
|
||||
|
||||
return lastActivityModel && lastActivityModel.id;
|
||||
return customFieldValue ? customFieldValue.id : [];
|
||||
}),
|
||||
),
|
||||
...cardModel
|
||||
.getCustomFieldGroupsQuerySet()
|
||||
.toModelArray()
|
||||
.flatMap((customFieldGroupModel) =>
|
||||
customFieldGroupModel
|
||||
.getShownOnFrontOfCardCustomFieldsModelArray()
|
||||
.flatMap((customFieldModel) => {
|
||||
const customFieldValue = CustomFieldValue.withId(
|
||||
buildCustomFieldValueId({
|
||||
cardId: id,
|
||||
customFieldGroupId: customFieldGroupModel.id,
|
||||
customFieldId: customFieldModel.id,
|
||||
}),
|
||||
);
|
||||
|
||||
return customFieldValue ? customFieldValue.id : [];
|
||||
}),
|
||||
),
|
||||
];
|
||||
},
|
||||
);
|
||||
|
||||
export const selectLastActivityIdByCardId = makeSelectLastActivityIdByCardId();
|
||||
export const selectShownOnFrontOfCardCustomFieldValueIdsByCardId =
|
||||
makeSelectShownOnFrontOfCardCustomFieldValueIdsByCardId();
|
||||
|
||||
export const makeSelectNotificationsByCardId = () =>
|
||||
createSelector(
|
||||
@@ -185,6 +213,40 @@ export const makeSelectNotificationsTotalByCardId = () =>
|
||||
|
||||
export const selectNotificationsTotalByCardId = makeSelectNotificationsTotalByCardId();
|
||||
|
||||
export const makeSelectIsCardWithIdRecent = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectRecentCardId(state),
|
||||
({ Card }, id, recentCardId) => {
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return cardModel.id === recentCardId;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectIsCardWithIdRecent = makeSelectIsCardWithIdRecent();
|
||||
|
||||
export const selectIsCardWithIdAvailableForCurrentUser = createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Card, User }, id, currentUserId) => {
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
return cardModel.isAvailableForUser(currentUserModel);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
@@ -203,7 +265,7 @@ export const selectCurrentCard = createSelector(
|
||||
},
|
||||
);
|
||||
|
||||
export const selectUsersForCurrentCard = createSelector(
|
||||
export const selectUserIdsForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
@@ -217,11 +279,11 @@ export const selectUsersForCurrentCard = createSelector(
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel.users.toRefArray();
|
||||
return cardModel.users.toRefArray().map((user) => user.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectLabelsForCurrentCard = createSelector(
|
||||
export const selectLabelIdsForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
@@ -235,11 +297,11 @@ export const selectLabelsForCurrentCard = createSelector(
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel.labels.toRefArray();
|
||||
return cardModel.labels.toRefArray().map((label) => label.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectTasksForCurrentCard = createSelector(
|
||||
export const selectTaskListIdsForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
@@ -254,12 +316,55 @@ export const selectTasksForCurrentCard = createSelector(
|
||||
}
|
||||
|
||||
return cardModel
|
||||
.getOrderedTasksQuerySet()
|
||||
.getTaskListsQuerySet()
|
||||
.toRefArray()
|
||||
.map((task) => ({
|
||||
...task,
|
||||
isPersisted: !isLocalId(task.id),
|
||||
}));
|
||||
.map((taskList) => taskList.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectAttachmentIdsForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel
|
||||
.getAttachmentsQuerySet()
|
||||
.toRefArray()
|
||||
.map((attachment) => attachment.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectImageAttachmentIdsExceptCoverForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel
|
||||
.getAttachmentsQuerySet()
|
||||
.toModelArray()
|
||||
.filter(
|
||||
(attachmentModel) =>
|
||||
attachmentModel.data && attachmentModel.data.image && !attachmentModel.coveredCard,
|
||||
)
|
||||
.map((attachmentModel) => attachmentModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -277,47 +382,11 @@ export const selectAttachmentsForCurrentCard = createSelector(
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel
|
||||
.getOrderedAttachmentsQuerySet()
|
||||
.toRefArray()
|
||||
.map((attachment) => ({
|
||||
...attachment,
|
||||
isCover: attachment.id === cardModel.coverAttachmentId,
|
||||
isPersisted: !isLocalId(attachment.id),
|
||||
}));
|
||||
return cardModel.getAttachmentsQuerySet().toRefArray();
|
||||
},
|
||||
);
|
||||
|
||||
export const selectActivitiesForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Card }, id, currentUserId) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel
|
||||
.getFilteredOrderedInCardActivitiesQuerySet()
|
||||
.toModelArray()
|
||||
.map((activityModel) => ({
|
||||
...activityModel.ref,
|
||||
isPersisted: !isLocalId(activityModel.id),
|
||||
user: {
|
||||
...activityModel.user.ref,
|
||||
isCurrent: activityModel.user.id === currentUserId,
|
||||
},
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationIdsForCurrentCard = createSelector(
|
||||
export const selectCustomFieldGroupIdsForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
@@ -332,9 +401,64 @@ export const selectNotificationIdsForCurrentCard = createSelector(
|
||||
}
|
||||
|
||||
return cardModel
|
||||
.getUnreadNotificationsQuerySet()
|
||||
.getCustomFieldGroupsQuerySet()
|
||||
.toRefArray()
|
||||
.map((notification) => notification.id);
|
||||
.map((customFieldGroup) => customFieldGroup.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCommentIdsForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel.getCommentsModelArray().map((commentModel) => commentModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectActivityIdsForCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
({ Card }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return cardModel.getActivitiesModelArray().map((activity) => activity.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectIsCurrentUserInCurrentCard = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).cardId,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Card }, id, currentUserId) => {
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const cardModel = Card.withId(id);
|
||||
|
||||
if (!cardModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return cardModel.hasUserWithId(currentUserId);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -343,27 +467,32 @@ export default {
|
||||
selectCardById,
|
||||
makeSelectCardIndexById,
|
||||
selectCardIndexById,
|
||||
makeSelectUsersByCardId,
|
||||
selectUsersByCardId,
|
||||
makeSelectLabelsByCardId,
|
||||
selectLabelsByCardId,
|
||||
makeSelectTaskIdsByCardId,
|
||||
selectTaskIdsByCardId,
|
||||
makeSelectTasksByCardId,
|
||||
selectTasksByCardId,
|
||||
makeSelectUserIdsByCardId,
|
||||
selectUserIdsByCardId,
|
||||
makeSelectLabelIdsByCardId,
|
||||
selectLabelIdsByCardId,
|
||||
makeSelectShownOnFrontOfCardTaskListIdsByCardId,
|
||||
selectShownOnFrontOfCardTaskListIdsByCardId,
|
||||
makeSelectAttachmentsTotalByCardId,
|
||||
makeSelectShownOnFrontOfCardCustomFieldValueIdsByCardId,
|
||||
selectShownOnFrontOfCardCustomFieldValueIdsByCardId,
|
||||
selectAttachmentsTotalByCardId,
|
||||
makeSelectLastActivityIdByCardId,
|
||||
selectLastActivityIdByCardId,
|
||||
makeSelectNotificationsByCardId,
|
||||
selectNotificationsByCardId,
|
||||
makeSelectNotificationsTotalByCardId,
|
||||
selectNotificationsTotalByCardId,
|
||||
makeSelectIsCardWithIdRecent,
|
||||
selectIsCardWithIdRecent,
|
||||
selectIsCardWithIdAvailableForCurrentUser,
|
||||
selectCurrentCard,
|
||||
selectUsersForCurrentCard,
|
||||
selectLabelsForCurrentCard,
|
||||
selectTasksForCurrentCard,
|
||||
selectUserIdsForCurrentCard,
|
||||
selectLabelIdsForCurrentCard,
|
||||
selectTaskListIdsForCurrentCard,
|
||||
selectAttachmentIdsForCurrentCard,
|
||||
selectImageAttachmentIdsExceptCoverForCurrentCard,
|
||||
selectAttachmentsForCurrentCard,
|
||||
selectActivitiesForCurrentCard,
|
||||
selectNotificationIdsForCurrentCard,
|
||||
selectCustomFieldGroupIdsForCurrentCard,
|
||||
selectCommentIdsForCurrentCard,
|
||||
selectActivityIdsForCurrentCard,
|
||||
selectIsCurrentUserInCurrentCard,
|
||||
};
|
||||
|
||||
34
client/src/selectors/comments.js
Normal file
34
client/src/selectors/comments.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectCommentById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Comment }, id) => {
|
||||
const commentModel = Comment.withId(id);
|
||||
|
||||
if (!commentModel) {
|
||||
return commentModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...commentModel.ref,
|
||||
isPersisted: !isLocalId(commentModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCommentById = makeSelectCommentById();
|
||||
|
||||
export default {
|
||||
makeSelectCommentById,
|
||||
selectCommentById,
|
||||
};
|
||||
34
client/src/selectors/common.js
Normal file
34
client/src/selectors/common.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
export const selectIsSocketDisconnected = ({ socket: { isDisconnected } }) => isDisconnected;
|
||||
|
||||
export const selectIsInitializing = ({ common: { isInitializing } }) => isInitializing;
|
||||
|
||||
export const selectConfig = ({ common: { config } }) => config;
|
||||
|
||||
export const selectOidcConfig = (state) => selectConfig(state).oidc;
|
||||
|
||||
export const selectActiveUsersLimit = (state) => selectConfig(state).activeUsersLimit;
|
||||
|
||||
export const selectAccessToken = ({ auth: { accessToken } }) => accessToken;
|
||||
|
||||
export const selectAuthenticateForm = ({ ui: { authenticateForm } }) => authenticateForm;
|
||||
|
||||
export const selectUserCreateForm = ({ ui: { userCreateForm } }) => userCreateForm;
|
||||
|
||||
export const selectProjectCreateForm = ({ ui: { projectCreateForm } }) => projectCreateForm;
|
||||
|
||||
export default {
|
||||
selectIsSocketDisconnected,
|
||||
selectIsInitializing,
|
||||
selectConfig,
|
||||
selectOidcConfig,
|
||||
selectActiveUsersLimit,
|
||||
selectAccessToken,
|
||||
selectAuthenticateForm,
|
||||
selectUserCreateForm,
|
||||
selectProjectCreateForm,
|
||||
};
|
||||
129
client/src/selectors/core.js
Executable file → Normal file
129
client/src/selectors/core.js
Executable file → Normal file
@@ -1,122 +1,35 @@
|
||||
import { createSelector } from 'redux-orm';
|
||||
import isUndefined from 'lodash/isUndefined';
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import orm from '../orm';
|
||||
import Config from '../constants/Config';
|
||||
|
||||
export const selectAccessToken = ({ auth: { accessToken } }) => accessToken;
|
||||
export const selectIsContentFetching = ({ core: { isContentFetching } }) => isContentFetching;
|
||||
|
||||
export const selectIsLogouting = ({ core: { isLogouting } }) => isLogouting;
|
||||
|
||||
const nextPosition = (items, index, excludedId) => {
|
||||
const filteredItems = isUndefined(excludedId)
|
||||
? items
|
||||
: items.filter((item) => item.id !== excludedId);
|
||||
export const selectIsFavoritesEnabled = ({ core: { isFavoritesEnabled } }) => isFavoritesEnabled;
|
||||
|
||||
if (isUndefined(index)) {
|
||||
const lastItem = filteredItems[filteredItems.length - 1];
|
||||
export const selectIsEditModeEnabled = ({ core: { isEditModeEnabled } }) => isEditModeEnabled;
|
||||
|
||||
return (lastItem ? lastItem.position : 0) + Config.POSITION_GAP;
|
||||
}
|
||||
export const selectRecentCardId = ({ core: { recentCardId } }) => recentCardId;
|
||||
|
||||
const prevItem = filteredItems[index - 1];
|
||||
const nextItem = filteredItems[index];
|
||||
export const selectHomeView = ({ core: { homeView } }) => homeView;
|
||||
|
||||
const prevPosition = prevItem ? prevItem.position : 0;
|
||||
export const selectProjectsSearch = ({ core: { projectsSearch } }) => projectsSearch;
|
||||
|
||||
if (!nextItem) {
|
||||
return prevPosition + Config.POSITION_GAP;
|
||||
}
|
||||
export const selectProjectsOrder = ({ core: { projectsOrder } }) => projectsOrder;
|
||||
|
||||
return prevPosition + (nextItem.position - prevPosition) / 2;
|
||||
};
|
||||
|
||||
export const selectNextBoardPosition = createSelector(
|
||||
orm,
|
||||
(_, projectId) => projectId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Project }, projectId, index, excludedId) => {
|
||||
const projectModel = Project.withId(projectId);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
return nextPosition(projectModel.getOrderedBoardsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextLabelPosition = createSelector(
|
||||
orm,
|
||||
(_, boardId) => boardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Board }, boardId, index, excludedId) => {
|
||||
const boardModel = Board.withId(boardId);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return nextPosition(boardModel.getOrderedLabelsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextListPosition = createSelector(
|
||||
orm,
|
||||
(_, boardId) => boardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Board }, boardId, index, excludedId) => {
|
||||
const boardModel = Board.withId(boardId);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return nextPosition(boardModel.getOrderedListsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextCardPosition = createSelector(
|
||||
orm,
|
||||
(_, listId) => listId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ List }, listId, index, excludedId) => {
|
||||
const listModel = List.withId(listId);
|
||||
|
||||
if (!listModel) {
|
||||
return listModel;
|
||||
}
|
||||
|
||||
return nextPosition(listModel.getFilteredOrderedCardsModelArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextTaskPosition = createSelector(
|
||||
orm,
|
||||
(_, cardId) => cardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Card }, cardId, index, excludedId) => {
|
||||
const cardModel = Card.withId(cardId);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return nextPosition(cardModel.getOrderedTasksQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
export const selectIsHiddenProjectsVisible = ({ core: { isHiddenProjectsVisible } }) =>
|
||||
isHiddenProjectsVisible;
|
||||
|
||||
export default {
|
||||
selectAccessToken,
|
||||
selectIsContentFetching,
|
||||
selectIsLogouting,
|
||||
selectNextBoardPosition,
|
||||
selectNextLabelPosition,
|
||||
selectNextListPosition,
|
||||
selectNextCardPosition,
|
||||
selectNextTaskPosition,
|
||||
selectIsFavoritesEnabled,
|
||||
selectIsEditModeEnabled,
|
||||
selectRecentCardId,
|
||||
selectHomeView,
|
||||
selectProjectsSearch,
|
||||
selectProjectsOrder,
|
||||
selectIsHiddenProjectsVisible,
|
||||
};
|
||||
|
||||
85
client/src/selectors/custom-field-groups.js
Normal file
85
client/src/selectors/custom-field-groups.js
Normal file
@@ -0,0 +1,85 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectCustomFieldGroupById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ CustomFieldGroup }, id) => {
|
||||
const customFieldGroupModel = CustomFieldGroup.withId(id);
|
||||
|
||||
if (!customFieldGroupModel) {
|
||||
return customFieldGroupModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...customFieldGroupModel.ref,
|
||||
name: customFieldGroupModel.name || customFieldGroupModel.baseCustomFieldGroup.name,
|
||||
isPersisted: !isLocalId(customFieldGroupModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCustomFieldGroupById = makeSelectCustomFieldGroupById();
|
||||
|
||||
export const makeSelectCustomFieldIdsByGroupId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ CustomFieldGroup }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const customFieldGroupModel = CustomFieldGroup.withId(id);
|
||||
|
||||
if (!customFieldGroupModel) {
|
||||
return customFieldGroupModel;
|
||||
}
|
||||
|
||||
return customFieldGroupModel
|
||||
.getCustomFieldsModelArray()
|
||||
.map((customFieldModel) => customFieldModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCustomFieldIdsByGroupId = makeSelectCustomFieldIdsByGroupId();
|
||||
|
||||
export const makeSelectCustomFieldsByGroupId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ CustomFieldGroup }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const customFieldGroupModel = CustomFieldGroup.withId(id);
|
||||
|
||||
if (!customFieldGroupModel) {
|
||||
return customFieldGroupModel;
|
||||
}
|
||||
|
||||
return customFieldGroupModel
|
||||
.getCustomFieldsModelArray()
|
||||
.map((customFieldModel) => customFieldModel.ref);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCustomFieldsByGroupId = makeSelectCustomFieldsByGroupId();
|
||||
|
||||
export default {
|
||||
makeSelectCustomFieldGroupById,
|
||||
selectCustomFieldGroupById,
|
||||
makeSelectCustomFieldIdsByGroupId,
|
||||
selectCustomFieldIdsByGroupId,
|
||||
makeSelectCustomFieldsByGroupId,
|
||||
selectCustomFieldsByGroupId,
|
||||
};
|
||||
30
client/src/selectors/custom-field-values.js
Normal file
30
client/src/selectors/custom-field-values.js
Normal file
@@ -0,0 +1,30 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
|
||||
export const makeSelectCustomFieldValueById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ CustomFieldValue }, id) => {
|
||||
const customFieldValueModel = CustomFieldValue.withId(id);
|
||||
|
||||
if (!customFieldValueModel) {
|
||||
return customFieldValueModel;
|
||||
}
|
||||
|
||||
return customFieldValueModel.ref;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCustomFieldValueById = makeSelectCustomFieldValueById();
|
||||
|
||||
export default {
|
||||
makeSelectCustomFieldValueById,
|
||||
selectCustomFieldValueById,
|
||||
};
|
||||
34
client/src/selectors/custom-fields.js
Normal file
34
client/src/selectors/custom-fields.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectCustomFieldById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ CustomField }, id) => {
|
||||
const customFieldModel = CustomField.withId(id);
|
||||
|
||||
if (!customFieldModel) {
|
||||
return customFieldModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...customFieldModel.ref,
|
||||
isPersisted: !isLocalId(customFieldModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCustomFieldById = makeSelectCustomFieldById();
|
||||
|
||||
export default {
|
||||
makeSelectCustomFieldById,
|
||||
selectCustomFieldById,
|
||||
};
|
||||
@@ -1,33 +1,58 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import router from './router';
|
||||
import socket from './socket';
|
||||
import root from './root';
|
||||
import common from './common';
|
||||
import core from './core';
|
||||
import modals from './modals';
|
||||
import positioning from './positioning';
|
||||
import users from './users';
|
||||
import projects from './projects';
|
||||
import projectManagers from './project-managers';
|
||||
import backgroundImages from './background-images';
|
||||
import baseCustomFieldGroups from './base-custom-field-groups';
|
||||
import boards from './boards';
|
||||
import boardMemberships from './board-memberships';
|
||||
import labels from './labels';
|
||||
import lists from './lists';
|
||||
import cards from './cards';
|
||||
import taskLists from './task-lists';
|
||||
import tasks from './tasks';
|
||||
import attachments from './attachments';
|
||||
import customFieldGroups from './custom-field-groups';
|
||||
import customFields from './custom-fields';
|
||||
import customFieldValues from './custom-field-values';
|
||||
import comments from './comments';
|
||||
import activities from './activities';
|
||||
import notifications from './notifications';
|
||||
import notificationServices from './notification-services';
|
||||
|
||||
export default {
|
||||
...router,
|
||||
...socket,
|
||||
...root,
|
||||
...common,
|
||||
...core,
|
||||
...modals,
|
||||
...positioning,
|
||||
...users,
|
||||
...projects,
|
||||
...projectManagers,
|
||||
...backgroundImages,
|
||||
...baseCustomFieldGroups,
|
||||
...boards,
|
||||
...boardMemberships,
|
||||
...labels,
|
||||
...lists,
|
||||
...cards,
|
||||
...taskLists,
|
||||
...tasks,
|
||||
...attachments,
|
||||
...customFieldGroups,
|
||||
...customFields,
|
||||
...customFieldValues,
|
||||
...comments,
|
||||
...activities,
|
||||
...notifications,
|
||||
...notificationServices,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectLabelById = () =>
|
||||
createSelector(
|
||||
@@ -13,7 +19,10 @@ export const makeSelectLabelById = () =>
|
||||
return labelModel;
|
||||
}
|
||||
|
||||
return labelModel.ref;
|
||||
return {
|
||||
...labelModel.ref,
|
||||
isPersisted: !isLocalId(labelModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { selectPath } from './router';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
import { BoardContexts, ListTypes } from '../constants/Enums';
|
||||
|
||||
export const makeSelectListById = () =>
|
||||
createSelector(
|
||||
@@ -34,15 +41,121 @@ export const makeSelectCardIdsByListId = () =>
|
||||
return listModel;
|
||||
}
|
||||
|
||||
return listModel.getFilteredOrderedCardsModelArray().map((cardModel) => cardModel.id);
|
||||
return listModel.getCardsModelArray().map((cardModel) => cardModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCardIdsByListId = makeSelectCardIdsByListId();
|
||||
|
||||
export const makeSelectFilteredCardIdsByListId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ List }, id) => {
|
||||
const listModel = List.withId(id);
|
||||
|
||||
if (!listModel) {
|
||||
return listModel;
|
||||
}
|
||||
|
||||
return listModel.getFilteredCardsModelArray().map((cardModel) => cardModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilteredCardIdsByListId = makeSelectFilteredCardIdsByListId();
|
||||
|
||||
export const selectCurrentListId = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
if (boardModel.context === BoardContexts.BOARD) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const listModel = boardModel.lists
|
||||
.filter({
|
||||
type: boardModel.context || ListTypes.ACTIVE, // TODO: hack?
|
||||
})
|
||||
.first();
|
||||
|
||||
return listModel && listModel.id;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectCurrentList = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentListId(state),
|
||||
({ List }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const listModel = List.withId(id);
|
||||
|
||||
if (!listModel) {
|
||||
return listModel;
|
||||
}
|
||||
|
||||
return listModel.ref;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFirstFiniteListId = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).boardId,
|
||||
({ Board }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const boardModel = Board.withId(id);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
const listModel = boardModel.getFiniteListsQuerySet().first();
|
||||
return listModel && listModel.id;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilteredCardIdsForCurrentList = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentListId(state),
|
||||
({ List }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const listModel = List.withId(id);
|
||||
|
||||
if (!listModel) {
|
||||
return listModel;
|
||||
}
|
||||
|
||||
return listModel.getFilteredCardsModelArray().map((cardModel) => cardModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export default {
|
||||
makeSelectListById,
|
||||
selectListById,
|
||||
makeSelectCardIdsByListId,
|
||||
selectCardIdsByListId,
|
||||
makeSelectFilteredCardIdsByListId,
|
||||
selectFilteredCardIdsByListId,
|
||||
selectCurrentListId,
|
||||
selectCurrentList,
|
||||
selectFirstFiniteListId,
|
||||
selectFilteredCardIdsForCurrentList,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,56 @@
|
||||
export const selectCurrentModal = ({ core: { currentModal } }) => currentModal;
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { selectPath } from './router';
|
||||
import { selectCurrentUserId } from './users';
|
||||
import { isUserAdminOrProjectOwner } from '../utils/record-helpers';
|
||||
import ModalTypes from '../constants/ModalTypes';
|
||||
import { UserRoles } from '../constants/Enums';
|
||||
|
||||
export const selectCurrentModal = ({ core: { modal } }) => modal;
|
||||
|
||||
export const isCurrentModalAvailableForCurrentUser = createSelector(
|
||||
orm,
|
||||
selectCurrentModal,
|
||||
(state) => selectCurrentUserId(state),
|
||||
(state) => selectPath(state).projectId,
|
||||
({ User, Project, Board }, currentModal, currentUserId, currentProjectId) => {
|
||||
if (currentModal) {
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
|
||||
switch (currentModal.type) {
|
||||
case ModalTypes.ADMINISTRATION:
|
||||
return currentUserModel.role === UserRoles.ADMIN;
|
||||
case ModalTypes.ADD_PROJECT:
|
||||
return isUserAdminOrProjectOwner(currentUserModel);
|
||||
case ModalTypes.PROJECT_SETTINGS: {
|
||||
const projectModel = Project.withId(currentProjectId);
|
||||
return !!projectModel && projectModel.isExternalAccessibleForUser(currentUserModel);
|
||||
}
|
||||
case ModalTypes.BOARD_SETTINGS: {
|
||||
const boardModel = Board.withId(currentModal.params.id);
|
||||
|
||||
if (!boardModel || !boardModel.isAvailableForUser(currentUserModel)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return boardModel.project.hasManagerWithUserId(currentUserId);
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
);
|
||||
|
||||
export default {
|
||||
selectCurrentModal,
|
||||
isCurrentModalAvailableForCurrentUser,
|
||||
};
|
||||
|
||||
34
client/src/selectors/notification-services.js
Normal file
34
client/src/selectors/notification-services.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectNotificationServiceById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ NotificationService }, id) => {
|
||||
const notificationServiceModel = NotificationService.withId(id);
|
||||
|
||||
if (!notificationServiceModel) {
|
||||
return notificationServiceModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...notificationServiceModel.ref,
|
||||
isPersisted: !isLocalId(notificationServiceModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationServiceById = makeSelectNotificationServiceById();
|
||||
|
||||
export default {
|
||||
makeSelectNotificationServiceById,
|
||||
selectNotificationServiceById,
|
||||
};
|
||||
46
client/src/selectors/notifications.js
Normal file
46
client/src/selectors/notifications.js
Normal file
@@ -0,0 +1,46 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
|
||||
export const makeSelectNotificationById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Notification }, id) => {
|
||||
const notificationModel = Notification.withId(id);
|
||||
|
||||
if (!notificationModel) {
|
||||
return notificationModel;
|
||||
}
|
||||
|
||||
return notificationModel.ref;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationById = makeSelectNotificationById();
|
||||
|
||||
export const makeSelectNotificationIdsByCardId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Notification }, id) =>
|
||||
Notification.filter({
|
||||
cardId: id,
|
||||
})
|
||||
.toRefArray()
|
||||
.map((notification) => notification.id),
|
||||
);
|
||||
|
||||
export const selectNotificationIdsByCardId = makeSelectNotificationIdsByCardId();
|
||||
|
||||
export default {
|
||||
makeSelectNotificationById,
|
||||
selectNotificationById,
|
||||
makeSelectNotificationIdsByCardId,
|
||||
selectNotificationIdsByCardId,
|
||||
};
|
||||
213
client/src/selectors/positioning.js
Executable file
213
client/src/selectors/positioning.js
Executable file
@@ -0,0 +1,213 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import isUndefined from 'lodash/isUndefined';
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import Config from '../constants/Config';
|
||||
|
||||
const nextPosition = (items, index, excludedId) => {
|
||||
const filteredItems = isUndefined(excludedId)
|
||||
? items
|
||||
: items.filter((item) => item.id !== excludedId);
|
||||
|
||||
if (isUndefined(index)) {
|
||||
const lastItem = filteredItems[filteredItems.length - 1];
|
||||
return (lastItem ? lastItem.position : 0) + Config.POSITION_GAP;
|
||||
}
|
||||
|
||||
const prevItem = filteredItems[index - 1];
|
||||
const nextItem = filteredItems[index];
|
||||
|
||||
const prevPosition = prevItem ? prevItem.position : 0;
|
||||
|
||||
if (!nextItem) {
|
||||
return prevPosition + Config.POSITION_GAP;
|
||||
}
|
||||
|
||||
return prevPosition + (nextItem.position - prevPosition) / 2;
|
||||
};
|
||||
|
||||
export const selectNextBoardPosition = createSelector(
|
||||
orm,
|
||||
(_, projectId) => projectId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Project }, projectId, index, excludedId) => {
|
||||
const projectModel = Project.withId(projectId);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
return nextPosition(projectModel.getBoardsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextLabelPosition = createSelector(
|
||||
orm,
|
||||
(_, boardId) => boardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Board }, boardId, index, excludedId) => {
|
||||
const boardModel = Board.withId(boardId);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return nextPosition(boardModel.getLabelsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextListPosition = createSelector(
|
||||
orm,
|
||||
(_, boardId) => boardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Board }, boardId, index, excludedId) => {
|
||||
const boardModel = Board.withId(boardId);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return nextPosition(boardModel.getFiniteListsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextCardPosition = createSelector(
|
||||
orm,
|
||||
(_, listId) => listId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ List }, listId, index, excludedId) => {
|
||||
const listModel = List.withId(listId);
|
||||
|
||||
if (!listModel) {
|
||||
return listModel;
|
||||
}
|
||||
|
||||
return nextPosition(listModel.getFilteredCardsModelArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextTaskListPosition = createSelector(
|
||||
orm,
|
||||
(_, cardId) => cardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Card }, cardId, index, excludedId) => {
|
||||
const cardModel = Card.withId(cardId);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return nextPosition(cardModel.getTaskListsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextTaskPosition = createSelector(
|
||||
orm,
|
||||
(_, taskListId) => taskListId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ TaskList }, taskListId, index, excludedId) => {
|
||||
const taskListModel = TaskList.withId(taskListId);
|
||||
|
||||
if (!taskListModel) {
|
||||
return taskListModel;
|
||||
}
|
||||
|
||||
return nextPosition(taskListModel.getTasksQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextCustomFieldGroupPositionInBoard = createSelector(
|
||||
orm,
|
||||
(_, cardId) => cardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Board }, boardId, index, excludedId) => {
|
||||
const boardModel = Board.withId(boardId);
|
||||
|
||||
if (!boardModel) {
|
||||
return boardModel;
|
||||
}
|
||||
|
||||
return nextPosition(boardModel.getCustomFieldGroupsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextCustomFieldGroupPositionInCard = createSelector(
|
||||
orm,
|
||||
(_, cardId) => cardId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ Card }, cardId, index, excludedId) => {
|
||||
const cardModel = Card.withId(cardId);
|
||||
|
||||
if (!cardModel) {
|
||||
return cardModel;
|
||||
}
|
||||
|
||||
return nextPosition(cardModel.getCustomFieldGroupsQuerySet().toRefArray(), index, excludedId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextCustomFieldPositionInBaseGroup = createSelector(
|
||||
orm,
|
||||
(_, baseCustomFieldGroupId) => baseCustomFieldGroupId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ BaseCustomFieldGroup }, baseCustomFieldGroupId, index, excludedId) => {
|
||||
const baseCustomFieldGroupModel = BaseCustomFieldGroup.withId(baseCustomFieldGroupId);
|
||||
|
||||
if (!baseCustomFieldGroupModel) {
|
||||
return baseCustomFieldGroupModel;
|
||||
}
|
||||
|
||||
return nextPosition(
|
||||
baseCustomFieldGroupModel.getCustomFieldsQuerySet().toRefArray(),
|
||||
index,
|
||||
excludedId,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNextCustomFieldPositionInGroup = createSelector(
|
||||
orm,
|
||||
(_, customFieldGroupId) => customFieldGroupId,
|
||||
(_, __, index) => index,
|
||||
(_, __, ___, excludedId) => excludedId,
|
||||
({ CustomFieldGroup }, customFieldGroupId, index, excludedId) => {
|
||||
const customFieldGroupModel = CustomFieldGroup.withId(customFieldGroupId);
|
||||
|
||||
if (!customFieldGroupModel) {
|
||||
return customFieldGroupModel;
|
||||
}
|
||||
|
||||
return nextPosition(
|
||||
customFieldGroupModel.getCustomFieldsQuerySet().toRefArray(),
|
||||
index,
|
||||
excludedId,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default {
|
||||
selectNextBoardPosition,
|
||||
selectNextLabelPosition,
|
||||
selectNextListPosition,
|
||||
selectNextCardPosition,
|
||||
selectNextTaskListPosition,
|
||||
selectNextTaskPosition,
|
||||
selectNextCustomFieldGroupPositionInBoard,
|
||||
selectNextCustomFieldGroupPositionInCard,
|
||||
selectNextCustomFieldPositionInBaseGroup,
|
||||
selectNextCustomFieldPositionInGroup,
|
||||
};
|
||||
@@ -1,3 +1,8 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
@@ -5,6 +10,134 @@ import { selectPath } from './router';
|
||||
import { selectCurrentUserId } from './users';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectProjectById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ Project }, id) => {
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
return projectModel.ref;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectProjectById = makeSelectProjectById();
|
||||
|
||||
export const makeSelectBoardIdsByProjectId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project, User }, id, currentUserId) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
|
||||
return projectModel
|
||||
.getBoardsModelArrayAvailableForUser(currentUserModel)
|
||||
.map((boardModel) => boardModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBoardIdsByProjectId = makeSelectBoardIdsByProjectId();
|
||||
|
||||
export const makeSelectFirstBoardIdByProjectId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project, User }, id, currentUserId) => {
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
const boardsModels = projectModel.getBoardsModelArrayAvailableForUser(currentUserModel);
|
||||
|
||||
return boardsModels[0] && boardsModels[0].id;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFirstBoardIdByProjectId = makeSelectFirstBoardIdByProjectId();
|
||||
|
||||
export const makeSelectNotificationsTotalByProjectId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project, User }, id, currentUserId) => {
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
const boardsModels = projectModel.getBoardsModelArrayAvailableForUser(currentUserModel);
|
||||
|
||||
return boardsModels.reduce(
|
||||
(result, boardModel) => result + boardModel.getUnreadNotificationsQuerySet().count(),
|
||||
0,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationsTotalByProjectId = makeSelectNotificationsTotalByProjectId();
|
||||
|
||||
export const makeSelectIsProjectWithIdAvailableForCurrentUser = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project, User }, id, currentUserId) => {
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
return projectModel.isAvailableForUser(currentUserModel);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectIsProjectWithIdAvailableForCurrentUser =
|
||||
makeSelectIsProjectWithIdAvailableForCurrentUser();
|
||||
|
||||
export const makeSelectIsProjectWithIdExternalAccessibleForCurrentUser = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project, User }, id, currentUserId) => {
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
return projectModel.isExternalAccessibleForUser(currentUserModel);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectIsProjectWithIdExternalAccessibleForCurrentUser =
|
||||
makeSelectIsProjectWithIdExternalAccessibleForCurrentUser();
|
||||
|
||||
export const selectCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
@@ -26,8 +159,7 @@ export const selectCurrentProject = createSelector(
|
||||
export const selectManagersForCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project }, id, currentUserId) => {
|
||||
({ Project }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
@@ -39,24 +171,20 @@ export const selectManagersForCurrentProject = createSelector(
|
||||
}
|
||||
|
||||
return projectModel
|
||||
.getOrderedManagersQuerySet()
|
||||
.getManagersQuerySet()
|
||||
.toModelArray()
|
||||
.map((projectManagerModel) => ({
|
||||
...projectManagerModel.ref,
|
||||
isPersisted: !isLocalId(projectManagerModel.id),
|
||||
user: {
|
||||
...projectManagerModel.user.ref,
|
||||
isCurrent: projectManagerModel.user.id === currentUserId,
|
||||
},
|
||||
user: projectManagerModel.user.ref,
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBoardsForCurrentProject = createSelector(
|
||||
export const selectManagerUserIdsForCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project }, id, currentUserId) => {
|
||||
({ Project }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
@@ -68,14 +196,101 @@ export const selectBoardsForCurrentProject = createSelector(
|
||||
}
|
||||
|
||||
return projectModel
|
||||
.getOrderedBoardsModelArrayAvailableForUser(currentUserId)
|
||||
.map((boardModel) => ({
|
||||
...boardModel.ref,
|
||||
isPersisted: !isLocalId(boardModel.id),
|
||||
.getManagersQuerySet()
|
||||
.toRefArray()
|
||||
.map((projectManager) => projectManager.userId);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBackgroundImageIdsForCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
({ Project }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
return projectModel
|
||||
.getBackgroundImagesQuerySet()
|
||||
.toRefArray()
|
||||
.map((backgroundImage) => backgroundImage.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBaseCustomFieldGroupIdsForCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
({ Project }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
return projectModel
|
||||
.getBaseCustomFieldGroupsQuerySet()
|
||||
.toRefArray()
|
||||
.map((baseCustomFieldGroup) => baseCustomFieldGroup.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBaseCustomFieldGroupsForCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
({ Project }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
return projectModel
|
||||
.getBaseCustomFieldGroupsQuerySet()
|
||||
.toRefArray()
|
||||
.map((baseCustomFieldGroup) => ({
|
||||
...baseCustomFieldGroup,
|
||||
isPersisted: !isLocalId(baseCustomFieldGroup.id),
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
export const selectBoardIdsForCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project, User }, id, currentUserId) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const projectModel = Project.withId(id);
|
||||
|
||||
if (!projectModel) {
|
||||
return projectModel;
|
||||
}
|
||||
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
|
||||
return projectModel
|
||||
.getBoardsModelArrayAvailableForUser(currentUserModel)
|
||||
.map((boardModel) => boardModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectIsCurrentUserManagerForCurrentProject = createSelector(
|
||||
orm,
|
||||
(state) => selectPath(state).projectId,
|
||||
@@ -91,13 +306,29 @@ export const selectIsCurrentUserManagerForCurrentProject = createSelector(
|
||||
return false;
|
||||
}
|
||||
|
||||
return projectModel.hasManagerForUser(currentUserId);
|
||||
return projectModel.hasManagerWithUserId(currentUserId);
|
||||
},
|
||||
);
|
||||
|
||||
export default {
|
||||
makeSelectProjectById,
|
||||
selectProjectById,
|
||||
makeSelectBoardIdsByProjectId,
|
||||
selectBoardIdsByProjectId,
|
||||
makeSelectFirstBoardIdByProjectId,
|
||||
selectFirstBoardIdByProjectId,
|
||||
makeSelectNotificationsTotalByProjectId,
|
||||
selectNotificationsTotalByProjectId,
|
||||
makeSelectIsProjectWithIdAvailableForCurrentUser,
|
||||
selectIsProjectWithIdAvailableForCurrentUser,
|
||||
makeSelectIsProjectWithIdExternalAccessibleForCurrentUser,
|
||||
selectIsProjectWithIdExternalAccessibleForCurrentUser,
|
||||
selectCurrentProject,
|
||||
selectManagersForCurrentProject,
|
||||
selectBoardsForCurrentProject,
|
||||
selectManagerUserIdsForCurrentProject,
|
||||
selectBackgroundImageIdsForCurrentProject,
|
||||
selectBaseCustomFieldGroupIdsForCurrentProject,
|
||||
selectBaseCustomFieldGroupsForCurrentProject,
|
||||
selectBoardIdsForCurrentProject,
|
||||
selectIsCurrentUserManagerForCurrentProject,
|
||||
};
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
export const selectIsInitializing = ({ root: { isInitializing } }) => isInitializing;
|
||||
|
||||
export const selectConfig = ({ root: { config } }) => config;
|
||||
|
||||
export const selectOidcConfig = (state) => selectConfig(state).oidc;
|
||||
|
||||
export default {
|
||||
selectIsInitializing,
|
||||
selectConfig,
|
||||
selectOidcConfig,
|
||||
};
|
||||
@@ -1,3 +1,8 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector as createReselectSelector } from 'reselect';
|
||||
import { createSelector as createReduxOrmSelector } from 'redux-orm';
|
||||
|
||||
@@ -20,13 +25,15 @@ export const selectPath = createReduxOrmSelector(
|
||||
orm,
|
||||
selectPathsMatch,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ Project, Board, Card }, pathsMatch, currentUserId) => {
|
||||
({ User, Project, Board, Card }, pathsMatch, currentUserId) => {
|
||||
if (pathsMatch) {
|
||||
const currentUserModel = User.withId(currentUserId);
|
||||
|
||||
switch (pathsMatch.pattern.path) {
|
||||
case Paths.PROJECTS: {
|
||||
const projectModel = Project.withId(pathsMatch.params.id);
|
||||
|
||||
if (!projectModel || !projectModel.isAvailableForUser(currentUserId)) {
|
||||
if (!projectModel || !projectModel.isAvailableForUser(currentUserModel)) {
|
||||
return {
|
||||
projectId: null,
|
||||
};
|
||||
@@ -39,7 +46,7 @@ export const selectPath = createReduxOrmSelector(
|
||||
case Paths.BOARDS: {
|
||||
const boardModel = Board.withId(pathsMatch.params.id);
|
||||
|
||||
if (!boardModel || !boardModel.isAvailableForUser(currentUserId)) {
|
||||
if (!boardModel || !boardModel.isAvailableForUser(currentUserModel)) {
|
||||
return {
|
||||
boardId: null,
|
||||
projectId: null,
|
||||
@@ -54,7 +61,7 @@ export const selectPath = createReduxOrmSelector(
|
||||
case Paths.CARDS: {
|
||||
const cardModel = Card.withId(pathsMatch.params.id);
|
||||
|
||||
if (!cardModel || !cardModel.isAvailableForUser(currentUserId)) {
|
||||
if (!cardModel || !cardModel.isAvailableForUser(currentUserModel)) {
|
||||
return {
|
||||
cardId: null,
|
||||
boardId: null,
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export const selectIsSocketDisconnected = ({ socket: { isDisconnected } }) => isDisconnected;
|
||||
|
||||
export default {
|
||||
selectIsSocketDisconnected,
|
||||
};
|
||||
53
client/src/selectors/task-lists.js
Normal file
53
client/src/selectors/task-lists.js
Normal file
@@ -0,0 +1,53 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectTaskListById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ TaskList }, id) => {
|
||||
const taskListModel = TaskList.withId(id);
|
||||
|
||||
if (!taskListModel) {
|
||||
return taskListModel;
|
||||
}
|
||||
|
||||
return {
|
||||
...taskListModel.ref,
|
||||
isPersisted: !isLocalId(taskListModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
export const selectTaskListById = makeSelectTaskListById();
|
||||
|
||||
export const makeSelectTasksByTaskListId = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ TaskList }, id) => {
|
||||
const taskListModel = TaskList.withId(id);
|
||||
|
||||
if (!taskListModel) {
|
||||
return taskListModel;
|
||||
}
|
||||
|
||||
return taskListModel.getTasksQuerySet().toRefArray();
|
||||
},
|
||||
);
|
||||
|
||||
export const selectTasksByTaskListId = makeSelectTasksByTaskListId();
|
||||
|
||||
export default {
|
||||
makeSelectTaskListById,
|
||||
selectTaskListById,
|
||||
makeSelectTasksByTaskListId,
|
||||
selectTasksByTaskListId,
|
||||
};
|
||||
@@ -1,6 +1,12 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
|
||||
export const makeSelectTaskById = () =>
|
||||
createSelector(
|
||||
@@ -13,7 +19,10 @@ export const makeSelectTaskById = () =>
|
||||
return taskModel;
|
||||
}
|
||||
|
||||
return taskModel.ref;
|
||||
return {
|
||||
...taskModel.ref,
|
||||
isPersisted: !isLocalId(taskModel.id),
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -1,24 +1,75 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { createSelector } from 'redux-orm';
|
||||
|
||||
import orm from '../orm';
|
||||
import {
|
||||
selectIsFavoritesEnabled,
|
||||
selectIsHiddenProjectsVisible,
|
||||
selectProjectsOrder,
|
||||
selectProjectsSearch,
|
||||
} from './core';
|
||||
import { isLocalId } from '../utils/local-id';
|
||||
import { isUserAdminOrProjectOwner } from '../utils/record-helpers';
|
||||
import { STATIC_USER_BY_ID } from '../constants/StaticUsers';
|
||||
import { BoardMembershipRoles, ProjectGroups, ProjectOrders } from '../constants/Enums';
|
||||
|
||||
const ORDER_BY_ARGS_BY_PROJECTS_ORDER = {
|
||||
[ProjectOrders.ALPHABETICALLY]: [['name', 'id.length', 'id']],
|
||||
[ProjectOrders.BY_CREATION_TIME]: [['id', 'id.length']],
|
||||
};
|
||||
|
||||
export const selectCurrentUserId = ({ auth: { userId } }) => userId;
|
||||
|
||||
export const selectUsers = createSelector(orm, ({ User }) =>
|
||||
User.getOrderedUndeletedQuerySet().toRefArray(),
|
||||
);
|
||||
export const makeSelectUserById = () =>
|
||||
createSelector(
|
||||
orm,
|
||||
(_, id) => id,
|
||||
({ User }, id) => {
|
||||
if (STATIC_USER_BY_ID[id]) {
|
||||
return STATIC_USER_BY_ID[id];
|
||||
}
|
||||
|
||||
const userModel = User.withId(id);
|
||||
|
||||
if (!userModel) {
|
||||
return userModel;
|
||||
}
|
||||
|
||||
return userModel.ref;
|
||||
},
|
||||
);
|
||||
|
||||
export const selectUserById = makeSelectUserById();
|
||||
|
||||
export const selectUsersExceptCurrent = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ User }, id) =>
|
||||
User.getOrderedUndeletedQuerySet()
|
||||
User.getAllQuerySet()
|
||||
.exclude({
|
||||
id,
|
||||
})
|
||||
.toRefArray(),
|
||||
);
|
||||
|
||||
export const selectActiveUsers = createSelector(orm, ({ User }) =>
|
||||
User.getActiveQuerySet().toRefArray(),
|
||||
);
|
||||
|
||||
export const selectActiveUsersTotal = createSelector(orm, ({ User }) =>
|
||||
User.getActiveQuerySet().count(),
|
||||
);
|
||||
|
||||
export const selectActiveAdminOrProjectOwnerUsers = createSelector(orm, ({ User }) =>
|
||||
User.getActiveQuerySet()
|
||||
.filter((user) => isUserAdminOrProjectOwner(user))
|
||||
.toRefArray(),
|
||||
);
|
||||
|
||||
export const selectCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
@@ -37,7 +88,7 @@ export const selectCurrentUser = createSelector(
|
||||
},
|
||||
);
|
||||
|
||||
export const selectProjectsForCurrentUser = createSelector(
|
||||
export const selectProjectIdsForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ User }, id) => {
|
||||
@@ -51,26 +102,102 @@ export const selectProjectsForCurrentUser = createSelector(
|
||||
return userModel;
|
||||
}
|
||||
|
||||
return userModel.getOrderedAvailableProjectsModelArray().map((projectModel) => {
|
||||
const boardsModels = projectModel.getOrderedBoardsModelArrayAvailableForUser(userModel.id);
|
||||
|
||||
let notificationsTotal = 0;
|
||||
boardsModels.forEach((boardModel) => {
|
||||
boardModel.cards.toModelArray().forEach((cardModel) => {
|
||||
notificationsTotal += cardModel.getUnreadNotificationsQuerySet().count();
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
...projectModel.ref,
|
||||
notificationsTotal,
|
||||
firstBoardId: boardsModels[0] && boardsModels[0].id,
|
||||
};
|
||||
});
|
||||
return userModel.getProjectsModelArray().map((projectModel) => projectModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectProjectsToListsForCurrentUser = createSelector(
|
||||
export const selectFilteredProjectIdsForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
(state) => selectProjectsSearch(state),
|
||||
(state) => selectIsHiddenProjectsVisible(state),
|
||||
(state) => selectProjectsOrder(state),
|
||||
({ User }, id, projectsSearch, isHiddenProjectsVisible, projectsOrder) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const userModel = User.withId(id);
|
||||
|
||||
if (!userModel) {
|
||||
return userModel;
|
||||
}
|
||||
|
||||
return userModel
|
||||
.getFilteredProjectsModelArray(
|
||||
projectsSearch,
|
||||
isHiddenProjectsVisible,
|
||||
ORDER_BY_ARGS_BY_PROJECTS_ORDER[projectsOrder],
|
||||
)
|
||||
.map((projectModel) => projectModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFilteredProjctIdsByGroupForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
(state) => selectProjectsSearch(state),
|
||||
(state) => selectIsHiddenProjectsVisible(state),
|
||||
(state) => selectProjectsOrder(state),
|
||||
({ User }, id, projectsSearch, isHiddenProjectsVisible, projectsOrder) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const userModel = User.withId(id);
|
||||
|
||||
if (!userModel) {
|
||||
return userModel;
|
||||
}
|
||||
|
||||
const { managerProjectModels, membershipProjectModels, adminProjectModels } =
|
||||
userModel.getFilteredSeparatedProjectsModelArray(
|
||||
projectsSearch,
|
||||
isHiddenProjectsVisible,
|
||||
ORDER_BY_ARGS_BY_PROJECTS_ORDER[projectsOrder],
|
||||
);
|
||||
|
||||
return managerProjectModels.reduce(
|
||||
(result, projectModel) => {
|
||||
const group = projectModel.ownerProjectManager ? ProjectGroups.MY_OWN : ProjectGroups.TEAM;
|
||||
|
||||
result[group].push(projectModel.id);
|
||||
return result;
|
||||
},
|
||||
{
|
||||
[ProjectGroups.MY_OWN]: [],
|
||||
[ProjectGroups.TEAM]: [],
|
||||
[ProjectGroups.SHARED_WITH_ME]: membershipProjectModels.map(
|
||||
(projectModel) => projectModel.id,
|
||||
),
|
||||
[ProjectGroups.OTHERS]: adminProjectModels.map((projectModel) => projectModel.id),
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectFavoriteProjectIdsForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
(state) => selectProjectsOrder(state),
|
||||
({ User }, id, projectsOrder) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const userModel = User.withId(id);
|
||||
|
||||
if (!userModel) {
|
||||
return userModel;
|
||||
}
|
||||
|
||||
return userModel
|
||||
.getFavoriteProjectsModelArray(ORDER_BY_ARGS_BY_PROJECTS_ORDER[projectsOrder])
|
||||
.map((projectModel) => projectModel.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectProjectsToListsWithEditorRightsForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ User }, id) => {
|
||||
@@ -84,17 +211,31 @@ export const selectProjectsToListsForCurrentUser = createSelector(
|
||||
return userModel;
|
||||
}
|
||||
|
||||
return userModel.getOrderedAvailableProjectsModelArray().map((projectModel) => ({
|
||||
return userModel.getMembershipProjectsModelArray().map((projectModel) => ({
|
||||
...projectModel.ref,
|
||||
boards: projectModel.getOrderedBoardsModelArrayForUser(id).map((boardModel) => ({
|
||||
...boardModel.ref,
|
||||
lists: boardModel.getOrderedListsQuerySet().toRefArray(),
|
||||
})),
|
||||
boards: projectModel.getBoardsModelArrayForUserWithId(id).flatMap((boardModel) => {
|
||||
const boardMembersipModel = boardModel.getMembershipModelByUserId(id);
|
||||
|
||||
if (boardMembersipModel.role !== BoardMembershipRoles.EDITOR) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return {
|
||||
...boardModel.ref,
|
||||
lists: boardModel
|
||||
.getListsQuerySet()
|
||||
.toRefArray()
|
||||
.map((list) => ({
|
||||
...list,
|
||||
isPersisted: !isLocalId(list.id),
|
||||
})),
|
||||
};
|
||||
}),
|
||||
}));
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationsForCurrentUser = createSelector(
|
||||
export const selectBoardIdsForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ User }, id) => {
|
||||
@@ -109,25 +250,93 @@ export const selectNotificationsForCurrentUser = createSelector(
|
||||
}
|
||||
|
||||
return userModel
|
||||
.getOrderedUnreadNotificationsQuerySet()
|
||||
.toModelArray()
|
||||
.map((notificationModel) => ({
|
||||
...notificationModel.ref,
|
||||
activity: notificationModel.activity && {
|
||||
...notificationModel.activity.ref,
|
||||
user: notificationModel.activity.user.ref,
|
||||
},
|
||||
card: notificationModel.card && notificationModel.card.ref,
|
||||
}));
|
||||
.getProjectsModelArray()
|
||||
.flatMap((projectModel) =>
|
||||
projectModel
|
||||
.getBoardsModelArrayAvailableForUser(userModel)
|
||||
.map((boardModel) => boardModel.id),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationIdsForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ User }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const userModel = User.withId(id);
|
||||
|
||||
if (!userModel) {
|
||||
return userModel;
|
||||
}
|
||||
|
||||
return userModel
|
||||
.getUnreadNotificationsQuerySet()
|
||||
.toRefArray()
|
||||
.map((notification) => notification.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectNotificationServiceIdsForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
({ User }, id) => {
|
||||
if (!id) {
|
||||
return id;
|
||||
}
|
||||
|
||||
const userModel = User.withId(id);
|
||||
|
||||
if (!userModel) {
|
||||
return userModel;
|
||||
}
|
||||
|
||||
return userModel
|
||||
.getNotificationServicesQuerySet()
|
||||
.toRefArray()
|
||||
.map((notificationService) => notificationService.id);
|
||||
},
|
||||
);
|
||||
|
||||
export const selectIsFavoritesActiveForCurrentUser = createSelector(
|
||||
orm,
|
||||
(state) => selectCurrentUserId(state),
|
||||
(state) => selectIsFavoritesEnabled(state),
|
||||
({ User }, id, isFavoritesEnabled) => {
|
||||
if (!id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const userModel = User.withId(id);
|
||||
|
||||
if (!userModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: use selectFavoriteProjectIdsForCurrentUser instead
|
||||
return isFavoritesEnabled && userModel.getFavoriteProjectsModelArray().length > 0;
|
||||
},
|
||||
);
|
||||
|
||||
export default {
|
||||
makeSelectUserById,
|
||||
selectUserById,
|
||||
selectCurrentUserId,
|
||||
selectUsers,
|
||||
selectUsersExceptCurrent,
|
||||
selectActiveUsers,
|
||||
selectActiveUsersTotal,
|
||||
selectActiveAdminOrProjectOwnerUsers,
|
||||
selectCurrentUser,
|
||||
selectProjectsForCurrentUser,
|
||||
selectProjectsToListsForCurrentUser,
|
||||
selectNotificationsForCurrentUser,
|
||||
selectProjectIdsForCurrentUser,
|
||||
selectFilteredProjectIdsForCurrentUser,
|
||||
selectFilteredProjctIdsByGroupForCurrentUser,
|
||||
selectFavoriteProjectIdsForCurrentUser,
|
||||
selectProjectsToListsWithEditorRightsForCurrentUser,
|
||||
selectBoardIdsForCurrentUser,
|
||||
selectNotificationIdsForCurrentUser,
|
||||
selectNotificationServiceIdsForCurrentUser,
|
||||
selectIsFavoritesActiveForCurrentUser,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user