@@ -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 { all, apply, fork, select, take } from 'redux-saga/effects';
|
||||
|
||||
import watchers from './watchers';
|
||||
@@ -18,9 +23,14 @@ export default function* coreSaga() {
|
||||
const oidcConfig = yield select(selectors.selectOidcConfig);
|
||||
|
||||
if (oidcConfig && oidcConfig.endSessionUrl !== null) {
|
||||
// Redirect the user to the IDP to log out.
|
||||
window.location.href = oidcConfig.endSessionUrl;
|
||||
} else {
|
||||
window.location.href = Paths.LOGIN;
|
||||
const currentUser = yield select(selectors.selectCurrentUser);
|
||||
|
||||
if (!currentUser || currentUser.isSsoUser) {
|
||||
// Redirect the user to the IDP to log out.
|
||||
window.location.href = oidcConfig.endSessionUrl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
window.location.href = Paths.LOGIN;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { call, fork, join, put, select, take } from 'redux-saga/effects';
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, join, put, select, spawn, take } from 'redux-saga/effects';
|
||||
|
||||
import selectors from '../../selectors';
|
||||
import entryActions from '../../entry-actions';
|
||||
@@ -10,7 +15,9 @@ function* queueRequest(method, ...args) {
|
||||
if (lastRequestTask) {
|
||||
try {
|
||||
yield join(lastRequestTask);
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
|
||||
const accessToken = yield select(selectors.selectAccessToken);
|
||||
@@ -30,7 +37,7 @@ function* queueRequest(method, ...args) {
|
||||
}
|
||||
|
||||
export default function* request(method, ...args) {
|
||||
lastRequestTask = yield fork(queueRequest, method, ...args);
|
||||
lastRequestTask = yield spawn(queueRequest, method, ...args);
|
||||
|
||||
return yield join(lastRequestTask);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import api from '../../../api';
|
||||
import mergeRecords from '../../../utils/merge-records';
|
||||
import Paths from '../../../constants/Paths';
|
||||
|
||||
export function* fetchBoardByCurrentPath() {
|
||||
@@ -10,16 +16,29 @@ export function* fetchBoardByCurrentPath() {
|
||||
|
||||
let board;
|
||||
let card;
|
||||
let users;
|
||||
let users1;
|
||||
let users2;
|
||||
let projects;
|
||||
let boardMemberships;
|
||||
let labels;
|
||||
let lists;
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let cardMemberships1;
|
||||
let cardMemberships2;
|
||||
let cardLabels1;
|
||||
let cardLabels2;
|
||||
let taskLists1;
|
||||
let taskLists2;
|
||||
let tasks1;
|
||||
let tasks2;
|
||||
let attachments1;
|
||||
let attachments2;
|
||||
let customFieldGroups1;
|
||||
let customFieldGroups2;
|
||||
let customFields1;
|
||||
let customFields2;
|
||||
let customFieldValues1;
|
||||
let customFieldValues2;
|
||||
|
||||
if (pathsMatch) {
|
||||
let boardId;
|
||||
@@ -29,6 +48,17 @@ export function* fetchBoardByCurrentPath() {
|
||||
({
|
||||
item: card,
|
||||
item: { boardId },
|
||||
included: {
|
||||
users: users1,
|
||||
cardMemberships: cardMemberships1,
|
||||
cardLabels: cardLabels1,
|
||||
taskLists: taskLists1,
|
||||
tasks: tasks1,
|
||||
attachments: attachments1,
|
||||
customFieldGroups: customFieldGroups1,
|
||||
customFields: customFields1,
|
||||
customFieldValues: customFieldValues1,
|
||||
},
|
||||
} = yield call(request, api.getCard, pathsMatch.params.id));
|
||||
}
|
||||
|
||||
@@ -36,16 +66,20 @@ export function* fetchBoardByCurrentPath() {
|
||||
({
|
||||
item: board,
|
||||
included: {
|
||||
users,
|
||||
projects,
|
||||
boardMemberships,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
tasks,
|
||||
attachments,
|
||||
users: users2,
|
||||
cardMemberships: cardMemberships2,
|
||||
cardLabels: cardLabels2,
|
||||
taskLists: taskLists2,
|
||||
tasks: tasks2,
|
||||
attachments: attachments2,
|
||||
customFieldGroups: customFieldGroups2,
|
||||
customFields: customFields2,
|
||||
customFieldValues: customFieldValues2,
|
||||
},
|
||||
} = yield call(request, api.getBoard, boardId, true));
|
||||
}
|
||||
@@ -54,16 +88,20 @@ export function* fetchBoardByCurrentPath() {
|
||||
return {
|
||||
board,
|
||||
card,
|
||||
users,
|
||||
boardMemberships,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
tasks,
|
||||
attachments,
|
||||
project: projects[0],
|
||||
users: mergeRecords(users1, users2),
|
||||
cardMemberships: mergeRecords(cardMemberships1, cardMemberships2),
|
||||
cardLabels: mergeRecords(cardLabels1, cardLabels2),
|
||||
taskLists: mergeRecords(taskLists1, taskLists2),
|
||||
tasks: mergeRecords(tasks1, tasks2),
|
||||
attachments: mergeRecords(attachments1, attachments2),
|
||||
customFieldGroups: mergeRecords(customFieldGroups1, customFieldGroups2),
|
||||
customFields: mergeRecords(customFields1, customFields2),
|
||||
customFieldValues: mergeRecords(customFieldValues1, customFieldValues2),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,44 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call } from 'redux-saga/effects';
|
||||
|
||||
import { fetchBoardByCurrentPath } from './boards';
|
||||
import request from '../request';
|
||||
import api from '../../../api';
|
||||
import mergeRecords from '../../../utils/merge-records';
|
||||
import { isUserAdminOrProjectOwner } from '../../../utils/record-helpers';
|
||||
|
||||
export function* fetchCore() {
|
||||
const { item: user } = yield call(request, api.getCurrentUser, true);
|
||||
const { items: users1 } = yield call(request, api.getUsers);
|
||||
const {
|
||||
item: user,
|
||||
included: { notificationServices: notificationServices1 },
|
||||
} = yield call(request, api.getCurrentUser, true);
|
||||
|
||||
let users1;
|
||||
if (isUserAdminOrProjectOwner(user)) {
|
||||
({ items: users1 } = yield call(request, api.getUsers));
|
||||
}
|
||||
|
||||
const {
|
||||
items: projects1,
|
||||
included: { projectManagers, boards, boardMemberships: boardMemberships1 },
|
||||
included: {
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
users: users2,
|
||||
boardMemberships: boardMemberships1,
|
||||
customFields: customFields1,
|
||||
notificationServices: notificationServices2,
|
||||
},
|
||||
} = yield call(request, api.getProjects);
|
||||
|
||||
let board;
|
||||
let card;
|
||||
let users2;
|
||||
let users3;
|
||||
let projects2;
|
||||
let boardMemberships2;
|
||||
let labels;
|
||||
@@ -24,43 +46,51 @@ export function* fetchCore() {
|
||||
let cards1;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let customFieldGroups;
|
||||
let customFields2;
|
||||
let customFieldValues;
|
||||
|
||||
try {
|
||||
({
|
||||
board,
|
||||
card,
|
||||
users: users2,
|
||||
projects: projects2,
|
||||
boardMemberships: boardMemberships2,
|
||||
labels,
|
||||
lists,
|
||||
cards: cards1,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFieldValues,
|
||||
users: users3,
|
||||
projects: projects2,
|
||||
boardMemberships: boardMemberships2,
|
||||
cards: cards1,
|
||||
customFields: customFields2,
|
||||
} = yield call(fetchBoardByCurrentPath));
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
const body = yield call(request, api.getNotifications);
|
||||
|
||||
let { items: notifications } = body;
|
||||
|
||||
const {
|
||||
included: { users: users3, cards: cards2, activities },
|
||||
included: { users: users4 },
|
||||
} = body;
|
||||
|
||||
if (card) {
|
||||
const notificationIds = notifications.flatMap((notification) =>
|
||||
notification.cardId === card.id ? [notification.id] : [],
|
||||
notification.cardId === card.id ? notification.id : [],
|
||||
);
|
||||
|
||||
if (notificationIds.length > 0) {
|
||||
yield call(request, api.updateNotifications, notificationIds, {
|
||||
isRead: true,
|
||||
});
|
||||
yield call(request, api.readCardNotifications, card.id);
|
||||
|
||||
notifications = notifications.filter(
|
||||
(notification) => !notificationIds.includes(notification.id),
|
||||
@@ -72,19 +102,25 @@ export function* fetchCore() {
|
||||
user,
|
||||
board,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
labels,
|
||||
lists,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
activities,
|
||||
customFieldGroups,
|
||||
customFieldValues,
|
||||
notifications,
|
||||
users: mergeRecords(users1, users2, users3),
|
||||
users: mergeRecords(users1, users2, users3, users4),
|
||||
projects: mergeRecords(projects1, projects2),
|
||||
boardMemberships: mergeRecords(boardMemberships1, boardMemberships2),
|
||||
cards: mergeRecords(cards1, cards2),
|
||||
cards: mergeRecords(card && [card], cards1),
|
||||
customFields: mergeRecords(customFields1, customFields2),
|
||||
notificationServices: mergeRecords(notificationServices1, notificationServices2),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -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 core from './core';
|
||||
import boards from './boards';
|
||||
|
||||
|
||||
@@ -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 { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
@@ -6,8 +11,7 @@ import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
|
||||
export function* fetchActivities(cardId) {
|
||||
const { isActivitiesDetailsVisible } = yield select(selectors.selectCardById, cardId);
|
||||
const lastId = yield select(selectors.selectLastActivityIdByCardId, cardId);
|
||||
const { lastActivityId } = yield select(selectors.selectCardById, cardId);
|
||||
|
||||
yield put(actions.fetchActivities(cardId));
|
||||
|
||||
@@ -19,8 +23,7 @@ export function* fetchActivities(cardId) {
|
||||
items: activities,
|
||||
included: { users },
|
||||
} = yield call(request, api.getActivities, cardId, {
|
||||
beforeId: lastId,
|
||||
withDetails: isActivitiesDetailsVisible,
|
||||
beforeId: lastActivityId || undefined,
|
||||
}));
|
||||
} catch (error) {
|
||||
yield put(actions.fetchActivities.failure(cardId, error));
|
||||
@@ -36,53 +39,12 @@ export function* fetchActivitiesInCurrentCard() {
|
||||
yield call(fetchActivities, cardId);
|
||||
}
|
||||
|
||||
export function* toggleActivitiesDetails(cardId, isVisible) {
|
||||
yield put(actions.toggleActivitiesDetails(cardId, isVisible));
|
||||
|
||||
if (isVisible) {
|
||||
let activities;
|
||||
let users;
|
||||
|
||||
try {
|
||||
({
|
||||
items: activities,
|
||||
included: { users },
|
||||
} = yield call(request, api.getActivities, cardId, {
|
||||
withDetails: isVisible,
|
||||
}));
|
||||
} catch (error) {
|
||||
yield put(actions.toggleActivitiesDetails.failure(cardId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.toggleActivitiesDetails.success(cardId, activities, users));
|
||||
}
|
||||
}
|
||||
|
||||
export function* toggleActivitiesDetailsInCurrentCard(isVisible) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(toggleActivitiesDetails, cardId, isVisible);
|
||||
}
|
||||
|
||||
export function* handleActivityCreate(activity) {
|
||||
yield put(actions.handleActivityCreate(activity));
|
||||
}
|
||||
|
||||
export function* handleActivityUpdate(activity) {
|
||||
yield put(actions.handleActivityUpdate(activity));
|
||||
}
|
||||
|
||||
export function* handleActivityDelete(activity) {
|
||||
yield put(actions.handleActivityDelete(activity));
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchActivities,
|
||||
fetchActivitiesInCurrentCard,
|
||||
toggleActivitiesDetails,
|
||||
toggleActivitiesDetailsInCurrentCard,
|
||||
handleActivityCreate,
|
||||
handleActivityUpdate,
|
||||
handleActivityDelete,
|
||||
};
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import omit from 'lodash/omit';
|
||||
import truncate from 'lodash/truncate';
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
@@ -5,21 +12,33 @@ import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
import { AttachmentTypes } from '../../../constants/Enums';
|
||||
|
||||
export function* createAttachment(cardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
name: truncate(data.name, {
|
||||
length: 128,
|
||||
}),
|
||||
};
|
||||
|
||||
yield put(
|
||||
actions.createAttachment({
|
||||
...omit(nextData, ['file', 'url']),
|
||||
cardId,
|
||||
id: localId,
|
||||
name: data.file.name,
|
||||
creatorUserId: currentUserId,
|
||||
}),
|
||||
);
|
||||
|
||||
let attachment;
|
||||
try {
|
||||
({ item: attachment } = yield call(request, api.createAttachment, cardId, data, localId));
|
||||
({ item: attachment } = yield nextData.type === AttachmentTypes.FILE
|
||||
? call(request, api.createAttachmentWithFile, cardId, nextData, localId)
|
||||
: call(request, api.createAttachment, cardId, nextData));
|
||||
} catch (error) {
|
||||
yield put(actions.createAttachment.failure(localId, error));
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import omit from 'lodash/omit';
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createBackgroundImage(projectId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.createBackgroundImage({
|
||||
...omit(data, ['file', 'url']),
|
||||
projectId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let backgroundImage;
|
||||
try {
|
||||
({ item: backgroundImage } = yield call(
|
||||
request,
|
||||
api.createBackgroundImage,
|
||||
projectId,
|
||||
data,
|
||||
localId,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createBackgroundImage.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createBackgroundImage.success(localId, backgroundImage));
|
||||
}
|
||||
|
||||
export function* createBackgroundImageInCurrentProject(data) {
|
||||
const { projectId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createBackgroundImage, projectId, data);
|
||||
}
|
||||
|
||||
export function* handleBackgroundImageCreate(backgroundImage, requestId) {
|
||||
const isExists = yield select(selectors.selectIsBackgroundImageWithIdExists, requestId);
|
||||
|
||||
if (!isExists) {
|
||||
yield put(actions.handleBackgroundImageCreate(backgroundImage));
|
||||
}
|
||||
}
|
||||
|
||||
export function* deleteBackgroundImage(id) {
|
||||
yield put(actions.deleteBackgroundImage(id));
|
||||
|
||||
let backgroundImage;
|
||||
try {
|
||||
({ item: backgroundImage } = yield call(request, api.deleteBackgroundImage, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteBackgroundImage.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteBackgroundImage.success(backgroundImage));
|
||||
}
|
||||
|
||||
export function* handleBackgroundImageDelete(backgroundImage) {
|
||||
yield put(actions.handleBackgroundImageDelete(backgroundImage));
|
||||
}
|
||||
|
||||
export default {
|
||||
createBackgroundImage,
|
||||
createBackgroundImageInCurrentProject,
|
||||
handleBackgroundImageCreate,
|
||||
deleteBackgroundImage,
|
||||
handleBackgroundImageDelete,
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createBaseCustomFieldGroup(projectId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.createBaseCustomFieldGroup({
|
||||
...data,
|
||||
projectId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let baseCustomFieldGroup;
|
||||
try {
|
||||
({ item: baseCustomFieldGroup } = yield call(
|
||||
request,
|
||||
api.createBaseCustomFieldGroup,
|
||||
projectId,
|
||||
data,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createBaseCustomFieldGroup.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createBaseCustomFieldGroup.success(localId, baseCustomFieldGroup));
|
||||
}
|
||||
|
||||
export function* createBaseCustomFieldGroupInCurrentProject(data) {
|
||||
const { projectId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createBaseCustomFieldGroup, projectId, data);
|
||||
}
|
||||
|
||||
export function* handleBaseCustomFieldGroupCreate(baseCustomFieldGroup) {
|
||||
yield put(actions.handleBaseCustomFieldGroupCreate(baseCustomFieldGroup));
|
||||
}
|
||||
|
||||
export function* updateBaseCustomFieldGroup(id, data) {
|
||||
yield put(actions.updateBaseCustomFieldGroup(id, data));
|
||||
|
||||
let baseCustomFieldGroup;
|
||||
try {
|
||||
({ item: baseCustomFieldGroup } = yield call(
|
||||
request,
|
||||
api.updateBaseCustomFieldGroup,
|
||||
id,
|
||||
data,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.updateBaseCustomFieldGroup.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateBaseCustomFieldGroup.success(baseCustomFieldGroup));
|
||||
}
|
||||
|
||||
export function* handleBaseCustomFieldGroupUpdate(baseCustomFieldGroup) {
|
||||
yield put(actions.handleBaseCustomFieldGroupUpdate(baseCustomFieldGroup));
|
||||
}
|
||||
|
||||
export function* deleteBaseCustomFieldGroup(id) {
|
||||
yield put(actions.deleteBaseCustomFieldGroup(id));
|
||||
|
||||
let baseCustomFieldGroup;
|
||||
try {
|
||||
({ item: baseCustomFieldGroup } = yield call(request, api.deleteBaseCustomFieldGroup, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteBaseCustomFieldGroup.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteBaseCustomFieldGroup.success(baseCustomFieldGroup));
|
||||
}
|
||||
|
||||
export function* handleBaseCustomFieldGroupDelete(baseCustomFieldGroup) {
|
||||
yield put(actions.handleBaseCustomFieldGroupDelete(baseCustomFieldGroup));
|
||||
}
|
||||
|
||||
export default {
|
||||
createBaseCustomFieldGroup,
|
||||
createBaseCustomFieldGroupInCurrentProject,
|
||||
handleBaseCustomFieldGroupCreate,
|
||||
updateBaseCustomFieldGroup,
|
||||
handleBaseCustomFieldGroupUpdate,
|
||||
deleteBaseCustomFieldGroup,
|
||||
handleBaseCustomFieldGroupDelete,
|
||||
};
|
||||
@@ -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 { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import { goToProject } from './router';
|
||||
@@ -37,16 +42,22 @@ export function* createMembershipInCurrentBoard(data) {
|
||||
yield call(createBoardMembership, boardId, data);
|
||||
}
|
||||
|
||||
export function* handleBoardMembershipCreate(boardMembership) {
|
||||
export function* handleBoardMembershipCreate(boardMembership, users) {
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const isCurrentUser = boardMembership.userId === currentUserId;
|
||||
|
||||
let user;
|
||||
const isExternalAccessibleForCurrentUser = yield select(
|
||||
selectors.selectIsProjectWithIdExternalAccessibleForCurrentUser,
|
||||
boardMembership.projectId,
|
||||
);
|
||||
|
||||
let project;
|
||||
let board1;
|
||||
let board;
|
||||
let users1;
|
||||
let users2;
|
||||
let projectManagers;
|
||||
let backgroundImages;
|
||||
let baseCustomFieldGroups;
|
||||
let boards;
|
||||
let boardMemberships1;
|
||||
let boardMemberships2;
|
||||
@@ -55,72 +66,86 @@ export function* handleBoardMembershipCreate(boardMembership) {
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let deletedNotifications;
|
||||
|
||||
if (isCurrentUser) {
|
||||
let board2;
|
||||
try {
|
||||
({ item: board2 } = yield call(request, api.getBoard, boardMembership.boardId, false));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
let customFieldGroups;
|
||||
let customFields1;
|
||||
let customFields2;
|
||||
let customFieldValues;
|
||||
let notificationsToDelete;
|
||||
let notificationServices;
|
||||
|
||||
if (isCurrentUser && !isExternalAccessibleForCurrentUser) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(
|
||||
actions.handleBoardMembershipCreate.fetchProject(board2.projectId, currentUserId, boardId),
|
||||
);
|
||||
|
||||
try {
|
||||
({
|
||||
item: project,
|
||||
included: { users: users1, projectManagers, boards, boardMemberships: boardMemberships1 },
|
||||
} = yield call(request, api.getProject, board2.projectId));
|
||||
included: {
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
notificationServices,
|
||||
users: users1,
|
||||
boardMemberships: boardMemberships1,
|
||||
customFields: customFields1,
|
||||
},
|
||||
} = yield call(request, api.getProject, boardMembership.projectId));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
let body;
|
||||
try {
|
||||
body = yield call(requests.fetchBoardByCurrentPath);
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
if (boardId === null) {
|
||||
let body;
|
||||
try {
|
||||
body = yield call(requests.fetchBoardByCurrentPath);
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
if (body && body.project && body.project.id === board2.projectId) {
|
||||
({
|
||||
project,
|
||||
board: board1,
|
||||
users: users2,
|
||||
boardMemberships: boardMemberships2,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
tasks,
|
||||
attachments,
|
||||
} = body);
|
||||
if (body) {
|
||||
({
|
||||
project,
|
||||
board,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFieldValues,
|
||||
users: users2,
|
||||
boardMemberships: boardMemberships2,
|
||||
customFields: customFields2,
|
||||
} = body);
|
||||
|
||||
if (body.card) {
|
||||
deletedNotifications = yield select(selectors.selectNotificationsByCardId, body.card.id);
|
||||
if (body.card) {
|
||||
notificationsToDelete = yield select(selectors.selectNotificationsByCardId, body.card.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
({ item: user } = yield call(request, api.getUser, boardMembership.userId));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const isProjectAvailable = yield select(
|
||||
selectors.selectIsProjectWithIdAvailableForCurrentUser,
|
||||
boardMembership.projectId,
|
||||
);
|
||||
|
||||
yield put(
|
||||
actions.handleBoardMembershipCreate(
|
||||
boardMembership,
|
||||
isProjectAvailable,
|
||||
project,
|
||||
board1,
|
||||
isCurrentUser ? mergeRecords(users1, users2) : [user],
|
||||
board,
|
||||
mergeRecords(users, users1, users2),
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
mergeRecords(boardMemberships1, boardMemberships2),
|
||||
labels,
|
||||
@@ -128,9 +153,14 @@ export function* handleBoardMembershipCreate(boardMembership) {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
deletedNotifications,
|
||||
customFieldGroups,
|
||||
mergeRecords(customFields1, customFields2),
|
||||
customFieldValues,
|
||||
notificationsToDelete,
|
||||
notificationServices,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -156,21 +186,24 @@ export function* handleBoardMembershipUpdate(boardMembership) {
|
||||
export function* deleteBoardMembership(id) {
|
||||
let boardMembership = yield select(selectors.selectBoardMembershipById, id);
|
||||
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const { boardId, projectId } = yield select(selectors.selectPath);
|
||||
|
||||
if (boardMembership.userId === currentUserId && boardMembership.boardId === boardId) {
|
||||
const isCurrentUserManager = yield select(
|
||||
selectors.selectIsCurrentUserManagerForCurrentProject,
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const isCurrentUser = boardMembership.userId === currentUserId;
|
||||
|
||||
yield put(actions.deleteBoardMembership(id, isCurrentUser));
|
||||
|
||||
if (isCurrentUser && boardMembership.boardId === boardId) {
|
||||
const isAvailableForCurrentUser = yield select(
|
||||
selectors.selectIsBoardWithIdAvailableForCurrentUser,
|
||||
boardMembership.boardId,
|
||||
);
|
||||
|
||||
if (!isCurrentUserManager) {
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield call(goToProject, projectId);
|
||||
}
|
||||
}
|
||||
|
||||
yield put(actions.deleteBoardMembership(id));
|
||||
|
||||
try {
|
||||
({ item: boardMembership } = yield call(request, api.deleteBoardMembership, id));
|
||||
} catch (error) {
|
||||
@@ -178,24 +211,27 @@ export function* deleteBoardMembership(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteBoardMembership.success(boardMembership));
|
||||
yield put(actions.deleteBoardMembership.success(boardMembership, isCurrentUser));
|
||||
}
|
||||
|
||||
export function* handleBoardMembershipDelete(boardMembership) {
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const { boardId, projectId } = yield select(selectors.selectPath);
|
||||
|
||||
if (boardMembership.userId === currentUserId && boardMembership.boardId === boardId) {
|
||||
const isCurrentUserManager = yield select(
|
||||
selectors.selectIsCurrentUserManagerForCurrentProject,
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const isCurrentUser = boardMembership.userId === currentUserId;
|
||||
|
||||
yield put(actions.handleBoardMembershipDelete(boardMembership, isCurrentUser));
|
||||
|
||||
if (isCurrentUser && boardMembership.boardId === boardId) {
|
||||
const isAvailableForCurrentUser = yield select(
|
||||
selectors.selectIsBoardWithIdAvailableForCurrentUser,
|
||||
boardMembership.boardId,
|
||||
);
|
||||
|
||||
if (!isCurrentUserManager) {
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield call(goToProject, projectId);
|
||||
}
|
||||
}
|
||||
|
||||
yield put(actions.handleBoardMembershipDelete(boardMembership));
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, fork, put, select, take } from 'redux-saga/effects';
|
||||
|
||||
import { goToBoard, goToProject } from './router';
|
||||
import { openModal } from './modals';
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
import ActionTypes from '../../../constants/ActionTypes';
|
||||
import ModalTypes from '../../../constants/ModalTypes';
|
||||
|
||||
export function* createBoard(projectId, { import: boardImport, ...data }) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextBoardPosition, projectId),
|
||||
};
|
||||
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.createBoard({
|
||||
...nextData,
|
||||
@@ -23,6 +31,11 @@ export function* createBoard(projectId, { import: boardImport, ...data }) {
|
||||
}),
|
||||
);
|
||||
|
||||
// TODO: use race instead
|
||||
const watchForCreateBoardActionTask = yield fork(function* watchForCreateBoardAction() {
|
||||
yield take(ActionTypes.BOARD_CREATE);
|
||||
});
|
||||
|
||||
let board;
|
||||
let boardMemberships;
|
||||
|
||||
@@ -49,7 +62,14 @@ export function* createBoard(projectId, { import: boardImport, ...data }) {
|
||||
}
|
||||
|
||||
yield put(actions.createBoard.success(localId, board, boardMemberships));
|
||||
yield call(goToBoard, board.id);
|
||||
|
||||
if (watchForCreateBoardActionTask.isRunning()) {
|
||||
yield call(goToBoard, board.id);
|
||||
yield call(openModal, ModalTypes.BOARD_SETTINGS, {
|
||||
id: board.id,
|
||||
openPreferences: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function* createBoardInCurrentProject(data) {
|
||||
@@ -58,11 +78,11 @@ export function* createBoardInCurrentProject(data) {
|
||||
yield call(createBoard, projectId, data);
|
||||
}
|
||||
|
||||
export function* handleBoardCreate(board, requestId) {
|
||||
export function* handleBoardCreate(board, boardMemberships, requestId) {
|
||||
const isExists = yield select(selectors.selectIsBoardWithIdExists, requestId);
|
||||
|
||||
if (!isExists) {
|
||||
yield put(actions.handleBoardCreate(board));
|
||||
yield put(actions.handleBoardCreate(board, boardMemberships));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +98,12 @@ export function* fetchBoard(id) {
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let customFieldGroups;
|
||||
let customFields;
|
||||
let customFieldValues;
|
||||
|
||||
try {
|
||||
({
|
||||
@@ -93,8 +117,12 @@ export function* fetchBoard(id) {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
},
|
||||
} = yield call(request, api.getBoard, id, true));
|
||||
} catch (error) {
|
||||
@@ -113,8 +141,12 @@ export function* fetchBoard(id) {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -133,6 +165,12 @@ export function* updateBoard(id, data) {
|
||||
yield put(actions.updateBoard.success(board));
|
||||
}
|
||||
|
||||
export function* updateCurrentBoard(data) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(updateBoard, boardId, data);
|
||||
}
|
||||
|
||||
export function* handleBoardUpdate(board) {
|
||||
yield put(actions.handleBoardUpdate(board));
|
||||
}
|
||||
@@ -146,15 +184,46 @@ export function* moveBoard(id, index) {
|
||||
});
|
||||
}
|
||||
|
||||
export function* deleteBoard(id) {
|
||||
const { boardId, projectId } = yield select(selectors.selectPath);
|
||||
export function* updateBoardContext(id, value) {
|
||||
yield put(actions.updateBoardContext(id, value));
|
||||
}
|
||||
|
||||
if (id === boardId) {
|
||||
yield call(goToProject, projectId);
|
||||
}
|
||||
export function* updateContextInCurrentBoard(value) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(updateBoardContext, boardId, value);
|
||||
}
|
||||
|
||||
export function* updateBoardView(id, value) {
|
||||
yield put(
|
||||
actions.updateBoard(id, {
|
||||
view: value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
export function* updateViewInCurrentBoard(value) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(updateBoardView, boardId, value);
|
||||
}
|
||||
|
||||
export function* searchInCurrentBoard(value) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
const currentListId = yield select(selectors.selectCurrentListId);
|
||||
|
||||
yield put(actions.searchInBoard(boardId, value, currentListId));
|
||||
}
|
||||
|
||||
export function* deleteBoard(id) {
|
||||
const currentBoard = yield select(selectors.selectCurrentBoard);
|
||||
|
||||
yield put(actions.deleteBoard(id));
|
||||
|
||||
if (currentBoard && id === currentBoard.id) {
|
||||
yield call(goToProject, currentBoard.projectId);
|
||||
}
|
||||
|
||||
let board;
|
||||
try {
|
||||
({ item: board } = yield call(request, api.deleteBoard, id));
|
||||
@@ -167,13 +236,13 @@ export function* deleteBoard(id) {
|
||||
}
|
||||
|
||||
export function* handleBoardDelete(board) {
|
||||
const { boardId, projectId } = yield select(selectors.selectPath);
|
||||
|
||||
if (board.id === boardId) {
|
||||
yield call(goToProject, projectId);
|
||||
}
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(actions.handleBoardDelete(board));
|
||||
|
||||
if (board.id === boardId) {
|
||||
yield call(goToProject, board.projectId);
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -182,8 +251,14 @@ export default {
|
||||
handleBoardCreate,
|
||||
fetchBoard,
|
||||
updateBoard,
|
||||
updateCurrentBoard,
|
||||
handleBoardUpdate,
|
||||
moveBoard,
|
||||
updateBoardContext,
|
||||
updateContextInCurrentBoard,
|
||||
updateBoardView,
|
||||
updateViewInCurrentBoard,
|
||||
searchInCurrentBoard,
|
||||
deleteBoard,
|
||||
handleBoardDelete,
|
||||
};
|
||||
|
||||
@@ -1,32 +1,155 @@
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, fork, join, put, race, select, take } from 'redux-saga/effects';
|
||||
import { LOCATION_CHANGE_HANDLE } from '../../../lib/redux-router';
|
||||
|
||||
import { goToBoard, goToCard } from './router';
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import i18n from '../../../i18n';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
import { isListArchiveOrTrash, isListFinite } from '../../../utils/record-helpers';
|
||||
import ActionTypes from '../../../constants/ActionTypes';
|
||||
import { BoardViews, ListTypes } from '../../../constants/Enums';
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const _preloadImage = (url) =>
|
||||
new Promise((resolve) => {
|
||||
const image = new Image();
|
||||
|
||||
image.onload = resolve;
|
||||
image.onerror = resolve;
|
||||
|
||||
image.src = url;
|
||||
});
|
||||
|
||||
export function* fetchCards(listId) {
|
||||
const { boardId, lastCard } = yield select(selectors.selectListById, listId);
|
||||
const { search } = yield select(selectors.selectBoardById, boardId);
|
||||
const filterUserIds = yield select(selectors.selectFilterUserIdsForCurrentBoard);
|
||||
const filterLabelIds = yield select(selectors.selectFilterLabelIdsForCurrentBoard);
|
||||
|
||||
function* getCardsRequest() {
|
||||
const response = {};
|
||||
|
||||
try {
|
||||
response.body = yield call(request, api.getCards, listId, {
|
||||
search: (search && search.trim()) || undefined,
|
||||
filterUserIds: filterUserIds.length > 0 ? filterUserIds.join(',') : undefined,
|
||||
filterLabelIds: filterLabelIds.length > 0 ? filterLabelIds.join(',') : undefined,
|
||||
before: lastCard || undefined,
|
||||
});
|
||||
} catch (error) {
|
||||
response.error = error;
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
yield put(actions.fetchCards(listId));
|
||||
|
||||
const getCardsRequestTask = yield fork(getCardsRequest);
|
||||
|
||||
const [response] = yield race([
|
||||
join(getCardsRequestTask),
|
||||
take((action) => action.type === ActionTypes.CARDS_FETCH && action.payload.listId === listId),
|
||||
]);
|
||||
|
||||
if (!response) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.error) {
|
||||
yield put(actions.fetchCards.failure(listId, response.error));
|
||||
return;
|
||||
}
|
||||
|
||||
const {
|
||||
body: {
|
||||
items: cards,
|
||||
included: {
|
||||
users,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
},
|
||||
},
|
||||
} = response;
|
||||
|
||||
yield put(
|
||||
actions.fetchCards.success(
|
||||
listId,
|
||||
cards,
|
||||
users,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function* fetchCardsInCurrentList() {
|
||||
const currentListId = yield select(selectors.selectCurrentListId);
|
||||
|
||||
yield call(fetchCards, currentListId);
|
||||
}
|
||||
|
||||
export function* handleCardsUpdate(cards, activities) {
|
||||
yield put(actions.handleCardsUpdate(cards, activities));
|
||||
}
|
||||
|
||||
export function* createCard(listId, data, autoOpen) {
|
||||
const { boardId } = yield select(selectors.selectListById, listId);
|
||||
const localId = yield call(createLocalId);
|
||||
const list = yield select(selectors.selectListById, listId);
|
||||
|
||||
const currentUserMembership = yield select(
|
||||
selectors.selectCurrentUserMembershipByBoardId,
|
||||
list.boardId,
|
||||
);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextCardPosition, listId),
|
||||
};
|
||||
|
||||
const localId = yield call(createLocalId);
|
||||
if (isListFinite(list)) {
|
||||
nextData.position = yield select(selectors.selectNextCardPosition, listId);
|
||||
}
|
||||
|
||||
yield put(
|
||||
actions.createCard({
|
||||
...nextData,
|
||||
boardId,
|
||||
listId,
|
||||
id: localId,
|
||||
}),
|
||||
actions.createCard(
|
||||
{
|
||||
...nextData,
|
||||
listId,
|
||||
id: localId,
|
||||
boardId: list.boardId,
|
||||
creatorUserId: currentUserMembership.userId,
|
||||
},
|
||||
autoOpen,
|
||||
),
|
||||
);
|
||||
|
||||
// TODO: use race instead
|
||||
let watchForCreateCardActionTask;
|
||||
if (autoOpen) {
|
||||
watchForCreateCardActionTask = yield fork(function* watchForCreateCardAction() {
|
||||
yield take((action) => action.type === ActionTypes.CARD_CREATE && action.payload.autoOpen);
|
||||
});
|
||||
}
|
||||
|
||||
let card;
|
||||
try {
|
||||
({ item: card } = yield call(request, api.createCard, listId, nextData));
|
||||
@@ -37,32 +160,94 @@ export function* createCard(listId, data, autoOpen) {
|
||||
|
||||
yield put(actions.createCard.success(localId, card));
|
||||
|
||||
if (autoOpen) {
|
||||
if (watchForCreateCardActionTask && watchForCreateCardActionTask.isRunning()) {
|
||||
yield call(goToCard, card.id);
|
||||
}
|
||||
}
|
||||
|
||||
export function* handleCardCreate({ id }) {
|
||||
let card;
|
||||
export function* createCardInCurrentList(data, autoOpen) {
|
||||
const currentListId = yield select(selectors.selectCurrentListId);
|
||||
|
||||
yield call(createCard, currentListId, data, autoOpen);
|
||||
}
|
||||
|
||||
export function* createCardInFirstFiniteList(data, autoOpen) {
|
||||
const firstFiniteListId = yield select(selectors.selectFirstFiniteListId);
|
||||
|
||||
yield call(createCard, firstFiniteListId, data, autoOpen);
|
||||
}
|
||||
|
||||
export function* handleCardCreate(card) {
|
||||
let users;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let customFieldGroups;
|
||||
let customFields;
|
||||
let customFieldValues;
|
||||
|
||||
try {
|
||||
({
|
||||
item: card,
|
||||
included: { cardMemberships, cardLabels, tasks, attachments },
|
||||
} = yield call(request, api.getCard, id));
|
||||
} catch (error) {
|
||||
item: card, // eslint-disable-line no-param-reassign
|
||||
included: {
|
||||
users,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
},
|
||||
} = yield call(request, api.getCard, card.id));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.handleCardCreate(card, cardMemberships, cardLabels, tasks, attachments));
|
||||
yield put(
|
||||
actions.handleCardCreate(
|
||||
card,
|
||||
users,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function* updateCard(id, data) {
|
||||
yield put(actions.updateCard(id, data));
|
||||
let prevListId;
|
||||
if (data.listId) {
|
||||
const list = yield select(selectors.selectListById, data.listId);
|
||||
|
||||
const card = yield select(selectors.selectCardById, id);
|
||||
const prevList = yield select(selectors.selectListById, card.listId);
|
||||
|
||||
if (prevList.type === ListTypes.TRASH) {
|
||||
prevListId = null;
|
||||
} else if (isListArchiveOrTrash(list)) {
|
||||
prevListId = prevList.id;
|
||||
} else if (prevList.type === ListTypes.ARCHIVE) {
|
||||
prevListId = null;
|
||||
}
|
||||
}
|
||||
|
||||
yield put(
|
||||
actions.updateCard(id, {
|
||||
...data,
|
||||
...(prevListId !== undefined && {
|
||||
prevListId,
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
let card;
|
||||
try {
|
||||
@@ -82,59 +267,142 @@ export function* updateCurrentCard(data) {
|
||||
}
|
||||
|
||||
export function* handleCardUpdate(card) {
|
||||
const { cardId, boardId } = yield select(selectors.selectPath);
|
||||
|
||||
let fetch = false;
|
||||
if (card.boardId) {
|
||||
const prevCard = yield select(selectors.selectCardById, card.id);
|
||||
fetch = !prevCard || prevCard.boardId !== card.boardId;
|
||||
const isAvailableForCurrentUser = yield select(
|
||||
selectors.selectIsCardWithIdAvailableForCurrentUser,
|
||||
card.id,
|
||||
);
|
||||
|
||||
fetch = !isAvailableForCurrentUser;
|
||||
}
|
||||
|
||||
let users;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let customFieldGroups;
|
||||
let customFields;
|
||||
let customFieldValues;
|
||||
|
||||
if (fetch) {
|
||||
try {
|
||||
({
|
||||
item: card, // eslint-disable-line no-param-reassign
|
||||
included: { cardMemberships, cardLabels, tasks, attachments },
|
||||
included: {
|
||||
users,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
},
|
||||
} = yield call(request, api.getCard, card.id));
|
||||
} catch (error) {
|
||||
} catch {
|
||||
fetch = false;
|
||||
}
|
||||
}
|
||||
|
||||
yield put(actions.handleCardUpdate(card, fetch, cardMemberships, cardLabels, tasks, attachments));
|
||||
yield put(
|
||||
actions.handleCardUpdate(
|
||||
card,
|
||||
fetch,
|
||||
users,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
),
|
||||
);
|
||||
|
||||
if (card.boardId === null && card.id === cardId) {
|
||||
yield call(goToBoard, boardId);
|
||||
}
|
||||
}
|
||||
|
||||
export function* moveCard(id, listId, index = 0) {
|
||||
const position = yield select(selectors.selectNextCardPosition, listId, index, id);
|
||||
export function* moveCard(id, listId, index) {
|
||||
const data = {};
|
||||
if (listId) {
|
||||
data.listId = listId;
|
||||
} else {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
({ listId } = yield select(selectors.selectCardById, id));
|
||||
}
|
||||
|
||||
yield call(updateCard, id, {
|
||||
listId,
|
||||
position,
|
||||
});
|
||||
const list = yield select(selectors.selectListById, listId);
|
||||
|
||||
if (isListFinite(list)) {
|
||||
data.position = yield select(selectors.selectNextCardPosition, listId, index, id);
|
||||
}
|
||||
|
||||
yield call(updateCard, id, data);
|
||||
}
|
||||
|
||||
export function* moveCurrentCard(listId, index) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
export function* moveCurrentCard(listId, index, autoClose) {
|
||||
const { cardId, boardId } = yield select(selectors.selectPath);
|
||||
|
||||
if (autoClose) {
|
||||
yield call(goToBoard, boardId);
|
||||
}
|
||||
|
||||
yield call(moveCard, cardId, listId, index);
|
||||
}
|
||||
|
||||
export function* transferCard(id, boardId, listId, index = 0) {
|
||||
const { cardId: currentCardId, boardId: currentBoardId } = yield select(selectors.selectPath);
|
||||
const position = yield select(selectors.selectNextCardPosition, listId, index, id);
|
||||
export function* moveCardToArchive(id) {
|
||||
const archiveListId = yield select(selectors.selectArchiveListIdForCurrentBoard);
|
||||
|
||||
yield call(moveCard, id, archiveListId);
|
||||
}
|
||||
|
||||
export function* moveCurrentCardToArchive() {
|
||||
const archiveListId = yield select(selectors.selectArchiveListIdForCurrentBoard);
|
||||
|
||||
yield call(moveCurrentCard, archiveListId, undefined, true);
|
||||
}
|
||||
|
||||
export function* moveCardToTrash(id) {
|
||||
const trashListId = yield select(selectors.selectTrashListIdForCurrentBoard);
|
||||
|
||||
yield call(moveCard, id, trashListId);
|
||||
}
|
||||
|
||||
export function* moveCurrentCardToTrash() {
|
||||
const trashListId = yield select(selectors.selectTrashListIdForCurrentBoard);
|
||||
|
||||
yield call(moveCurrentCard, trashListId, undefined, true);
|
||||
}
|
||||
|
||||
export function* transferCard(id, boardId, listId, index) {
|
||||
const { cardId: currentCardId, boardId: currentBoardId } = yield select(selectors.selectPath);
|
||||
|
||||
// TODO: hack?
|
||||
if (id === currentCardId) {
|
||||
yield call(goToBoard, currentBoardId);
|
||||
}
|
||||
|
||||
yield call(updateCard, id, {
|
||||
boardId,
|
||||
const list = yield select(selectors.selectListById, listId);
|
||||
|
||||
const data = {
|
||||
listId,
|
||||
position,
|
||||
});
|
||||
boardId,
|
||||
};
|
||||
|
||||
if (isListFinite(list)) {
|
||||
data.position = yield select(selectors.selectNextCardPosition, listId, index, id);
|
||||
}
|
||||
|
||||
yield call(updateCard, id, data);
|
||||
}
|
||||
|
||||
export function* transferCurrentCard(boardId, listId, index) {
|
||||
@@ -143,64 +411,142 @@ export function* transferCurrentCard(boardId, listId, index) {
|
||||
yield call(transferCard, cardId, boardId, listId, index);
|
||||
}
|
||||
|
||||
export function* duplicateCard(id) {
|
||||
const { listId, name } = yield select(selectors.selectCardById, id);
|
||||
export function* duplicateCard(id, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
const { boardId, listId } = yield select(selectors.selectCardById, id);
|
||||
const index = yield select(selectors.selectCardIndexById, id);
|
||||
|
||||
const currentUserMembership = yield select(
|
||||
selectors.selectCurrentUserMembershipByBoardId,
|
||||
boardId,
|
||||
);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextCardPosition, listId, index + 1),
|
||||
name: `${name} (${i18n.t('common.copy', {
|
||||
context: 'inline',
|
||||
})})`,
|
||||
};
|
||||
|
||||
const localId = yield call(createLocalId);
|
||||
const taskIds = yield select(selectors.selectTaskIdsByCardId, id);
|
||||
|
||||
yield put(
|
||||
actions.duplicateCard(
|
||||
id,
|
||||
{
|
||||
...nextData,
|
||||
id: localId,
|
||||
},
|
||||
taskIds,
|
||||
),
|
||||
actions.duplicateCard(id, localId, {
|
||||
...nextData,
|
||||
creatorUserId: currentUserMembership.userId,
|
||||
}),
|
||||
);
|
||||
|
||||
let card;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let customFieldGroups;
|
||||
let customFields;
|
||||
let customFieldValues;
|
||||
|
||||
try {
|
||||
({
|
||||
item: card,
|
||||
included: { cardMemberships, cardLabels, tasks },
|
||||
included: {
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
},
|
||||
} = yield call(request, api.duplicateCard, id, nextData));
|
||||
} catch (error) {
|
||||
yield put(actions.duplicateCard.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.duplicateCard.success(localId, card, cardMemberships, cardLabels, tasks));
|
||||
if (card.coverAttachmentId) {
|
||||
const coverAttachment = attachments.find(
|
||||
(attachment) => attachment.id === card.coverAttachmentId,
|
||||
);
|
||||
|
||||
if (coverAttachment) {
|
||||
yield call(_preloadImage, coverAttachment.data.thumbnailUrls.outside360);
|
||||
}
|
||||
}
|
||||
|
||||
yield put(
|
||||
actions.duplicateCard.success(
|
||||
localId,
|
||||
card,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function* duplicateCurrentCard() {
|
||||
export function* duplicateCurrentCard(data) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(duplicateCard, cardId);
|
||||
yield call(duplicateCard, cardId, data);
|
||||
}
|
||||
|
||||
export function* goToAdjacentCard(direction) {
|
||||
const card = yield select(selectors.selectCurrentCard);
|
||||
const list = yield select(selectors.selectListById, card.listId);
|
||||
|
||||
let cardIds;
|
||||
if (isListFinite(list)) {
|
||||
const { view } = yield select(selectors.selectCurrentBoard);
|
||||
|
||||
if (view === BoardViews.KANBAN) {
|
||||
cardIds = yield select(selectors.selectFilteredCardIdsByListId, card.listId);
|
||||
} else {
|
||||
cardIds = yield select(selectors.selectFilteredCardIdsForCurrentBoard);
|
||||
}
|
||||
} else {
|
||||
cardIds = yield select(selectors.selectFilteredCardIdsByListId, card.listId);
|
||||
|
||||
if (direction === 1 && card.id === cardIds[cardIds.length - 1]) {
|
||||
if (list.isCardsFetching || list.isAllCardsFetched) {
|
||||
return;
|
||||
}
|
||||
|
||||
const [, cancelled] = yield race([call(fetchCards, list.id), take(LOCATION_CHANGE_HANDLE)]);
|
||||
|
||||
if (cancelled) {
|
||||
return;
|
||||
}
|
||||
|
||||
cardIds = yield select(selectors.selectFilteredCardIdsByListId, card.listId);
|
||||
}
|
||||
}
|
||||
|
||||
const index = cardIds.indexOf(card.id);
|
||||
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const adjacentCardId = cardIds[index + direction];
|
||||
|
||||
if (adjacentCardId) {
|
||||
yield call(goToCard, adjacentCardId);
|
||||
}
|
||||
}
|
||||
|
||||
export function* deleteCard(id) {
|
||||
const { cardId, boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(actions.deleteCard(id));
|
||||
|
||||
if (id === cardId) {
|
||||
yield call(goToBoard, boardId);
|
||||
}
|
||||
|
||||
yield put(actions.deleteCard(id));
|
||||
|
||||
let card;
|
||||
try {
|
||||
({ item: card } = yield call(request, api.deleteCard, id));
|
||||
@@ -219,35 +565,38 @@ export function* deleteCurrentCard() {
|
||||
}
|
||||
|
||||
export function* handleCardDelete(card) {
|
||||
const { cardId, boardId } = yield select(selectors.selectPath);
|
||||
|
||||
if (card.id === cardId) {
|
||||
yield call(goToBoard, boardId);
|
||||
}
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(actions.handleCardDelete(card));
|
||||
}
|
||||
|
||||
export function* handleTextFilter(text) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(actions.filterText(boardId, text));
|
||||
if (card.id === cardId) {
|
||||
yield call(goToBoard, card.boardId);
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchCards,
|
||||
fetchCardsInCurrentList,
|
||||
handleCardsUpdate,
|
||||
createCard,
|
||||
createCardInCurrentList,
|
||||
handleCardCreate,
|
||||
createCardInFirstFiniteList,
|
||||
updateCard,
|
||||
updateCurrentCard,
|
||||
handleCardUpdate,
|
||||
moveCard,
|
||||
moveCurrentCard,
|
||||
moveCardToArchive,
|
||||
moveCurrentCardToArchive,
|
||||
moveCardToTrash,
|
||||
moveCurrentCardToTrash,
|
||||
transferCard,
|
||||
transferCurrentCard,
|
||||
duplicateCard,
|
||||
duplicateCurrentCard,
|
||||
goToAdjacentCard,
|
||||
deleteCard,
|
||||
deleteCurrentCard,
|
||||
handleCardDelete,
|
||||
handleTextFilter,
|
||||
};
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
import { ActivityTypes } from '../../../constants/Enums';
|
||||
|
||||
export function* createCommentActivity(cardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
const userId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield put(
|
||||
actions.createCommentActivity({
|
||||
cardId,
|
||||
userId,
|
||||
data,
|
||||
id: localId,
|
||||
type: ActivityTypes.COMMENT_CARD,
|
||||
}),
|
||||
);
|
||||
|
||||
let activity;
|
||||
try {
|
||||
({ item: activity } = yield call(request, api.createCommentActivity, cardId, data));
|
||||
} catch (error) {
|
||||
yield put(actions.createCommentActivity.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createCommentActivity.success(localId, activity));
|
||||
}
|
||||
|
||||
export function* createCommentActivityInCurrentCard(data) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createCommentActivity, cardId, data);
|
||||
}
|
||||
|
||||
export function* updateCommentActivity(id, data) {
|
||||
yield put(actions.updateCommentActivity(id, data));
|
||||
|
||||
let activity;
|
||||
try {
|
||||
({ item: activity } = yield call(request, api.updateCommentActivity, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.updateCommentActivity.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateCommentActivity.success(activity));
|
||||
}
|
||||
|
||||
export function* deleteCommentActivity(id) {
|
||||
yield put(actions.deleteCommentActivity(id));
|
||||
|
||||
let activity;
|
||||
try {
|
||||
({ item: activity } = yield call(request, api.deleteCommentActivity, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteCommentActivity.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteCommentActivity.success(activity));
|
||||
}
|
||||
|
||||
export default {
|
||||
createCommentActivity,
|
||||
createCommentActivityInCurrentCard,
|
||||
updateCommentActivity,
|
||||
deleteCommentActivity,
|
||||
};
|
||||
@@ -0,0 +1,123 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* fetchComments(cardId) {
|
||||
const { lastCommentId } = yield select(selectors.selectCardById, cardId);
|
||||
|
||||
yield put(actions.fetchComments(cardId));
|
||||
|
||||
let comments;
|
||||
let users;
|
||||
|
||||
try {
|
||||
({
|
||||
items: comments,
|
||||
included: { users },
|
||||
} = yield call(request, api.getComments, cardId, {
|
||||
beforeId: lastCommentId || undefined,
|
||||
}));
|
||||
} catch (error) {
|
||||
yield put(actions.fetchComments.failure(cardId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.fetchComments.success(cardId, comments, users));
|
||||
}
|
||||
|
||||
export function* fetchCommentsInCurrentCard() {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(fetchComments, cardId);
|
||||
}
|
||||
|
||||
export function* createComment(cardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
const currentUser = yield select(selectors.selectCurrentUser);
|
||||
|
||||
yield put(
|
||||
actions.createComment({
|
||||
...data,
|
||||
cardId,
|
||||
id: localId,
|
||||
userId: currentUser.id,
|
||||
}),
|
||||
);
|
||||
|
||||
let comment;
|
||||
try {
|
||||
({ item: comment } = yield call(request, api.createComment, cardId, data));
|
||||
} catch (error) {
|
||||
yield put(actions.createComment.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createComment.success(localId, comment));
|
||||
}
|
||||
|
||||
export function* createCommentInCurrentCard(data) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createComment, cardId, data);
|
||||
}
|
||||
|
||||
export function* handleCommentCreate(comment, users) {
|
||||
yield put(actions.handleCommentCreate(comment, users));
|
||||
}
|
||||
|
||||
export function* updateComment(id, data) {
|
||||
yield put(actions.updateComment(id, data));
|
||||
|
||||
let comment;
|
||||
try {
|
||||
({ item: comment } = yield call(request, api.updateComment, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.updateComment.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateComment.success(comment));
|
||||
}
|
||||
|
||||
export function* handleCommentUpdate(comment) {
|
||||
yield put(actions.handleCommentUpdate(comment));
|
||||
}
|
||||
|
||||
export function* deleteComment(id) {
|
||||
yield put(actions.deleteComment(id));
|
||||
|
||||
let comment;
|
||||
try {
|
||||
({ item: comment } = yield call(request, api.deleteComment, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteComment.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteComment.success(comment));
|
||||
}
|
||||
|
||||
export function* handleCommentDelete(comment) {
|
||||
yield put(actions.handleCommentDelete(comment));
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchComments,
|
||||
fetchCommentsInCurrentCard,
|
||||
createComment,
|
||||
createCommentInCurrentCard,
|
||||
handleCommentCreate,
|
||||
updateComment,
|
||||
handleCommentUpdate,
|
||||
deleteComment,
|
||||
handleCommentDelete,
|
||||
};
|
||||
@@ -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 { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
@@ -9,14 +14,9 @@ import i18n from '../../../i18n';
|
||||
import { removeAccessToken } from '../../../utils/access-token-storage';
|
||||
|
||||
export function* initializeCore() {
|
||||
const currentConfig = yield select(selectors.selectConfig); // TODO: add boolean selector?
|
||||
const { item: config } = yield call(request, api.getConfig); // TODO: handle error
|
||||
|
||||
let config;
|
||||
if (!currentConfig) {
|
||||
({ item: config } = yield call(api.getConfig)); // TODO: handle error
|
||||
|
||||
yield put(actions.initializeCore.fetchConfig(config));
|
||||
}
|
||||
yield put(actions.initializeCore.fetchConfig(config));
|
||||
|
||||
const {
|
||||
user,
|
||||
@@ -24,6 +24,8 @@ export function* initializeCore() {
|
||||
users,
|
||||
projects,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
boardMemberships,
|
||||
labels,
|
||||
@@ -31,10 +33,14 @@ export function* initializeCore() {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
activities,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
notifications,
|
||||
notificationServices,
|
||||
} = yield call(requests.fetchCore); // TODO: handle error
|
||||
|
||||
yield call(i18n.changeLanguage, user.language);
|
||||
@@ -47,6 +53,8 @@ export function* initializeCore() {
|
||||
users,
|
||||
projects,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
boardMemberships,
|
||||
labels,
|
||||
@@ -54,10 +62,14 @@ export function* initializeCore() {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
activities,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
notifications,
|
||||
notificationServices,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -73,7 +85,39 @@ export function* changeCoreLanguage(language) {
|
||||
}
|
||||
}
|
||||
|
||||
export function* logout(invalidateAccessToken = true) {
|
||||
export function* toggleFavorites(isEnabled) {
|
||||
yield put(actions.toggleFavorites(isEnabled));
|
||||
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
try {
|
||||
yield call(request, api.updateUser, currentUserId, {
|
||||
enableFavoritesByDefault: isEnabled,
|
||||
});
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
|
||||
export function* toggleEditMode(isEnabled) {
|
||||
yield put(actions.toggleEditMode(isEnabled));
|
||||
}
|
||||
|
||||
export function* updateHomeView(value) {
|
||||
yield put(actions.updateHomeView(value));
|
||||
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
try {
|
||||
yield call(request, api.updateUser, currentUserId, {
|
||||
defaultHomeView: value,
|
||||
});
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
|
||||
export function* logout(invalidateAccessToken) {
|
||||
yield call(removeAccessToken);
|
||||
|
||||
if (invalidateAccessToken) {
|
||||
@@ -81,7 +125,9 @@ export function* logout(invalidateAccessToken = true) {
|
||||
|
||||
try {
|
||||
yield call(request, api.deleteCurrentAccessToken);
|
||||
} catch (error) {} // eslint-disable-line no-empty
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
|
||||
yield put(actions.logout()); // TODO: next url
|
||||
@@ -90,5 +136,8 @@ export function* logout(invalidateAccessToken = true) {
|
||||
export default {
|
||||
initializeCore,
|
||||
changeCoreLanguage,
|
||||
toggleFavorites,
|
||||
toggleEditMode,
|
||||
updateHomeView,
|
||||
logout,
|
||||
};
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createCustomFieldGroupInBoard(boardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextCustomFieldGroupPositionInBoard, boardId),
|
||||
};
|
||||
|
||||
yield put(
|
||||
actions.createCustomFieldGroup({
|
||||
...nextData,
|
||||
boardId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let customFieldGroup;
|
||||
try {
|
||||
({ item: customFieldGroup } = yield call(
|
||||
request,
|
||||
api.createCustomFieldGroupInBoard,
|
||||
boardId,
|
||||
nextData,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createCustomFieldGroup.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createCustomFieldGroup.success(localId, customFieldGroup));
|
||||
}
|
||||
|
||||
export function* createCustomFieldGroupInCurrentBoard(data) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createCustomFieldGroupInBoard, boardId, data);
|
||||
}
|
||||
|
||||
export function* createCustomFieldGroupInCard(cardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextCustomFieldGroupPositionInCard, cardId),
|
||||
};
|
||||
|
||||
yield put(
|
||||
actions.createCustomFieldGroup({
|
||||
...nextData,
|
||||
cardId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let customFieldGroup;
|
||||
try {
|
||||
({ item: customFieldGroup } = yield call(
|
||||
request,
|
||||
api.createCustomFieldGroupInCard,
|
||||
cardId,
|
||||
nextData,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createCustomFieldGroup.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createCustomFieldGroup.success(localId, customFieldGroup));
|
||||
}
|
||||
|
||||
export function* createCustomFieldGroupInCurrentCard(data) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createCustomFieldGroupInCard, cardId, data);
|
||||
}
|
||||
|
||||
export function* handleCustomFieldGroupCreate(customFieldGroup) {
|
||||
yield put(actions.handleCustomFieldGroupCreate(customFieldGroup));
|
||||
}
|
||||
|
||||
export function* updateCustomFieldGroup(id, data) {
|
||||
yield put(actions.updateCustomFieldGroup(id, data));
|
||||
|
||||
let customFieldGroup;
|
||||
try {
|
||||
({ item: customFieldGroup } = yield call(request, api.updateCustomFieldGroup, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.updateCustomFieldGroup.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateCustomFieldGroup.success(customFieldGroup));
|
||||
}
|
||||
|
||||
export function* handleCustomFieldGroupUpdate(customFieldGroup) {
|
||||
yield put(actions.handleCustomFieldGroupUpdate(customFieldGroup));
|
||||
}
|
||||
|
||||
export function* moveCustomFieldGroup(id, index) {
|
||||
const customFieldGroup = yield select(selectors.selectCustomFieldGroupById, id);
|
||||
|
||||
let position;
|
||||
if (customFieldGroup.boardId) {
|
||||
position = yield select(
|
||||
selectors.selectNextCustomFieldGroupPositionInBoard,
|
||||
customFieldGroup.boardId,
|
||||
index,
|
||||
id,
|
||||
);
|
||||
} else if (customFieldGroup.cardId) {
|
||||
position = yield select(
|
||||
selectors.selectNextCustomFieldGroupPositionInCard,
|
||||
customFieldGroup.cardId,
|
||||
index,
|
||||
id,
|
||||
);
|
||||
}
|
||||
|
||||
yield call(updateCustomFieldGroup, id, {
|
||||
position,
|
||||
});
|
||||
}
|
||||
|
||||
export function* deleteCustomFieldGroup(id) {
|
||||
yield put(actions.deleteCustomFieldGroup(id));
|
||||
|
||||
let customFieldGroup;
|
||||
try {
|
||||
({ item: customFieldGroup } = yield call(request, api.deleteCustomFieldGroup, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteCustomFieldGroup.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteCustomFieldGroup.success(customFieldGroup));
|
||||
}
|
||||
|
||||
export function* handleCustomFieldGroupDelete(customFieldGroup) {
|
||||
yield put(actions.handleCustomFieldGroupDelete(customFieldGroup));
|
||||
}
|
||||
|
||||
export default {
|
||||
createCustomFieldGroupInBoard,
|
||||
createCustomFieldGroupInCurrentBoard,
|
||||
createCustomFieldGroupInCard,
|
||||
createCustomFieldGroupInCurrentCard,
|
||||
handleCustomFieldGroupCreate,
|
||||
updateCustomFieldGroup,
|
||||
handleCustomFieldGroupUpdate,
|
||||
moveCustomFieldGroup,
|
||||
deleteCustomFieldGroup,
|
||||
handleCustomFieldGroupDelete,
|
||||
};
|
||||
@@ -0,0 +1,83 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { buildCustomFieldValueId } from '../../../models/CustomFieldValue';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* updateCustomFieldValue(cardId, customFieldGroupId, customFieldId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.updateCustomFieldValue({
|
||||
...data,
|
||||
cardId,
|
||||
customFieldGroupId,
|
||||
customFieldId,
|
||||
}),
|
||||
);
|
||||
|
||||
let customFieldValue;
|
||||
try {
|
||||
({ item: customFieldValue } = yield call(
|
||||
request,
|
||||
api.updateCustomFieldValue,
|
||||
cardId,
|
||||
customFieldGroupId,
|
||||
customFieldId,
|
||||
data,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.updateCustomFieldValue.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateCustomFieldValue.success(localId, customFieldValue));
|
||||
}
|
||||
|
||||
export function* handleCustomFieldValueUpdate(customFieldValue) {
|
||||
yield put(actions.handleCustomFieldValueUpdate(customFieldValue));
|
||||
}
|
||||
|
||||
export function* deleteCustomFieldValue(cardId, customFieldGroupId, customFieldId) {
|
||||
const id = buildCustomFieldValueId({
|
||||
cardId,
|
||||
customFieldGroupId,
|
||||
customFieldId,
|
||||
});
|
||||
|
||||
yield put(actions.deleteCustomFieldValue(id));
|
||||
|
||||
let customFieldValue;
|
||||
try {
|
||||
({ item: customFieldValue } = yield call(
|
||||
request,
|
||||
api.deleteCustomFieldValue,
|
||||
cardId,
|
||||
customFieldGroupId,
|
||||
customFieldId,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteCustomFieldValue.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteCustomFieldValue.success(customFieldValue));
|
||||
}
|
||||
|
||||
export function* handleCustomFieldValueDelete(customFieldValue) {
|
||||
yield put(actions.handleCustomFieldValueDelete(customFieldValue));
|
||||
}
|
||||
|
||||
export default {
|
||||
updateCustomFieldValue,
|
||||
handleCustomFieldValueUpdate,
|
||||
deleteCustomFieldValue,
|
||||
handleCustomFieldValueDelete,
|
||||
};
|
||||
@@ -0,0 +1,155 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createCustomFieldInBaseGroup(baseCustomFieldGroupId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(
|
||||
selectors.selectNextCustomFieldPositionInBaseGroup,
|
||||
baseCustomFieldGroupId,
|
||||
),
|
||||
};
|
||||
|
||||
yield put(
|
||||
actions.createCustomField({
|
||||
...nextData,
|
||||
baseCustomFieldGroupId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let customField;
|
||||
try {
|
||||
({ item: customField } = yield call(
|
||||
request,
|
||||
api.createCustomFieldInBaseGroup,
|
||||
baseCustomFieldGroupId,
|
||||
nextData,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createCustomField.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createCustomField.success(localId, customField));
|
||||
}
|
||||
|
||||
export function* createCustomFieldInGroup(customFieldGroupId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextCustomFieldPositionInGroup, customFieldGroupId),
|
||||
};
|
||||
|
||||
yield put(
|
||||
actions.createCustomField({
|
||||
...nextData,
|
||||
customFieldGroupId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let customField;
|
||||
try {
|
||||
({ item: customField } = yield call(
|
||||
request,
|
||||
api.createCustomFieldInGroup,
|
||||
customFieldGroupId,
|
||||
nextData,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createCustomField.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createCustomField.success(localId, customField));
|
||||
}
|
||||
|
||||
export function* handleCustomFieldCreate(customField) {
|
||||
yield put(actions.handleCustomFieldCreate(customField));
|
||||
}
|
||||
|
||||
export function* updateCustomField(id, data) {
|
||||
yield put(actions.updateCustomField(id, data));
|
||||
|
||||
let customField;
|
||||
try {
|
||||
({ item: customField } = yield call(request, api.updateCustomField, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.updateCustomField.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateCustomField.success(customField));
|
||||
}
|
||||
|
||||
export function* handleCustomFieldUpdate(customField) {
|
||||
yield put(actions.handleCustomFieldUpdate(customField));
|
||||
}
|
||||
|
||||
export function* moveCustomField(id, index) {
|
||||
const customField = yield select(selectors.selectCustomFieldById, id);
|
||||
|
||||
let position;
|
||||
if (customField.baseCustomFieldGroupId) {
|
||||
position = yield select(
|
||||
selectors.selectNextCustomFieldPositionInBaseGroup,
|
||||
customField.baseCustomFieldGroupId,
|
||||
index,
|
||||
id,
|
||||
);
|
||||
} else if (customField.customFieldGroupId) {
|
||||
position = yield select(
|
||||
selectors.selectNextCustomFieldPositionInGroup,
|
||||
customField.customFieldGroupId,
|
||||
index,
|
||||
id,
|
||||
);
|
||||
}
|
||||
|
||||
yield call(updateCustomField, id, {
|
||||
position,
|
||||
});
|
||||
}
|
||||
|
||||
export function* deleteCustomField(id) {
|
||||
yield put(actions.deleteCustomField(id));
|
||||
|
||||
let customField;
|
||||
try {
|
||||
({ item: customField } = yield call(request, api.deleteCustomField, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteCustomField.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteCustomField.success(customField));
|
||||
}
|
||||
|
||||
export function* handleCustomFieldDelete(customField) {
|
||||
yield put(actions.handleCustomFieldDelete(customField));
|
||||
}
|
||||
|
||||
export default {
|
||||
createCustomFieldInBaseGroup,
|
||||
createCustomFieldInGroup,
|
||||
handleCustomFieldCreate,
|
||||
updateCustomField,
|
||||
handleCustomFieldUpdate,
|
||||
moveCustomField,
|
||||
deleteCustomField,
|
||||
handleCustomFieldDelete,
|
||||
};
|
||||
@@ -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 router from './router';
|
||||
import socket from './socket';
|
||||
import core from './core';
|
||||
@@ -5,16 +10,23 @@ import modals from './modals';
|
||||
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 commentActivities from './comment-activities';
|
||||
import notifications from './notifications';
|
||||
import notificationServices from './notification-services';
|
||||
|
||||
export default {
|
||||
...router,
|
||||
@@ -24,14 +36,21 @@ export default {
|
||||
...users,
|
||||
...projects,
|
||||
...projectManagers,
|
||||
...backgroundImages,
|
||||
...baseCustomFieldGroups,
|
||||
...boards,
|
||||
...boardMemberships,
|
||||
...labels,
|
||||
...lists,
|
||||
...cards,
|
||||
...taskLists,
|
||||
...tasks,
|
||||
...attachments,
|
||||
...customFieldGroups,
|
||||
...customFields,
|
||||
...customFieldValues,
|
||||
...comments,
|
||||
...activities,
|
||||
...commentActivities,
|
||||
...notifications,
|
||||
...notificationServices,
|
||||
};
|
||||
|
||||
@@ -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 { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
@@ -7,13 +12,13 @@ import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createLabel(boardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextLabelPosition, boardId),
|
||||
};
|
||||
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.createLabel({
|
||||
...nextData,
|
||||
@@ -39,6 +44,44 @@ export function* createLabelInCurrentBoard(data) {
|
||||
yield call(createLabel, boardId, data);
|
||||
}
|
||||
|
||||
export function* createLabelFromCard(cardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
const { boardId } = yield select(selectors.selectCardById, cardId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextLabelPosition, boardId),
|
||||
};
|
||||
|
||||
yield put(
|
||||
actions.createLabelFromCard(cardId, {
|
||||
...nextData,
|
||||
boardId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let label;
|
||||
try {
|
||||
({ item: label } = yield call(request, api.createLabel, boardId, nextData));
|
||||
} catch (error) {
|
||||
yield put(actions.createLabelFromCard.failure(cardId, localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
let cardLabel;
|
||||
try {
|
||||
({ item: cardLabel } = yield call(request, api.createCardLabel, cardId, {
|
||||
labelId: label.id,
|
||||
}));
|
||||
} catch (error) {
|
||||
yield put(actions.createLabelFromCard.failure(cardId, localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createLabelFromCard.success(localId, label, cardLabel));
|
||||
}
|
||||
|
||||
export function* handleLabelCreate(label) {
|
||||
yield put(actions.handleLabelCreate(label));
|
||||
}
|
||||
@@ -139,7 +182,9 @@ export function* handleLabelFromCardRemove(cardLabel) {
|
||||
}
|
||||
|
||||
export function* addLabelToBoardFilter(id, boardId) {
|
||||
yield put(actions.addLabelToBoardFilter(id, boardId));
|
||||
const currentListId = yield select(selectors.selectCurrentListId);
|
||||
|
||||
yield put(actions.addLabelToBoardFilter(id, boardId, currentListId));
|
||||
}
|
||||
|
||||
export function* addLabelToFilterInCurrentBoard(id) {
|
||||
@@ -149,7 +194,9 @@ export function* addLabelToFilterInCurrentBoard(id) {
|
||||
}
|
||||
|
||||
export function* removeLabelFromBoardFilter(id, boardId) {
|
||||
yield put(actions.removeLabelFromBoardFilter(id, boardId));
|
||||
const currentListId = yield select(selectors.selectCurrentListId);
|
||||
|
||||
yield put(actions.removeLabelFromBoardFilter(id, boardId, currentListId));
|
||||
}
|
||||
|
||||
export function* removeLabelFromFilterInCurrentBoard(id) {
|
||||
@@ -161,6 +208,7 @@ export function* removeLabelFromFilterInCurrentBoard(id) {
|
||||
export default {
|
||||
createLabel,
|
||||
createLabelInCurrentBoard,
|
||||
createLabelFromCard,
|
||||
handleLabelCreate,
|
||||
updateLabel,
|
||||
handleLabelUpdate,
|
||||
|
||||
@@ -1,19 +1,26 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
import ToastTypes from '../../../constants/ToastTypes';
|
||||
|
||||
export function* createList(boardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextListPosition, boardId),
|
||||
};
|
||||
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.createList({
|
||||
...nextData,
|
||||
@@ -70,7 +77,6 @@ export function* moveList(id, index) {
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: sort locally
|
||||
export function* sortList(id, data) {
|
||||
yield put(actions.sortList(id, data));
|
||||
|
||||
@@ -90,26 +96,91 @@ export function* sortList(id, data) {
|
||||
yield put(actions.sortList.success(list, cards));
|
||||
}
|
||||
|
||||
export function* handleListSort(list, cards) {
|
||||
yield put(actions.handleListSort(list, cards));
|
||||
export function* moveListCards(id, nextId) {
|
||||
const cardIds = yield select(selectors.selectCardIdsByListId, id);
|
||||
|
||||
if (cardIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.moveListCards(id, nextId, cardIds));
|
||||
|
||||
let list;
|
||||
let cards;
|
||||
let activities;
|
||||
|
||||
try {
|
||||
({
|
||||
item: list,
|
||||
included: { cards, activities },
|
||||
} = yield call(request, api.moveListCards, id, {
|
||||
listId: nextId,
|
||||
}));
|
||||
} catch (error) {
|
||||
yield put(actions.moveListCards.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.moveListCards.success(list, cards, activities));
|
||||
}
|
||||
|
||||
export function* deleteList(id) {
|
||||
yield put(actions.deleteList(id));
|
||||
export function* moveListCardsToArchiveList(id) {
|
||||
const archiveListId = yield select(selectors.selectArchiveListIdForCurrentBoard);
|
||||
|
||||
yield call(moveListCards, id, archiveListId);
|
||||
}
|
||||
|
||||
export function* clearTrashListInCurrentBoard() {
|
||||
const trashListId = yield select(selectors.selectTrashListIdForCurrentBoard);
|
||||
|
||||
yield put(actions.clearList(trashListId));
|
||||
|
||||
yield call(toast, {
|
||||
type: ToastTypes.EMPTY_TRASH,
|
||||
params: {
|
||||
listId: trashListId,
|
||||
},
|
||||
});
|
||||
|
||||
let list;
|
||||
try {
|
||||
({ item: list } = yield call(request, api.deleteList, id));
|
||||
({ item: list } = yield call(request, api.clearList, trashListId));
|
||||
} catch (error) {
|
||||
yield put(actions.clearList.failure(trashListId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.clearList.success(list));
|
||||
}
|
||||
|
||||
export function* handleListClear(list) {
|
||||
yield put(actions.handleListClear(list));
|
||||
}
|
||||
|
||||
export function* deleteList(id) {
|
||||
const trashListId = yield select(selectors.selectTrashListIdForCurrentBoard);
|
||||
const cardIds = yield select(selectors.selectCardIdsByListId, id);
|
||||
|
||||
yield put(actions.deleteList(id, trashListId, cardIds));
|
||||
|
||||
let list;
|
||||
let cards;
|
||||
|
||||
try {
|
||||
({
|
||||
item: list,
|
||||
included: { cards },
|
||||
} = yield call(request, api.deleteList, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteList.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteList.success(list));
|
||||
yield put(actions.deleteList.success(list, cards));
|
||||
}
|
||||
|
||||
export function* handleListDelete(list) {
|
||||
yield put(actions.handleListDelete(list));
|
||||
export function* handleListDelete(list, cards) {
|
||||
yield put(actions.handleListDelete(list, cards));
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -120,7 +191,9 @@ export default {
|
||||
handleListUpdate,
|
||||
moveList,
|
||||
sortList,
|
||||
handleListSort,
|
||||
moveListCardsToArchiveList,
|
||||
clearTrashListInCurrentBoard,
|
||||
handleListClear,
|
||||
deleteList,
|
||||
handleListDelete,
|
||||
};
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { put } from 'redux-saga/effects';
|
||||
|
||||
import actions from '../../../actions';
|
||||
|
||||
export function* openModal(type) {
|
||||
yield put(actions.openModal(type));
|
||||
export function* openModal(type, params) {
|
||||
yield put(actions.openModal(type, params));
|
||||
}
|
||||
|
||||
export function* closeModal() {
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createNotificationServiceInCurrentUser(data) {
|
||||
const localId = yield call(createLocalId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield put(
|
||||
actions.createNotificationService({
|
||||
...data,
|
||||
id: localId,
|
||||
userId: currentUserId,
|
||||
}),
|
||||
);
|
||||
|
||||
let notificationService;
|
||||
try {
|
||||
({ item: notificationService } = yield call(
|
||||
request,
|
||||
api.createNotificationServiceInUser,
|
||||
currentUserId,
|
||||
data,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createNotificationService.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createNotificationService.success(localId, notificationService));
|
||||
}
|
||||
|
||||
export function* createNotificationServiceInBoard(boardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.createNotificationService({
|
||||
...data,
|
||||
boardId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let notificationService;
|
||||
try {
|
||||
({ item: notificationService } = yield call(
|
||||
request,
|
||||
api.createNotificationServiceInBoard,
|
||||
boardId,
|
||||
data,
|
||||
));
|
||||
} catch (error) {
|
||||
yield put(actions.createNotificationService.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createNotificationService.success(localId, notificationService));
|
||||
}
|
||||
|
||||
export function* handleNotificationServiceCreate(notificationService) {
|
||||
yield put(actions.handleNotificationServiceCreate(notificationService));
|
||||
}
|
||||
|
||||
export function* updateNotificationService(id, data) {
|
||||
yield put(actions.updateNotificationService(id, data));
|
||||
|
||||
let notificationService;
|
||||
try {
|
||||
({ item: notificationService } = yield call(request, api.updateNotificationService, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.updateNotificationService.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateNotificationService.success(notificationService));
|
||||
}
|
||||
|
||||
export function* handleNotificationServiceUpdate(notificationService) {
|
||||
yield put(actions.handleNotificationServiceUpdate(notificationService));
|
||||
}
|
||||
|
||||
export function* testNotificationService(id) {
|
||||
yield put(actions.testNotificationService(id));
|
||||
|
||||
let notificationService;
|
||||
try {
|
||||
({ item: notificationService } = yield call(request, api.testNotificationService, id));
|
||||
} catch (error) {
|
||||
yield put(actions.testNotificationService.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.testNotificationService.success(notificationService));
|
||||
}
|
||||
|
||||
export function* deleteNotificationService(id) {
|
||||
yield put(actions.deleteNotificationService(id));
|
||||
|
||||
let notificationService;
|
||||
try {
|
||||
({ item: notificationService } = yield call(request, api.deleteNotificationService, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteNotificationService.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteNotificationService.success(notificationService));
|
||||
}
|
||||
|
||||
export function* handleNotificationServiceDelete(notificationService) {
|
||||
yield put(actions.handleNotificationServiceDelete(notificationService));
|
||||
}
|
||||
|
||||
export default {
|
||||
createNotificationServiceInCurrentUser,
|
||||
createNotificationServiceInBoard,
|
||||
handleNotificationServiceCreate,
|
||||
updateNotificationService,
|
||||
handleNotificationServiceUpdate,
|
||||
testNotificationService,
|
||||
deleteNotificationService,
|
||||
handleNotificationServiceDelete,
|
||||
};
|
||||
@@ -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 { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
@@ -5,38 +10,42 @@ import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
|
||||
export function* handleNotificationCreate(notification) {
|
||||
export function* deleteAllNotifications() {
|
||||
yield put(actions.deleteAllNotifications());
|
||||
|
||||
let notifications;
|
||||
try {
|
||||
({ items: notifications } = yield call(request, api.readAllNotifications));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteAllNotifications.failure(error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteAllNotifications.success(notifications));
|
||||
}
|
||||
|
||||
export function* handleNotificationCreate(notification, users) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
if (notification.cardId === cardId) {
|
||||
try {
|
||||
yield call(request, api.updateNotifications, [notification.id], {
|
||||
yield call(request, api.updateNotification, notification.id, {
|
||||
isRead: true,
|
||||
});
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
} else {
|
||||
let users;
|
||||
let cards;
|
||||
let activities;
|
||||
|
||||
try {
|
||||
({
|
||||
included: { users, cards, activities },
|
||||
} = yield call(request, api.getNotification, notification.id));
|
||||
} catch {
|
||||
return;
|
||||
/* empty */
|
||||
}
|
||||
|
||||
yield put(actions.handleNotificationCreate(notification, users, cards, activities));
|
||||
} else {
|
||||
yield put(actions.handleNotificationCreate(notification, users));
|
||||
}
|
||||
}
|
||||
|
||||
export function* deleteNotification(id) {
|
||||
yield put(actions.deleteNotification(id));
|
||||
|
||||
let notifications;
|
||||
let notification;
|
||||
try {
|
||||
({ items: notifications } = yield call(request, api.updateNotifications, [id], {
|
||||
({ item: notification } = yield call(request, api.updateNotification, id, {
|
||||
isRead: true,
|
||||
}));
|
||||
} catch (error) {
|
||||
@@ -44,7 +53,7 @@ export function* deleteNotification(id) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteNotification.success(notifications[0]));
|
||||
yield put(actions.deleteNotification.success(notification));
|
||||
}
|
||||
|
||||
export function* handleNotificationDelete(notification) {
|
||||
@@ -52,6 +61,7 @@ export function* handleNotificationDelete(notification) {
|
||||
}
|
||||
|
||||
export default {
|
||||
deleteAllNotifications,
|
||||
handleNotificationCreate,
|
||||
deleteNotification,
|
||||
handleNotificationDelete,
|
||||
|
||||
@@ -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 { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
@@ -36,16 +41,17 @@ export function* createManagerInCurrentProject(data) {
|
||||
yield call(createProjectManager, projectId, data);
|
||||
}
|
||||
|
||||
export function* handleProjectManagerCreate(projectManager) {
|
||||
export function* handleProjectManagerCreate(projectManager, users) {
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const isCurrentUser = projectManager.userId === currentUserId;
|
||||
|
||||
let user;
|
||||
let project;
|
||||
let board;
|
||||
let users1;
|
||||
let users2;
|
||||
let projectManagers;
|
||||
let backgroundImages;
|
||||
let baseCustomFieldGroups;
|
||||
let boards;
|
||||
let boardMemberships1;
|
||||
let boardMemberships2;
|
||||
@@ -54,69 +60,95 @@ export function* handleProjectManagerCreate(projectManager) {
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let deletedNotifications;
|
||||
let customFieldGroups;
|
||||
let customFields1;
|
||||
let customFields2;
|
||||
let customFieldValues;
|
||||
let notificationsToDelete;
|
||||
let notificationServices;
|
||||
|
||||
if (isCurrentUser) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(
|
||||
actions.handleProjectManagerCreate.fetchProject(
|
||||
projectManager.projectId,
|
||||
currentUserId,
|
||||
boardId,
|
||||
),
|
||||
const isExternalAccessibleForCurrentUser = yield select(
|
||||
selectors.selectIsProjectWithIdExternalAccessibleForCurrentUser,
|
||||
projectManager.projectId,
|
||||
);
|
||||
|
||||
try {
|
||||
({
|
||||
item: project,
|
||||
included: { users: users1, projectManagers, boards, boardMemberships: boardMemberships1 },
|
||||
included: {
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
notificationServices,
|
||||
users: users1,
|
||||
boardMemberships: boardMemberships1,
|
||||
customFields: customFields1,
|
||||
},
|
||||
} = yield call(request, api.getProject, projectManager.projectId));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
let body;
|
||||
try {
|
||||
body = yield call(requests.fetchBoardByCurrentPath);
|
||||
} catch {} // eslint-disable-line no-empty
|
||||
if (boardId === null && !isExternalAccessibleForCurrentUser) {
|
||||
let body;
|
||||
try {
|
||||
body = yield call(requests.fetchBoardByCurrentPath);
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
if (body && body.project && body.project.id === projectManager.projectId) {
|
||||
({
|
||||
project,
|
||||
board,
|
||||
users: users2,
|
||||
boardMemberships: boardMemberships2,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
tasks,
|
||||
attachments,
|
||||
} = body);
|
||||
if (body) {
|
||||
({
|
||||
project,
|
||||
board,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFieldValues,
|
||||
users: users2,
|
||||
boardMemberships: boardMemberships2,
|
||||
customFields: customFields2,
|
||||
} = body);
|
||||
|
||||
if (body.card) {
|
||||
deletedNotifications = yield select(selectors.selectNotificationsByCardId, body.card.id);
|
||||
if (body.card) {
|
||||
notificationsToDelete = yield select(selectors.selectNotificationsByCardId, body.card.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
({ item: user } = yield call(request, api.getUser, projectManager.userId));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
const boardIds = yield select(selectors.selectBoardIdsByProjectId, projectManager.projectId);
|
||||
|
||||
const isProjectAvailable = yield select(
|
||||
selectors.selectIsProjectWithIdAvailableForCurrentUser,
|
||||
projectManager.projectId,
|
||||
);
|
||||
|
||||
yield put(
|
||||
actions.handleProjectManagerCreate(
|
||||
projectManager,
|
||||
boardIds,
|
||||
isCurrentUser,
|
||||
isProjectAvailable,
|
||||
project,
|
||||
board,
|
||||
isCurrentUser ? mergeRecords(users1, users2) : [user],
|
||||
mergeRecords(users, users1, users2),
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
mergeRecords(boardMemberships1, boardMemberships2),
|
||||
labels,
|
||||
@@ -124,26 +156,31 @@ export function* handleProjectManagerCreate(projectManager) {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
deletedNotifications,
|
||||
customFieldGroups,
|
||||
mergeRecords(customFields1, customFields2),
|
||||
customFieldValues,
|
||||
notificationsToDelete,
|
||||
notificationServices,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function* deleteProjectManager(id) {
|
||||
let projectManager = yield select(selectors.selectProjectManagerById, id);
|
||||
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const { projectId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(
|
||||
actions.deleteProjectManager(
|
||||
id,
|
||||
projectManager.userId === currentUserId,
|
||||
projectManager.projectId === projectId,
|
||||
),
|
||||
);
|
||||
yield put(actions.deleteProjectManager(id));
|
||||
|
||||
if (projectManager.userId === currentUserId) {
|
||||
const isAvailableForCurrentUser = yield select(selectors.isCurrentModalAvailableForCurrentUser);
|
||||
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield put(actions.closeModal());
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
({ item: projectManager } = yield call(request, api.deleteProjectManager, id));
|
||||
@@ -157,15 +194,16 @@ export function* deleteProjectManager(id) {
|
||||
|
||||
export function* handleProjectManagerDelete(projectManager) {
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const { projectId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(
|
||||
actions.handleProjectManagerDelete(
|
||||
projectManager,
|
||||
projectManager.userId === currentUserId,
|
||||
projectManager.projectId === projectId,
|
||||
),
|
||||
);
|
||||
yield put(actions.handleProjectManagerDelete(projectManager));
|
||||
|
||||
if (projectManager.userId === currentUserId) {
|
||||
const isAvailableForCurrentUser = yield select(selectors.isCurrentModalAvailableForCurrentUser);
|
||||
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield put(actions.closeModal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -1,13 +1,44 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import omit from 'lodash/omit';
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import { goToProject, goToRoot } from './router';
|
||||
import request from '../request';
|
||||
import requests from '../requests';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import mergeRecords from '../../../utils/merge-records';
|
||||
import { UserRoles } from '../../../constants/Enums';
|
||||
|
||||
export function* searchProjects(value) {
|
||||
yield put(actions.searchProjects(value));
|
||||
}
|
||||
|
||||
export function* updateProjectsOrder(value) {
|
||||
yield put(actions.updateProjectsOrder(value));
|
||||
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
try {
|
||||
yield call(request, api.updateUser, currentUserId, {
|
||||
defaultProjectsOrder: value,
|
||||
});
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
|
||||
export function* toggleHiddenProjects(isVisible) {
|
||||
yield put(actions.toggleHiddenProjects(isVisible));
|
||||
}
|
||||
|
||||
export function* createProject(data) {
|
||||
yield put(actions.createProject(data));
|
||||
yield put(actions.createProject(omit(data, 'type')));
|
||||
|
||||
let project;
|
||||
let projectManagers;
|
||||
@@ -30,24 +61,55 @@ export function* handleProjectCreate({ id }) {
|
||||
let project;
|
||||
let users;
|
||||
let projectManagers;
|
||||
let backgroundImages;
|
||||
let baseCustomFieldGroups;
|
||||
let boards;
|
||||
let boardMemberships;
|
||||
let customFields;
|
||||
let notificationServices;
|
||||
|
||||
try {
|
||||
({
|
||||
item: project,
|
||||
included: { users, projectManagers, boards, boardMemberships },
|
||||
included: {
|
||||
users,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
boardMemberships,
|
||||
customFields,
|
||||
notificationServices,
|
||||
},
|
||||
} = yield call(request, api.getProject, id));
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.handleProjectCreate(project, users, projectManagers, boards, boardMemberships));
|
||||
yield put(
|
||||
actions.handleProjectCreate(
|
||||
project,
|
||||
users,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
boardMemberships,
|
||||
customFields,
|
||||
notificationServices,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export function* updateProject(id, data) {
|
||||
yield put(actions.updateProject(id, data));
|
||||
|
||||
const isAvailableForCurrentUser = yield select(selectors.isCurrentModalAvailableForCurrentUser);
|
||||
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield put(actions.closeModal());
|
||||
}
|
||||
|
||||
let project;
|
||||
try {
|
||||
({ item: project } = yield call(request, api.updateProject, id, data));
|
||||
@@ -66,38 +128,148 @@ export function* updateCurrentProject(data) {
|
||||
}
|
||||
|
||||
export function* handleProjectUpdate(project) {
|
||||
yield put(actions.handleProjectUpdate(project));
|
||||
}
|
||||
const prevProject = yield select(selectors.selectProjectById, project.id);
|
||||
|
||||
export function* updateProjectBackgroundImage(id, data) {
|
||||
yield put(actions.updateProjectBackgroundImage(id));
|
||||
const isChangedToShared =
|
||||
(!prevProject || !!prevProject.ownerProjectManagerId) && !project.ownerProjectManagerId;
|
||||
|
||||
let project;
|
||||
try {
|
||||
({ item: project } = yield call(request, api.updateProjectBackgroundImage, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.updateProjectBackgroundImage.failure(id, error));
|
||||
return;
|
||||
const currentUser = yield select(selectors.selectCurrentUser);
|
||||
const isCurrentUserAdmin = currentUser.role === UserRoles.ADMIN;
|
||||
|
||||
const isExternalAccessibleForCurrentUser = yield select(
|
||||
selectors.selectIsProjectWithIdExternalAccessibleForCurrentUser,
|
||||
project.id,
|
||||
);
|
||||
|
||||
let board;
|
||||
let users1;
|
||||
let users2;
|
||||
let projectManagers;
|
||||
let backgroundImages;
|
||||
let baseCustomFieldGroups;
|
||||
let boards;
|
||||
let boardMemberships1;
|
||||
let boardMemberships2;
|
||||
let labels;
|
||||
let lists;
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let customFieldGroups;
|
||||
let customFields1;
|
||||
let customFields2;
|
||||
let customFieldValues;
|
||||
let notificationsToDelete;
|
||||
let notificationServices;
|
||||
|
||||
if (isCurrentUserAdmin && isChangedToShared && !isExternalAccessibleForCurrentUser) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
try {
|
||||
({
|
||||
item: project, // eslint-disable-line no-param-reassign
|
||||
included: {
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
notificationServices,
|
||||
users: users1,
|
||||
boardMemberships: boardMemberships1,
|
||||
customFields: customFields1,
|
||||
},
|
||||
} = yield call(request, api.getProject, project.id));
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
if (boardId === null) {
|
||||
let body;
|
||||
try {
|
||||
body = yield call(requests.fetchBoardByCurrentPath);
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
if (body) {
|
||||
({
|
||||
board,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFieldValues,
|
||||
users: users2,
|
||||
boardMemberships: boardMemberships2,
|
||||
customFields: customFields2,
|
||||
} = body);
|
||||
|
||||
if (body.card) {
|
||||
notificationsToDelete = yield select(selectors.selectNotificationsByCardId, body.card.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield put(actions.updateProjectBackgroundImage.success(project));
|
||||
}
|
||||
const boardIds = yield select(selectors.selectBoardIdsByProjectId, project.id);
|
||||
|
||||
export function* updateCurrentProjectBackgroundImage(data) {
|
||||
const { projectId } = yield select(selectors.selectPath);
|
||||
const isAvailable = yield select(
|
||||
selectors.selectIsProjectWithIdAvailableForCurrentUser,
|
||||
project.id,
|
||||
);
|
||||
|
||||
yield call(updateProjectBackgroundImage, projectId, data);
|
||||
yield put(
|
||||
actions.handleProjectUpdate(
|
||||
project,
|
||||
boardIds,
|
||||
isAvailable,
|
||||
board,
|
||||
mergeRecords(users1, users2),
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
mergeRecords(boardMemberships1, boardMemberships2),
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
mergeRecords(customFields1, customFields2),
|
||||
customFieldValues,
|
||||
notificationsToDelete,
|
||||
notificationServices,
|
||||
),
|
||||
);
|
||||
|
||||
const isAvailableForCurrentUser = yield select(selectors.isCurrentModalAvailableForCurrentUser);
|
||||
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield put(actions.closeModal());
|
||||
}
|
||||
}
|
||||
|
||||
export function* deleteProject(id) {
|
||||
const { projectId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(actions.deleteProject(id));
|
||||
|
||||
if (id === projectId) {
|
||||
yield call(goToRoot);
|
||||
}
|
||||
|
||||
yield put(actions.deleteProject(id));
|
||||
|
||||
let project;
|
||||
try {
|
||||
({ item: project } = yield call(request, api.deleteProject, id));
|
||||
@@ -118,21 +290,22 @@ export function* deleteCurrentProject() {
|
||||
export function* handleProjectDelete(project) {
|
||||
const { projectId } = yield select(selectors.selectPath);
|
||||
|
||||
yield put(actions.handleProjectDelete(project));
|
||||
|
||||
if (project.id === projectId) {
|
||||
yield call(goToRoot);
|
||||
}
|
||||
|
||||
yield put(actions.handleProjectDelete(project));
|
||||
}
|
||||
|
||||
export default {
|
||||
searchProjects,
|
||||
updateProjectsOrder,
|
||||
toggleHiddenProjects,
|
||||
createProject,
|
||||
handleProjectCreate,
|
||||
updateProject,
|
||||
updateCurrentProject,
|
||||
handleProjectUpdate,
|
||||
updateProjectBackgroundImage,
|
||||
updateCurrentProjectBackgroundImage,
|
||||
deleteProject,
|
||||
deleteCurrentProject,
|
||||
handleProjectDelete,
|
||||
|
||||
@@ -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 { call, put, select, take } from 'redux-saga/effects';
|
||||
import { push } from '../../../lib/redux-router';
|
||||
|
||||
@@ -7,23 +12,28 @@ import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { getAccessToken } from '../../../utils/access-token-storage';
|
||||
import mergeRecords from '../../../utils/merge-records';
|
||||
import ActionTypes from '../../../constants/ActionTypes';
|
||||
import Paths from '../../../constants/Paths';
|
||||
|
||||
export function* goTo(pathname) {
|
||||
yield put(push(pathname));
|
||||
}
|
||||
|
||||
export function* goToRoot() {
|
||||
yield put(push(Paths.ROOT));
|
||||
yield call(goTo, Paths.ROOT);
|
||||
}
|
||||
|
||||
export function* goToProject(projectId) {
|
||||
yield put(push(Paths.PROJECTS.replace(':id', projectId)));
|
||||
yield call(goTo, Paths.PROJECTS.replace(':id', projectId));
|
||||
}
|
||||
|
||||
export function* goToBoard(boardId) {
|
||||
yield put(push(Paths.BOARDS.replace(':id', boardId)));
|
||||
yield call(goTo, Paths.BOARDS.replace(':id', boardId));
|
||||
}
|
||||
|
||||
export function* goToCard(cardId) {
|
||||
yield put(push(Paths.CARDS.replace(':id', cardId)));
|
||||
yield call(goTo, Paths.CARDS.replace(':id', cardId));
|
||||
}
|
||||
|
||||
export function* handleLocationChange() {
|
||||
@@ -45,7 +55,7 @@ export function* handleLocationChange() {
|
||||
case Paths.OIDC_CALLBACK:
|
||||
yield call(goToRoot);
|
||||
|
||||
return;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
@@ -55,87 +65,197 @@ export function* handleLocationChange() {
|
||||
yield take(ActionTypes.CORE_INITIALIZE);
|
||||
}
|
||||
|
||||
let currentBoard = yield select(selectors.selectCurrentBoard);
|
||||
|
||||
let currentBoardId = null;
|
||||
let currentCardId = null;
|
||||
let isEditModeEnabled;
|
||||
let board;
|
||||
let users;
|
||||
let card;
|
||||
let users1;
|
||||
let users2;
|
||||
let projects;
|
||||
let boardMemberships;
|
||||
let labels;
|
||||
let lists;
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let deletedNotifications;
|
||||
let cardMemberships1;
|
||||
let cardMemberships2;
|
||||
let cardLabels1;
|
||||
let cardLabels2;
|
||||
let taskLists1;
|
||||
let taskLists2;
|
||||
let tasks1;
|
||||
let tasks2;
|
||||
let attachments1;
|
||||
let attachments2;
|
||||
let customFieldGroups1;
|
||||
let customFieldGroups2;
|
||||
let customFields1;
|
||||
let customFields2;
|
||||
let customFieldValues1;
|
||||
let customFieldValues2;
|
||||
let notificationsToDelete;
|
||||
|
||||
switch (pathsMatch.pattern.path) {
|
||||
case Paths.BOARDS:
|
||||
case Paths.CARDS: {
|
||||
const currentBoard = yield select(selectors.selectCurrentBoard);
|
||||
case Paths.ROOT:
|
||||
isEditModeEnabled = false;
|
||||
|
||||
if (currentBoard && currentBoard.isFetching === null) {
|
||||
yield put(actions.handleLocationChange.fetchBoard(currentBoard.id));
|
||||
break;
|
||||
case Paths.PROJECTS: {
|
||||
const boardIds = yield select(selectors.selectBoardIdsForCurrentProject);
|
||||
|
||||
try {
|
||||
({
|
||||
item: board,
|
||||
included: {
|
||||
users,
|
||||
projects,
|
||||
boardMemberships,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
tasks,
|
||||
attachments,
|
||||
},
|
||||
} = yield call(request, api.getBoard, currentBoard.id, true));
|
||||
} catch (error) {} // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
if (pathsMatch.pattern.path === Paths.CARDS) {
|
||||
const notificationIds = yield select(selectors.selectNotificationIdsForCurrentCard);
|
||||
|
||||
if (notificationIds && notificationIds.length > 0) {
|
||||
try {
|
||||
({ items: deletedNotifications } = yield call(
|
||||
request,
|
||||
api.updateNotifications,
|
||||
notificationIds,
|
||||
{
|
||||
isRead: true,
|
||||
},
|
||||
));
|
||||
} catch (error) {} // eslint-disable-line no-empty
|
||||
}
|
||||
if (boardIds && boardIds.length === 0) {
|
||||
isEditModeEnabled = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Paths.BOARDS:
|
||||
if (currentBoard) {
|
||||
({ id: currentBoardId } = currentBoard);
|
||||
|
||||
if (currentBoard.isFetching === null) {
|
||||
yield put(actions.handleLocationChange.fetchBoard(currentBoard.id));
|
||||
|
||||
try {
|
||||
({
|
||||
item: board,
|
||||
included: {
|
||||
projects,
|
||||
boardMemberships,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
users: users1,
|
||||
cardMemberships: cardMemberships1,
|
||||
cardLabels: cardLabels1,
|
||||
taskLists: taskLists1,
|
||||
tasks: tasks1,
|
||||
attachments: attachments1,
|
||||
customFieldGroups: customFieldGroups1,
|
||||
customFields: customFields1,
|
||||
customFieldValues: customFieldValues1,
|
||||
},
|
||||
} = yield call(request, api.getBoard, currentBoard.id, true));
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case Paths.CARDS:
|
||||
({ cardId: currentCardId, boardId: currentBoardId } = yield select(selectors.selectPath));
|
||||
|
||||
if (!currentCardId) {
|
||||
yield put(actions.handleLocationChange.fetchContent());
|
||||
|
||||
try {
|
||||
({
|
||||
item: card,
|
||||
included: {
|
||||
users: users1,
|
||||
cardMemberships: cardMemberships1,
|
||||
cardLabels: cardLabels1,
|
||||
taskLists: taskLists1,
|
||||
tasks: tasks1,
|
||||
attachments: attachments1,
|
||||
customFieldGroups: customFieldGroups1,
|
||||
customFields: customFields1,
|
||||
customFieldValues: customFieldValues1,
|
||||
},
|
||||
} = yield call(request, api.getCard, pathsMatch.params.id));
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
if (card) {
|
||||
({ id: currentCardId } = card);
|
||||
|
||||
currentBoard = yield select(selectors.selectBoardById, card.boardId);
|
||||
|
||||
if (currentBoard) {
|
||||
({ id: currentBoardId } = currentBoard);
|
||||
|
||||
if (currentBoard.isFetching === null) {
|
||||
try {
|
||||
({
|
||||
item: board,
|
||||
included: {
|
||||
projects,
|
||||
boardMemberships,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
users: users2,
|
||||
cardMemberships: cardMemberships2,
|
||||
cardLabels: cardLabels2,
|
||||
taskLists: taskLists2,
|
||||
tasks: tasks2,
|
||||
attachments: attachments2,
|
||||
customFieldGroups: customFieldGroups2,
|
||||
customFields: customFields2,
|
||||
customFieldValues: customFieldValues2,
|
||||
},
|
||||
} = yield call(request, api.getBoard, card.boardId, true));
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCardId) {
|
||||
const notificationIds = yield select(
|
||||
selectors.selectNotificationIdsByCardId,
|
||||
currentCardId,
|
||||
);
|
||||
|
||||
if (notificationIds.length > 0) {
|
||||
try {
|
||||
({
|
||||
included: { notifications: notificationsToDelete },
|
||||
} = yield call(request, api.readCardNotifications, currentCardId));
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
yield put(
|
||||
actions.handleLocationChange(
|
||||
pathsMatch.pathname,
|
||||
currentBoardId,
|
||||
currentCardId,
|
||||
isEditModeEnabled,
|
||||
board,
|
||||
users,
|
||||
mergeRecords(users1, users2),
|
||||
projects,
|
||||
boardMemberships,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
tasks,
|
||||
attachments,
|
||||
deletedNotifications,
|
||||
mergeRecords(card && [card], cards),
|
||||
mergeRecords(cardMemberships1, cardMemberships2),
|
||||
mergeRecords(cardLabels1, cardLabels2),
|
||||
mergeRecords(taskLists1, taskLists2),
|
||||
mergeRecords(tasks1, tasks2),
|
||||
mergeRecords(attachments1, attachments2),
|
||||
mergeRecords(customFieldGroups1, customFieldGroups2),
|
||||
mergeRecords(customFields1, customFields2),
|
||||
mergeRecords(customFieldValues1, customFieldValues2),
|
||||
notificationsToDelete,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
export default {
|
||||
goTo,
|
||||
goToRoot,
|
||||
goToProject,
|
||||
goToBoard,
|
||||
|
||||
@@ -1,24 +1,34 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import requests from '../requests';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
|
||||
export function* handleSocketDisconnect() {
|
||||
yield put(actions.handleSocketDisconnect());
|
||||
}
|
||||
|
||||
export function* handleSocketReconnect() {
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield put(actions.handleSocketReconnect.fetchCore(currentUserId, boardId));
|
||||
|
||||
let config;
|
||||
let user;
|
||||
let board;
|
||||
let users;
|
||||
let projects;
|
||||
let projectManagers;
|
||||
let backgroundImages;
|
||||
let baseCustomFieldGroups;
|
||||
let boards;
|
||||
let boardMemberships;
|
||||
let labels;
|
||||
@@ -26,18 +36,26 @@ export function* handleSocketReconnect() {
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let activities;
|
||||
let customFieldGroups;
|
||||
let customFields;
|
||||
let customFieldValues;
|
||||
let notifications;
|
||||
let notificationServices;
|
||||
|
||||
try {
|
||||
({ item: config } = yield call(request, api.getConfig));
|
||||
|
||||
({
|
||||
user,
|
||||
board,
|
||||
users,
|
||||
projects,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
boardMemberships,
|
||||
labels,
|
||||
@@ -45,22 +63,29 @@ export function* handleSocketReconnect() {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
activities,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
notifications,
|
||||
notificationServices,
|
||||
} = yield call(requests.fetchCore));
|
||||
} catch (error) {
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(
|
||||
actions.handleSocketReconnect(
|
||||
config,
|
||||
user,
|
||||
board,
|
||||
users,
|
||||
projects,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
boardMemberships,
|
||||
labels,
|
||||
@@ -68,12 +93,22 @@ export function* handleSocketReconnect() {
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
activities,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
notifications,
|
||||
notificationServices,
|
||||
),
|
||||
);
|
||||
|
||||
const isAvailableForCurrentUser = yield select(selectors.isCurrentModalAvailableForCurrentUser);
|
||||
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield put(actions.closeModal());
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createTaskList(cardId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextTaskListPosition, cardId),
|
||||
};
|
||||
|
||||
yield put(
|
||||
actions.createTaskList({
|
||||
...nextData,
|
||||
cardId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let taskList;
|
||||
try {
|
||||
({ item: taskList } = yield call(request, api.createTaskList, cardId, nextData));
|
||||
} catch (error) {
|
||||
yield put(actions.createTaskList.failure(localId, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.createTaskList.success(localId, taskList));
|
||||
}
|
||||
|
||||
export function* createTaskListInCurrentCard(data) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createTaskList, cardId, data);
|
||||
}
|
||||
|
||||
export function* handleTaskListCreate(taskList) {
|
||||
yield put(actions.handleTaskListCreate(taskList));
|
||||
}
|
||||
|
||||
export function* updateTaskList(id, data) {
|
||||
yield put(actions.updateTaskList(id, data));
|
||||
|
||||
let taskList;
|
||||
try {
|
||||
({ item: taskList } = yield call(request, api.updateTaskList, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.updateTaskList.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.updateTaskList.success(taskList));
|
||||
}
|
||||
|
||||
export function* handleTaskListUpdate(taskList) {
|
||||
yield put(actions.handleTaskListUpdate(taskList));
|
||||
}
|
||||
|
||||
export function* moveTaskList(id, index) {
|
||||
const { cardId } = yield select(selectors.selectTaskListById, id);
|
||||
const position = yield select(selectors.selectNextTaskListPosition, cardId, index, id);
|
||||
|
||||
yield call(updateTaskList, id, {
|
||||
position,
|
||||
});
|
||||
}
|
||||
|
||||
export function* deleteTaskList(id) {
|
||||
yield put(actions.deleteTaskList(id));
|
||||
|
||||
let taskList;
|
||||
try {
|
||||
({ item: taskList } = yield call(request, api.deleteTaskList, id));
|
||||
} catch (error) {
|
||||
yield put(actions.deleteTaskList.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.deleteTaskList.success(taskList));
|
||||
}
|
||||
|
||||
export function* handleTaskListDelete(taskList) {
|
||||
yield put(actions.handleTaskListDelete(taskList));
|
||||
}
|
||||
|
||||
export default {
|
||||
createTaskList,
|
||||
createTaskListInCurrentCard,
|
||||
handleTaskListCreate,
|
||||
updateTaskList,
|
||||
handleTaskListUpdate,
|
||||
moveTaskList,
|
||||
deleteTaskList,
|
||||
handleTaskListDelete,
|
||||
};
|
||||
@@ -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 { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import request from '../request';
|
||||
@@ -6,25 +11,25 @@ import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { createLocalId } from '../../../utils/local-id';
|
||||
|
||||
export function* createTask(cardId, data) {
|
||||
export function* createTask(taskListId, data) {
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
const nextData = {
|
||||
...data,
|
||||
position: yield select(selectors.selectNextTaskPosition, cardId),
|
||||
position: yield select(selectors.selectNextTaskPosition, taskListId),
|
||||
};
|
||||
|
||||
const localId = yield call(createLocalId);
|
||||
|
||||
yield put(
|
||||
actions.createTask({
|
||||
...nextData,
|
||||
cardId,
|
||||
taskListId,
|
||||
id: localId,
|
||||
}),
|
||||
);
|
||||
|
||||
let task;
|
||||
try {
|
||||
({ item: task } = yield call(request, api.createTask, cardId, nextData));
|
||||
({ item: task } = yield call(request, api.createTask, taskListId, nextData));
|
||||
} catch (error) {
|
||||
yield put(actions.createTask.failure(localId, error));
|
||||
return;
|
||||
@@ -33,12 +38,6 @@ export function* createTask(cardId, data) {
|
||||
yield put(actions.createTask.success(localId, task));
|
||||
}
|
||||
|
||||
export function* createTaskInCurrentCard(data) {
|
||||
const { cardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(createTask, cardId, data);
|
||||
}
|
||||
|
||||
export function* handleTaskCreate(task) {
|
||||
yield put(actions.handleTaskCreate(task));
|
||||
}
|
||||
@@ -61,11 +60,11 @@ export function* handleTaskUpdate(task) {
|
||||
yield put(actions.handleTaskUpdate(task));
|
||||
}
|
||||
|
||||
export function* moveTask(id, index) {
|
||||
const { cardId } = yield select(selectors.selectTaskById, id);
|
||||
const position = yield select(selectors.selectNextTaskPosition, cardId, index, id);
|
||||
export function* moveTask(id, taskListId, index) {
|
||||
const position = yield select(selectors.selectNextTaskPosition, taskListId, index, id);
|
||||
|
||||
yield call(updateTask, id, {
|
||||
taskListId,
|
||||
position,
|
||||
});
|
||||
}
|
||||
@@ -90,7 +89,6 @@ export function* handleTaskDelete(task) {
|
||||
|
||||
export default {
|
||||
createTask,
|
||||
createTaskInCurrentCard,
|
||||
handleTaskCreate,
|
||||
updateTask,
|
||||
handleTaskUpdate,
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
|
||||
import { changeCoreLanguage, logout } from './core';
|
||||
import request from '../request';
|
||||
import requests from '../requests';
|
||||
import selectors from '../../../selectors';
|
||||
import actions from '../../../actions';
|
||||
import api from '../../../api';
|
||||
import { setAccessToken } from '../../../utils/access-token-storage';
|
||||
import mergeRecords from '../../../utils/merge-records';
|
||||
import { isUserAdminOrProjectOwner } from '../../../utils/record-helpers';
|
||||
import { UserRoles } from '../../../constants/Enums';
|
||||
|
||||
export function* createUser(data) {
|
||||
yield put(actions.createUser(data));
|
||||
@@ -44,21 +53,147 @@ export function* updateUser(id, data) {
|
||||
}
|
||||
|
||||
export function* updateCurrentUser(data) {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(updateUser, id, data);
|
||||
yield call(updateUser, currentUserId, data);
|
||||
}
|
||||
|
||||
export function* handleUserUpdate(user) {
|
||||
const currentUser = yield select(selectors.selectCurrentUser);
|
||||
const isCurrent = user.id === currentUser.id;
|
||||
const prevUser = yield select(selectors.selectUserById, user.id);
|
||||
|
||||
let users;
|
||||
if (isCurrent && !currentUser.isAdmin && user.isAdmin) {
|
||||
({ items: users } = yield call(request, api.getUsers));
|
||||
const isChangedToAdminOrProjectOwner =
|
||||
(!prevUser || (prevUser.role !== user.role && prevUser.role !== UserRoles.ADMIN)) &&
|
||||
isUserAdminOrProjectOwner(user);
|
||||
|
||||
const currentUser = yield select(selectors.selectCurrentUser);
|
||||
const isCurrentUser = user.id === currentUser.id;
|
||||
|
||||
let config;
|
||||
let board;
|
||||
let users1;
|
||||
let users2;
|
||||
let users3;
|
||||
let projects;
|
||||
let projectManagers;
|
||||
let backgroundImages;
|
||||
let baseCustomFieldGroups;
|
||||
let boards;
|
||||
let boardMemberships1;
|
||||
let boardMemberships2;
|
||||
let labels;
|
||||
let lists;
|
||||
let cards;
|
||||
let cardMemberships;
|
||||
let cardLabels;
|
||||
let taskLists;
|
||||
let tasks;
|
||||
let attachments;
|
||||
let customFieldGroups;
|
||||
let customFields1;
|
||||
let customFields2;
|
||||
let customFieldValues;
|
||||
let notificationsToDelete;
|
||||
let notificationServices;
|
||||
|
||||
if (isCurrentUser && isChangedToAdminOrProjectOwner) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
({ items: users1 } = yield call(request, api.getUsers));
|
||||
|
||||
if (user.role === UserRoles.ADMIN) {
|
||||
({ item: config } = yield call(request, api.getConfig));
|
||||
|
||||
({
|
||||
items: projects,
|
||||
included: {
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
notificationServices,
|
||||
users: users2,
|
||||
boardMemberships: boardMemberships1,
|
||||
customFields: customFields1,
|
||||
},
|
||||
} = yield call(request, api.getProjects));
|
||||
|
||||
if (boardId === null) {
|
||||
let body;
|
||||
try {
|
||||
body = yield call(requests.fetchBoardByCurrentPath);
|
||||
} catch {
|
||||
/* empty */
|
||||
}
|
||||
|
||||
if (body) {
|
||||
({
|
||||
board,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFieldValues,
|
||||
users: users3,
|
||||
boardMemberships: boardMemberships2,
|
||||
customFields: customFields2,
|
||||
} = body);
|
||||
|
||||
if (body.card) {
|
||||
notificationsToDelete = yield select(
|
||||
selectors.selectNotificationsByCardId,
|
||||
body.card.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield put(actions.handleUserUpdate(user, users, isCurrent));
|
||||
const projectIds = yield select(selectors.selectProjectIdsForCurrentUser);
|
||||
const boardIds = yield select(selectors.selectBoardIdsForCurrentUser);
|
||||
|
||||
yield put(
|
||||
actions.handleUserUpdate(
|
||||
user,
|
||||
projectIds,
|
||||
boardIds,
|
||||
config,
|
||||
board,
|
||||
mergeRecords(users1, users2, users3),
|
||||
projects,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
mergeRecords(boardMemberships1, boardMemberships2),
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
cardMemberships,
|
||||
cardLabels,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
mergeRecords(customFields1, customFields2),
|
||||
customFieldValues,
|
||||
notificationsToDelete,
|
||||
notificationServices,
|
||||
),
|
||||
);
|
||||
|
||||
if (isCurrentUser) {
|
||||
const isAvailableForCurrentUser = yield select(selectors.isCurrentModalAvailableForCurrentUser);
|
||||
|
||||
if (!isAvailableForCurrentUser) {
|
||||
yield put(actions.closeModal());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add loading state
|
||||
@@ -71,9 +206,9 @@ export function* updateUserLanguage(id, language) {
|
||||
}
|
||||
|
||||
export function* updateCurrentUserLanguage(language) {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(updateUserLanguage, id, language);
|
||||
yield call(updateUserLanguage, currentUserId, language);
|
||||
}
|
||||
|
||||
export function* updateUserEmail(id, data) {
|
||||
@@ -91,9 +226,9 @@ export function* updateUserEmail(id, data) {
|
||||
}
|
||||
|
||||
export function* updateCurrentUserEmail(data) {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(updateUserEmail, id, data);
|
||||
yield call(updateUserEmail, currentUserId, data);
|
||||
}
|
||||
|
||||
export function* clearUserEmailUpdateError(id) {
|
||||
@@ -101,9 +236,9 @@ export function* clearUserEmailUpdateError(id) {
|
||||
}
|
||||
|
||||
export function* clearCurrentUserEmailUpdateError() {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(clearUserEmailUpdateError, id);
|
||||
yield call(clearUserEmailUpdateError, currentUserId);
|
||||
}
|
||||
|
||||
export function* updateUserPassword(id, data) {
|
||||
@@ -134,9 +269,9 @@ export function* updateUserPassword(id, data) {
|
||||
}
|
||||
|
||||
export function* updateCurrentUserPassword(data) {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(updateUserPassword, id, data);
|
||||
yield call(updateUserPassword, currentUserId, data);
|
||||
}
|
||||
|
||||
export function* clearUserPasswordUpdateError(id) {
|
||||
@@ -144,9 +279,9 @@ export function* clearUserPasswordUpdateError(id) {
|
||||
}
|
||||
|
||||
export function* clearCurrentUserPasswordUpdateError() {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(clearUserPasswordUpdateError, id);
|
||||
yield call(clearUserPasswordUpdateError, currentUserId);
|
||||
}
|
||||
|
||||
export function* updateUserUsername(id, data) {
|
||||
@@ -164,9 +299,9 @@ export function* updateUserUsername(id, data) {
|
||||
}
|
||||
|
||||
export function* updateCurrentUserUsername(data) {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(updateUserUsername, id, data);
|
||||
yield call(updateUserUsername, currentUserId, data);
|
||||
}
|
||||
|
||||
export function* clearUserUsernameUpdateError(id) {
|
||||
@@ -174,9 +309,9 @@ export function* clearUserUsernameUpdateError(id) {
|
||||
}
|
||||
|
||||
export function* clearCurrentUserUsernameUpdateError() {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(clearUserUsernameUpdateError, id);
|
||||
yield call(clearUserUsernameUpdateError, currentUserId);
|
||||
}
|
||||
|
||||
export function* updateUserAvatar(id, data) {
|
||||
@@ -194,9 +329,9 @@ export function* updateUserAvatar(id, data) {
|
||||
}
|
||||
|
||||
export function* updateCurrentUserAvatar(data) {
|
||||
const id = yield select(selectors.selectCurrentUserId);
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(updateUserAvatar, id, data);
|
||||
yield call(updateUserAvatar, currentUserId, data);
|
||||
}
|
||||
|
||||
export function* deleteUser(id) {
|
||||
@@ -248,6 +383,12 @@ export function* addUserToCurrentCard(id) {
|
||||
yield call(addUserToCard, id, cardId);
|
||||
}
|
||||
|
||||
export function* addCurrentUserToCurrentCard() {
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(addUserToCurrentCard, currentUserId);
|
||||
}
|
||||
|
||||
export function* handleUserToCardAdd(cardMembership) {
|
||||
yield put(actions.handleUserToCardAdd(cardMembership));
|
||||
}
|
||||
@@ -272,22 +413,32 @@ export function* removeUserFromCurrentCard(id) {
|
||||
yield call(removeUserFromCard, id, cardId);
|
||||
}
|
||||
|
||||
export function* removeCurrentUserFromCurrentCard() {
|
||||
const currentUserId = yield select(selectors.selectCurrentUserId);
|
||||
|
||||
yield call(removeUserFromCurrentCard, currentUserId);
|
||||
}
|
||||
|
||||
export function* handleUserFromCardRemove(cardMembership) {
|
||||
yield put(actions.handleUserFromCardRemove(cardMembership));
|
||||
}
|
||||
|
||||
export function* addUserToBoardFilter(id, boardId) {
|
||||
yield put(actions.addUserToBoardFilter(id, boardId));
|
||||
export function* addUserToBoardFilter(id, boardId, replace) {
|
||||
const currentListId = yield select(selectors.selectCurrentListId);
|
||||
|
||||
yield put(actions.addUserToBoardFilter(id, boardId, replace, currentListId));
|
||||
}
|
||||
|
||||
export function* addUserToFilterInCurrentBoard(id) {
|
||||
export function* addUserToFilterInCurrentBoard(id, replace) {
|
||||
const { boardId } = yield select(selectors.selectPath);
|
||||
|
||||
yield call(addUserToBoardFilter, id, boardId);
|
||||
yield call(addUserToBoardFilter, id, boardId, replace);
|
||||
}
|
||||
|
||||
export function* removeUserFromBoardFilter(id, boardId) {
|
||||
yield put(actions.removeUserFromBoardFilter(id, boardId));
|
||||
const currentListId = yield select(selectors.selectCurrentListId);
|
||||
|
||||
yield put(actions.removeUserFromBoardFilter(id, boardId, currentListId));
|
||||
}
|
||||
|
||||
export function* removeUserFromFilterInCurrentBoard(id) {
|
||||
@@ -323,9 +474,11 @@ export default {
|
||||
handleUserDelete,
|
||||
addUserToCard,
|
||||
addUserToCurrentCard,
|
||||
addCurrentUserToCurrentCard,
|
||||
handleUserToCardAdd,
|
||||
removeUserFromCard,
|
||||
removeUserFromCurrentCard,
|
||||
removeCurrentUserFromCurrentCard,
|
||||
handleUserFromCardRemove,
|
||||
addUserToBoardFilter,
|
||||
addUserToFilterInCurrentBoard,
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -8,18 +13,8 @@ export default function* activitiesWatchers() {
|
||||
takeEvery(EntryActionTypes.ACTIVITIES_IN_CURRENT_CARD_FETCH, () =>
|
||||
services.fetchActivitiesInCurrentCard(),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.ACTIVITIES_DETAILS_IN_CURRENT_CARD_TOGGLE,
|
||||
({ payload: { isVisible } }) => services.toggleActivitiesDetailsInCurrentCard(isVisible),
|
||||
),
|
||||
takeEvery(EntryActionTypes.ACTIVITY_CREATE_HANDLE, ({ payload: { activity } }) =>
|
||||
services.handleActivityCreate(activity),
|
||||
),
|
||||
takeEvery(EntryActionTypes.ACTIVITY_UPDATE_HANDLE, ({ payload: { activity } }) =>
|
||||
services.handleActivityUpdate(activity),
|
||||
),
|
||||
takeEvery(EntryActionTypes.ACTIVITY_DELETE_HANDLE, ({ payload: { activity } }) =>
|
||||
services.handleActivityDelete(activity),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* backgroundImagesWatchers() {
|
||||
yield all([
|
||||
takeEvery(
|
||||
EntryActionTypes.BACKGROUND_IMAGE_IN_CURRENT_PROJECT_CREATE,
|
||||
({ payload: { data } }) => services.createBackgroundImageInCurrentProject(data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.BACKGROUND_IMAGE_CREATE_HANDLE,
|
||||
({ payload: { backgroundImage, requestId } }) =>
|
||||
services.handleBackgroundImageCreate(backgroundImage, requestId),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BACKGROUND_IMAGE_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteBackgroundImage(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BACKGROUND_IMAGE_DELETE_HANDLE, ({ payload: { backgroundImage } }) =>
|
||||
services.handleBackgroundImageDelete(backgroundImage),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* baseCustomFieldGroupsWatchers() {
|
||||
yield all([
|
||||
takeEvery(
|
||||
EntryActionTypes.BASE_CUSTOM_FIELD_GROUP_IN_CURRENT_PROJECT_CREATE,
|
||||
({ payload: { data } }) => services.createBaseCustomFieldGroupInCurrentProject(data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.BASE_CUSTOM_FIELD_GROUP_CREATE_HANDLE,
|
||||
({ payload: { baseCustomFieldGroup } }) =>
|
||||
services.handleBaseCustomFieldGroupCreate(baseCustomFieldGroup),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BASE_CUSTOM_FIELD_GROUP_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateBaseCustomFieldGroup(id, data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.BASE_CUSTOM_FIELD_GROUP_UPDATE_HANDLE,
|
||||
({ payload: { baseCustomFieldGroup } }) =>
|
||||
services.handleBaseCustomFieldGroupUpdate(baseCustomFieldGroup),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BASE_CUSTOM_FIELD_GROUP_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteBaseCustomFieldGroup(id),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.BASE_CUSTOM_FIELD_GROUP_DELETE_HANDLE,
|
||||
({ payload: { baseCustomFieldGroup } }) =>
|
||||
services.handleBaseCustomFieldGroupDelete(baseCustomFieldGroup),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -8,8 +13,10 @@ export default function* boardMembershipsWatchers() {
|
||||
takeEvery(EntryActionTypes.MEMBERSHIP_IN_CURRENT_BOARD_CREATE, ({ payload: { data } }) =>
|
||||
services.createMembershipInCurrentBoard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE, ({ payload: { boardMembership } }) =>
|
||||
services.handleBoardMembershipCreate(boardMembership),
|
||||
takeEvery(
|
||||
EntryActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE,
|
||||
({ payload: { boardMembership, users } }) =>
|
||||
services.handleBoardMembershipCreate(boardMembership, users),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BOARD_MEMBERSHIP_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateBoardMembership(id, data),
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -8,19 +13,33 @@ export default function* boardsWatchers() {
|
||||
takeEvery(EntryActionTypes.BOARD_IN_CURRENT_PROJECT_CREATE, ({ payload: { data } }) =>
|
||||
services.createBoardInCurrentProject(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BOARD_CREATE_HANDLE, ({ payload: { board, requestId } }) =>
|
||||
services.handleBoardCreate(board, requestId),
|
||||
takeEvery(
|
||||
EntryActionTypes.BOARD_CREATE_HANDLE,
|
||||
({ payload: { board, boardMemberships, requestId } }) =>
|
||||
services.handleBoardCreate(board, boardMemberships, requestId),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BOARD_FETCH, ({ payload: { id } }) => services.fetchBoard(id)),
|
||||
takeEvery(EntryActionTypes.BOARD_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateBoard(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_BOARD_UPDATE, ({ payload: { data } }) =>
|
||||
services.updateCurrentBoard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BOARD_UPDATE_HANDLE, ({ payload: { board } }) =>
|
||||
services.handleBoardUpdate(board),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BOARD_MOVE, ({ payload: { id, index } }) =>
|
||||
services.moveBoard(id, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CONTEXT_IN_CURRENT_BOARD_UPDATE, ({ payload: { value } }) =>
|
||||
services.updateContextInCurrentBoard(value),
|
||||
),
|
||||
takeEvery(EntryActionTypes.VIEW_IN_CURRENT_BOARD_UPDATE, ({ payload: { value } }) =>
|
||||
services.updateViewInCurrentBoard(value),
|
||||
),
|
||||
takeEvery(EntryActionTypes.IN_CURRENT_BOARD_SEARCH, ({ payload: { value } }) =>
|
||||
services.searchInCurrentBoard(value),
|
||||
),
|
||||
takeEvery(EntryActionTypes.BOARD_DELETE, ({ payload: { id } }) => services.deleteBoard(id)),
|
||||
takeEvery(EntryActionTypes.BOARD_DELETE_HANDLE, ({ payload: { board } }) =>
|
||||
services.handleBoardDelete(board),
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -5,9 +10,22 @@ import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* cardsWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.CARDS_IN_CURRENT_LIST_FETCH, () =>
|
||||
services.fetchCardsInCurrentList(),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARDS_UPDATE_HANDLE, ({ payload: { cards, activities } }) =>
|
||||
services.handleCardsUpdate(cards, activities),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARD_CREATE, ({ payload: { listId, data, autoOpen } }) =>
|
||||
services.createCard(listId, data, autoOpen),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARD_IN_CURRENT_LIST_CREATE, ({ payload: { data, autoOpen } }) =>
|
||||
services.createCardInCurrentList(data, autoOpen),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CARD_IN_FIRST_FINITE_LIST_CREATE,
|
||||
({ payload: { data, autoOpen } }) => services.createCardInFirstFiniteList(data, autoOpen),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARD_CREATE_HANDLE, ({ payload: { card } }) =>
|
||||
services.handleCardCreate(card),
|
||||
),
|
||||
@@ -23,24 +41,38 @@ export default function* cardsWatchers() {
|
||||
takeEvery(EntryActionTypes.CARD_MOVE, ({ payload: { id, listId, index } }) =>
|
||||
services.moveCard(id, listId, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_MOVE, ({ payload: { listId, index } }) =>
|
||||
services.moveCurrentCard(listId, index),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_MOVE, ({ payload: { listId, index, autoClose } }) =>
|
||||
services.moveCurrentCard(listId, index, autoClose),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARD_TO_ARCHIVE_MOVE, ({ payload: { id } }) =>
|
||||
services.moveCardToArchive(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_TO_ARCHIVE_MOVE, () =>
|
||||
services.moveCurrentCardToArchive(),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARD_TO_TRASH_MOVE, ({ payload: { id } }) =>
|
||||
services.moveCardToTrash(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_TO_TRASH_MOVE, () => services.moveCurrentCardToTrash()),
|
||||
takeEvery(EntryActionTypes.CARD_TRANSFER, ({ payload: { id, boardId, listId, index } }) =>
|
||||
services.transferCard(id, boardId, listId, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_TRANSFER, ({ payload: { boardId, listId, index } }) =>
|
||||
services.transferCurrentCard(boardId, listId, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARD_DUPLICATE, ({ payload: { id } }) => services.duplicateCard(id)),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_DUPLICATE, () => services.duplicateCurrentCard()),
|
||||
takeEvery(EntryActionTypes.CARD_DUPLICATE, ({ payload: { id, data } }) =>
|
||||
services.duplicateCard(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_DUPLICATE, ({ payload: { data } }) =>
|
||||
services.duplicateCurrentCard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TO_ADJACENT_CARD_GO, ({ payload: { direction } }) =>
|
||||
services.goToAdjacentCard(direction),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CARD_DELETE, ({ payload: { id } }) => services.deleteCard(id)),
|
||||
takeEvery(EntryActionTypes.CURRENT_CARD_DELETE, () => services.deleteCurrentCard()),
|
||||
takeEvery(EntryActionTypes.CARD_DELETE_HANDLE, ({ payload: { card } }) =>
|
||||
services.handleCardDelete(card),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TEXT_FILTER_IN_CURRENT_BOARD, ({ payload: { text } }) =>
|
||||
services.handleTextFilter(text),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
import { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* commentActivitiesWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.COMMENT_ACTIVITY_IN_CURRENT_CARD_CREATE, ({ payload: { data } }) =>
|
||||
services.createCommentActivityInCurrentCard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.COMMENT_ACTIVITY_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateCommentActivity(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.COMMENT_ACTIVITY_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteCommentActivity(id),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* commentsWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.COMMENTS_IN_CURRENT_CARD_FETCH, () =>
|
||||
services.fetchCommentsInCurrentCard(),
|
||||
),
|
||||
takeEvery(EntryActionTypes.COMMENT_IN_CURRENT_CARD_CREATE, ({ payload: { data } }) =>
|
||||
services.createCommentInCurrentCard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.COMMENT_CREATE_HANDLE, ({ payload: { comment, users } }) =>
|
||||
services.handleCommentCreate(comment, users),
|
||||
),
|
||||
takeEvery(EntryActionTypes.COMMENT_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateComment(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.COMMENT_UPDATE_HANDLE, ({ payload: { comment } }) =>
|
||||
services.handleCommentUpdate(comment),
|
||||
),
|
||||
takeEvery(EntryActionTypes.COMMENT_DELETE, ({ payload: { id } }) => services.deleteComment(id)),
|
||||
takeEvery(EntryActionTypes.COMMENT_DELETE_HANDLE, ({ payload: { comment } }) =>
|
||||
services.handleCommentDelete(comment),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -5,6 +10,15 @@ import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* coreWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.FAVORITES_TOGGLE, ({ payload: { isEnabled } }) =>
|
||||
services.toggleFavorites(isEnabled),
|
||||
),
|
||||
takeEvery(EntryActionTypes.EDIT_MODE_TOGGLE, ({ payload: { isEnabled } }) =>
|
||||
services.toggleEditMode(isEnabled),
|
||||
),
|
||||
takeEvery(EntryActionTypes.HOME_VIEW_UPDATE, ({ payload: { value } }) =>
|
||||
services.updateHomeView(value),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LOGOUT, ({ payload: { invalidateAccessToken } }) =>
|
||||
services.logout(invalidateAccessToken),
|
||||
),
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* customFieldGroupsWatchers() {
|
||||
yield all([
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_GROUP_IN_CURRENT_BOARD_CREATE,
|
||||
({ payload: { data } }) => services.createCustomFieldGroupInCurrentBoard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_GROUP_IN_CURRENT_CARD_CREATE, ({ payload: { data } }) =>
|
||||
services.createCustomFieldGroupInCurrentCard(data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_GROUP_CREATE_HANDLE,
|
||||
({ payload: { customFieldGroup } }) =>
|
||||
services.handleCustomFieldGroupCreate(customFieldGroup),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_GROUP_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateCustomFieldGroup(id, data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_GROUP_UPDATE_HANDLE,
|
||||
({ payload: { customFieldGroup } }) =>
|
||||
services.handleCustomFieldGroupUpdate(customFieldGroup),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_GROUP_MOVE, ({ payload: { id, index } }) =>
|
||||
services.moveCustomFieldGroup(id, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_GROUP_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteCustomFieldGroup(id),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_GROUP_DELETE_HANDLE,
|
||||
({ payload: { customFieldGroup } }) =>
|
||||
services.handleCustomFieldGroupDelete(customFieldGroup),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* customFieldValuessWatchers() {
|
||||
yield all([
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_VALUE_UPDATE,
|
||||
({ payload: { cardId, customFieldGroupId, customFieldId, data } }) =>
|
||||
services.updateCustomFieldValue(cardId, customFieldGroupId, customFieldId, data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_VALUE_UPDATE_HANDLE,
|
||||
({ payload: { customFieldValue } }) =>
|
||||
services.handleCustomFieldValueUpdate(customFieldValue),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_VALUE_DELETE,
|
||||
({ payload: { cardId, customFieldGroupId, customFieldId } }) =>
|
||||
services.deleteCustomFieldValue(cardId, customFieldGroupId, customFieldId),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_VALUE_DELETE_HANDLE,
|
||||
({ payload: { customFieldValue } }) =>
|
||||
services.handleCustomFieldValueDelete(customFieldValue),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* customFieldsWatchers() {
|
||||
yield all([
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_IN_BASE_GROUP_CREATE,
|
||||
({ payload: { baseCustomFieldGroupId, data } }) =>
|
||||
services.createCustomFieldInBaseGroup(baseCustomFieldGroupId, data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.CUSTOM_FIELD_IN_GROUP_CREATE,
|
||||
({ payload: { customFieldGroupId, data } }) =>
|
||||
services.createCustomFieldInGroup(customFieldGroupId, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_CREATE_HANDLE, ({ payload: { customField } }) =>
|
||||
services.handleCustomFieldCreate(customField),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateCustomField(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_UPDATE_HANDLE, ({ payload: { customField } }) =>
|
||||
services.handleCustomFieldUpdate(customField),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_MOVE, ({ payload: { id, index } }) =>
|
||||
services.moveCustomField(id, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteCustomField(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CUSTOM_FIELD_DELETE_HANDLE, ({ payload: { customField } }) =>
|
||||
services.handleCustomFieldDelete(customField),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -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 router from './router';
|
||||
import socket from './socket';
|
||||
import core from './core';
|
||||
@@ -5,16 +10,23 @@ import modals from './modals';
|
||||
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 commentActivities from './comment-activities';
|
||||
import notifications from './notifications';
|
||||
import notificationServices from './notification-services';
|
||||
|
||||
export default [
|
||||
router,
|
||||
@@ -24,14 +36,21 @@ export default [
|
||||
users,
|
||||
projects,
|
||||
projectManagers,
|
||||
backgroundImages,
|
||||
baseCustomFieldGroups,
|
||||
boards,
|
||||
boardMemberships,
|
||||
labels,
|
||||
lists,
|
||||
cards,
|
||||
taskLists,
|
||||
tasks,
|
||||
attachments,
|
||||
customFieldGroups,
|
||||
customFields,
|
||||
customFieldValues,
|
||||
comments,
|
||||
activities,
|
||||
commentActivities,
|
||||
notifications,
|
||||
notificationServices,
|
||||
];
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -8,6 +13,9 @@ export default function* labelsWatchers() {
|
||||
takeEvery(EntryActionTypes.LABEL_IN_CURRENT_BOARD_CREATE, ({ payload: { data } }) =>
|
||||
services.createLabelInCurrentBoard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LABEL_FROM_CARD_CREATE, ({ payload: { cardId, data } }) =>
|
||||
services.createLabelFromCard(cardId, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LABEL_CREATE_HANDLE, ({ payload: { label } }) =>
|
||||
services.handleLabelCreate(label),
|
||||
),
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -23,12 +28,18 @@ export default function* listsWatchers() {
|
||||
takeEvery(EntryActionTypes.LIST_SORT, ({ payload: { id, data } }) =>
|
||||
services.sortList(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LIST_SORT_HANDLE, ({ payload: { list, cards } }) =>
|
||||
services.handleListSort(list, cards),
|
||||
takeEvery(EntryActionTypes.LIST_CARDS_TO_ARCHIVE_LIST_MOVE, ({ payload: { id } }) =>
|
||||
services.moveListCardsToArchiveList(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TRASH_LIST_IN_CURRENT_BOARD_CLEAR, () =>
|
||||
services.clearTrashListInCurrentBoard(),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LIST_CLEAR_HANDLE, ({ payload: { list } }) =>
|
||||
services.handleListClear(list),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LIST_DELETE, ({ payload: { id } }) => services.deleteList(id)),
|
||||
takeEvery(EntryActionTypes.LIST_DELETE_HANDLE, ({ payload: { list } }) =>
|
||||
services.handleListDelete(list),
|
||||
takeEvery(EntryActionTypes.LIST_DELETE_HANDLE, ({ payload: { list, cards } }) =>
|
||||
services.handleListDelete(list, cards),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -5,7 +10,9 @@ import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* modalsWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.MODAL_OPEN, ({ payload: { type } }) => services.openModal(type)),
|
||||
takeEvery(EntryActionTypes.MODAL_OPEN, ({ payload: { type, params } }) =>
|
||||
services.openModal(type, params),
|
||||
),
|
||||
takeEvery(EntryActionTypes.MODAL_CLOSE, () => services.closeModal()),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* notificationServicesWatchers() {
|
||||
yield all([
|
||||
takeEvery(
|
||||
EntryActionTypes.NOTIFICATION_SERVICE_IN_CURRENT_USER_CREATE,
|
||||
({ payload: { data } }) => services.createNotificationServiceInCurrentUser(data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.NOTIFICATION_SERVICE_IN_BOARD_CREATE,
|
||||
({ payload: { boardId, data } }) => services.createNotificationServiceInBoard(boardId, data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.NOTIFICATION_SERVICE_CREATE_HANDLE,
|
||||
({ payload: { notificationService } }) =>
|
||||
services.handleNotificationServiceCreate(notificationService),
|
||||
),
|
||||
takeEvery(EntryActionTypes.NOTIFICATION_SERVICE_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateNotificationService(id, data),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.NOTIFICATION_SERVICE_UPDATE_HANDLE,
|
||||
({ payload: { notificationService } }) =>
|
||||
services.handleNotificationServiceUpdate(notificationService),
|
||||
),
|
||||
takeEvery(EntryActionTypes.NOTIFICATION_SERVICE_TEST, ({ payload: { id } }) =>
|
||||
services.testNotificationService(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.NOTIFICATION_SERVICE_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteNotificationService(id),
|
||||
),
|
||||
takeEvery(
|
||||
EntryActionTypes.NOTIFICATION_SERVICE_DELETE_HANDLE,
|
||||
({ payload: { notificationService } }) =>
|
||||
services.handleNotificationServiceDelete(notificationService),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -5,8 +10,9 @@ import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* notificationsWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.NOTIFICATION_CREATE_HANDLE, ({ payload: { notification } }) =>
|
||||
services.handleNotificationCreate(notification),
|
||||
takeEvery(EntryActionTypes.ALL_NOTIFICATIONS_DELETE, () => services.deleteAllNotifications()),
|
||||
takeEvery(EntryActionTypes.NOTIFICATION_CREATE_HANDLE, ({ payload: { notification, users } }) =>
|
||||
services.handleNotificationCreate(notification, users),
|
||||
),
|
||||
takeEvery(EntryActionTypes.NOTIFICATION_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteNotification(id),
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -8,8 +13,10 @@ export default function* projectManagersWatchers() {
|
||||
takeEvery(EntryActionTypes.MANAGER_IN_CURRENT_PROJECT_CREATE, ({ payload: { data } }) =>
|
||||
services.createManagerInCurrentProject(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.PROJECT_MANAGER_CREATE_HANDLE, ({ payload: { projectManager } }) =>
|
||||
services.handleProjectManagerCreate(projectManager),
|
||||
takeEvery(
|
||||
EntryActionTypes.PROJECT_MANAGER_CREATE_HANDLE,
|
||||
({ payload: { projectManager, users } }) =>
|
||||
services.handleProjectManagerCreate(projectManager, users),
|
||||
),
|
||||
takeEvery(EntryActionTypes.PROJECT_MANAGER_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteProjectManager(id),
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -5,21 +10,30 @@ import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* projectsWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.PROJECTS_SEARCH, ({ payload: { value } }) =>
|
||||
services.searchProjects(value),
|
||||
),
|
||||
takeEvery(EntryActionTypes.PROJECTS_ORDER_UPDATE, ({ payload: { value } }) =>
|
||||
services.updateProjectsOrder(value),
|
||||
),
|
||||
takeEvery(EntryActionTypes.HIDDEN_PROJECTS_TOGGLE, ({ payload: { isVisible } }) =>
|
||||
services.toggleHiddenProjects(isVisible),
|
||||
),
|
||||
takeEvery(EntryActionTypes.PROJECT_CREATE, ({ payload: { data } }) =>
|
||||
services.createProject(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.PROJECT_CREATE_HANDLE, ({ payload: { project } }) =>
|
||||
services.handleProjectCreate(project),
|
||||
),
|
||||
takeEvery(EntryActionTypes.PROJECT_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateProject(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_PROJECT_UPDATE, ({ payload: { data } }) =>
|
||||
services.updateCurrentProject(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.PROJECT_UPDATE_HANDLE, ({ payload: { project } }) =>
|
||||
services.handleProjectUpdate(project),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_PROJECT_BACKGROUND_IMAGE_UPDATE, ({ payload: { data } }) =>
|
||||
services.updateCurrentProjectBackgroundImage(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_PROJECT_DELETE, () => services.deleteCurrentProject()),
|
||||
takeEvery(EntryActionTypes.PROJECT_DELETE_HANDLE, ({ payload: { project } }) =>
|
||||
services.handleProjectDelete(project),
|
||||
|
||||
@@ -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 { takeEvery } from 'redux-saga/effects';
|
||||
import { LOCATION_CHANGE_HANDLE } from '../../../lib/redux-router';
|
||||
|
||||
|
||||
@@ -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 { eventChannel } from 'redux-saga';
|
||||
import { all, call, cancelled, put, take, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
@@ -20,17 +25,21 @@ const createSocketEventsChannel = () =>
|
||||
emit(entryActions.logout(false));
|
||||
};
|
||||
|
||||
const handleUserCreate = api.makeHandleUserCreate(({ item }) => {
|
||||
const handleConfigUpdate = ({ item }) => {
|
||||
emit(entryActions.handleConfigUpdate(item));
|
||||
};
|
||||
|
||||
const handleUserCreate = ({ item }) => {
|
||||
emit(entryActions.handleUserCreate(item));
|
||||
});
|
||||
};
|
||||
|
||||
const handleUserUpdate = api.makeHandleUserUpdate(({ item }) => {
|
||||
const handleUserUpdate = ({ item }) => {
|
||||
emit(entryActions.handleUserUpdate(item));
|
||||
});
|
||||
};
|
||||
|
||||
const handleUserDelete = api.makeHandleUserDelete(({ item }) => {
|
||||
const handleUserDelete = ({ item }) => {
|
||||
emit(entryActions.handleUserDelete(item));
|
||||
});
|
||||
};
|
||||
|
||||
const handleProjectCreate = ({ item }) => {
|
||||
emit(entryActions.handleProjectCreate(item));
|
||||
@@ -44,16 +53,36 @@ const createSocketEventsChannel = () =>
|
||||
emit(entryActions.handleProjectDelete(item));
|
||||
};
|
||||
|
||||
const handleProjectManagerCreate = api.makeHandleProjectManagerCreate(({ item }) => {
|
||||
emit(entryActions.handleProjectManagerCreate(item));
|
||||
});
|
||||
const handleProjectManagerCreate = ({ item, included: { users } }) => {
|
||||
emit(entryActions.handleProjectManagerCreate(item, users));
|
||||
};
|
||||
|
||||
const handleProjectManagerDelete = api.makeHandleProjectManagerDelete(({ item }) => {
|
||||
const handleProjectManagerDelete = ({ item }) => {
|
||||
emit(entryActions.handleProjectManagerDelete(item));
|
||||
});
|
||||
};
|
||||
|
||||
const handleBoardCreate = ({ item, requestId }) => {
|
||||
emit(entryActions.handleBoardCreate(item, requestId));
|
||||
const handleBackgroundImageCreate = ({ item, requestId }) => {
|
||||
emit(entryActions.handleBackgroundImageCreate(item, requestId));
|
||||
};
|
||||
|
||||
const handleBackgroundImageDelete = ({ item }) => {
|
||||
emit(entryActions.handleBackgroundImageDelete(item));
|
||||
};
|
||||
|
||||
const handleBaseCustomFieldGroupCreate = ({ item }) => {
|
||||
emit(entryActions.handleBaseCustomFieldGroupCreate(item));
|
||||
};
|
||||
|
||||
const handleBaseCustomFieldGroupUpdate = ({ item }) => {
|
||||
emit(entryActions.handleBaseCustomFieldGroupUpdate(item));
|
||||
};
|
||||
|
||||
const handleBaseCustomFieldGroupDelete = ({ item }) => {
|
||||
emit(entryActions.handleBaseCustomFieldGroupDelete(item));
|
||||
};
|
||||
|
||||
const handleBoardCreate = ({ item, included: { boardMemberships }, requestId }) => {
|
||||
emit(entryActions.handleBoardCreate(item, boardMemberships, requestId));
|
||||
};
|
||||
|
||||
const handleBoardUpdate = ({ item }) => {
|
||||
@@ -64,17 +93,17 @@ const createSocketEventsChannel = () =>
|
||||
emit(entryActions.handleBoardDelete(item));
|
||||
};
|
||||
|
||||
const handleBoardMembershipCreate = api.makeHandleBoardMembershipCreate(({ item }) => {
|
||||
emit(entryActions.handleBoardMembershipCreate(item));
|
||||
});
|
||||
const handleBoardMembershipCreate = ({ item, included: { users } = {} }) => {
|
||||
emit(entryActions.handleBoardMembershipCreate(item, users));
|
||||
};
|
||||
|
||||
const handleBoardMembershipUpdate = api.makeHandleBoardMembershipUpdate(({ item }) => {
|
||||
const handleBoardMembershipUpdate = ({ item }) => {
|
||||
emit(entryActions.handleBoardMembershipUpdate(item));
|
||||
});
|
||||
};
|
||||
|
||||
const handleBoardMembershipDelete = api.makeHandleBoardMembershipDelete(({ item }) => {
|
||||
const handleBoardMembershipDelete = ({ item }) => {
|
||||
emit(entryActions.handleBoardMembershipDelete(item));
|
||||
});
|
||||
};
|
||||
|
||||
const handleListCreate = ({ item }) => {
|
||||
emit(entryActions.handleListCreate(item));
|
||||
@@ -84,14 +113,14 @@ const createSocketEventsChannel = () =>
|
||||
emit(entryActions.handleListUpdate(item));
|
||||
};
|
||||
|
||||
const handleListSort = api.makeHandleListSort(({ item, included: { cards } }) => {
|
||||
emit(entryActions.handleListSort(item, cards));
|
||||
});
|
||||
|
||||
const handleListDelete = ({ item }) => {
|
||||
emit(entryActions.handleListDelete(item));
|
||||
const handleListClear = ({ item }) => {
|
||||
emit(entryActions.handleListClear(item));
|
||||
};
|
||||
|
||||
const handleListDelete = api.makeHandleListDelete(({ item, included: { cards } }) => {
|
||||
emit(entryActions.handleListDelete(item, cards));
|
||||
});
|
||||
|
||||
const handleLabelCreate = ({ item }) => {
|
||||
emit(entryActions.handleLabelCreate(item));
|
||||
};
|
||||
@@ -104,6 +133,12 @@ const createSocketEventsChannel = () =>
|
||||
emit(entryActions.handleLabelDelete(item));
|
||||
};
|
||||
|
||||
const handleCardsUpdate = api.makeHandleCardsUpdate(
|
||||
({ items, included: { activities } = {} }) => {
|
||||
emit(entryActions.handleCardsUpdate(items, activities));
|
||||
},
|
||||
);
|
||||
|
||||
const handleCardCreate = api.makeHandleCardCreate(({ item }) => {
|
||||
emit(entryActions.handleCardCreate(item));
|
||||
});
|
||||
@@ -132,6 +167,18 @@ const createSocketEventsChannel = () =>
|
||||
emit(entryActions.handleLabelFromCardRemove(item));
|
||||
};
|
||||
|
||||
const handleTaskListCreate = ({ item }) => {
|
||||
emit(entryActions.handleTaskListCreate(item));
|
||||
};
|
||||
|
||||
const handleTaskListUpdate = ({ item }) => {
|
||||
emit(entryActions.handleTaskListUpdate(item));
|
||||
};
|
||||
|
||||
const handleTaskListDelete = ({ item }) => {
|
||||
emit(entryActions.handleTaskListDelete(item));
|
||||
};
|
||||
|
||||
const handleTaskCreate = ({ item }) => {
|
||||
emit(entryActions.handleTaskCreate(item));
|
||||
};
|
||||
@@ -156,31 +203,83 @@ const createSocketEventsChannel = () =>
|
||||
emit(entryActions.handleAttachmentDelete(item));
|
||||
});
|
||||
|
||||
const handleCustomFieldGroupCreate = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldGroupCreate(item));
|
||||
};
|
||||
|
||||
const handleCustomFieldGroupUpdate = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldGroupUpdate(item));
|
||||
};
|
||||
|
||||
const handleCustomFieldGroupDelete = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldGroupDelete(item));
|
||||
};
|
||||
|
||||
const handleCustomFieldCreate = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldCreate(item));
|
||||
};
|
||||
|
||||
const handleCustomFieldUpdate = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldUpdate(item));
|
||||
};
|
||||
|
||||
const handleCustomFieldDelete = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldDelete(item));
|
||||
};
|
||||
|
||||
const handleCustomFieldValueUpdate = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldValueUpdate(item));
|
||||
};
|
||||
|
||||
const handleCustomFieldValueDelete = ({ item }) => {
|
||||
emit(entryActions.handleCustomFieldValueDelete(item));
|
||||
};
|
||||
|
||||
const handleCommentCreate = api.makeHandleCommentCreate(({ item, included: { users } }) => {
|
||||
emit(entryActions.handleCommentCreate(item, users));
|
||||
});
|
||||
|
||||
const handleCommentUpdate = api.makeHandleCommentUpdate(({ item }) => {
|
||||
emit(entryActions.handleCommentUpdate(item));
|
||||
});
|
||||
|
||||
const handleCommentDelete = api.makeHandleCommentDelete(({ item }) => {
|
||||
emit(entryActions.handleCommentDelete(item));
|
||||
});
|
||||
|
||||
const handleActivityCreate = api.makeHandleActivityCreate(({ item }) => {
|
||||
emit(entryActions.handleActivityCreate(item));
|
||||
});
|
||||
|
||||
const handleActivityUpdate = api.makeHandleActivityUpdate(({ item }) => {
|
||||
emit(entryActions.handleActivityUpdate(item));
|
||||
});
|
||||
|
||||
const handleActivityDelete = api.makeHandleActivityDelete(({ item }) => {
|
||||
emit(entryActions.handleActivityDelete(item));
|
||||
});
|
||||
|
||||
const handleNotificationCreate = api.makeHandleNotificationCreate(({ item }) => {
|
||||
emit(entryActions.handleNotificationCreate(item));
|
||||
});
|
||||
const handleNotificationCreate = api.makeHandleNotificationCreate(
|
||||
({ item, included: { users } }) => {
|
||||
emit(entryActions.handleNotificationCreate(item, users));
|
||||
},
|
||||
);
|
||||
|
||||
const handleNotificationUpdate = api.makeHandleNotificationUpdate(({ item }) => {
|
||||
emit(entryActions.handleNotificationDelete(item));
|
||||
});
|
||||
|
||||
const handleNotificationServiceCreate = ({ item }) => {
|
||||
emit(entryActions.handleNotificationServiceCreate(item));
|
||||
};
|
||||
|
||||
const handleNotificationServiceUpdate = ({ item }) => {
|
||||
emit(entryActions.handleNotificationServiceUpdate(item));
|
||||
};
|
||||
|
||||
const handleNotificationServiceDelete = ({ item }) => {
|
||||
emit(entryActions.handleNotificationServiceDelete(item));
|
||||
};
|
||||
|
||||
socket.on('disconnect', handleDisconnect);
|
||||
socket.on('reconnect', handleReconnect);
|
||||
|
||||
socket.on('logout', handleLogout);
|
||||
|
||||
socket.on('configUpdate', handleConfigUpdate);
|
||||
|
||||
socket.on('userCreate', handleUserCreate);
|
||||
socket.on('userUpdate', handleUserUpdate);
|
||||
socket.on('userDelete', handleUserDelete);
|
||||
@@ -192,6 +291,13 @@ const createSocketEventsChannel = () =>
|
||||
socket.on('projectManagerCreate', handleProjectManagerCreate);
|
||||
socket.on('projectManagerDelete', handleProjectManagerDelete);
|
||||
|
||||
socket.on('backgroundImageCreate', handleBackgroundImageCreate);
|
||||
socket.on('backgroundImageDelete', handleBackgroundImageDelete);
|
||||
|
||||
socket.on('baseCustomFieldGroupCreate', handleBaseCustomFieldGroupCreate);
|
||||
socket.on('baseCustomFieldGroupUpdate', handleBaseCustomFieldGroupUpdate);
|
||||
socket.on('baseCustomFieldGroupDelete', handleBaseCustomFieldGroupDelete);
|
||||
|
||||
socket.on('boardCreate', handleBoardCreate);
|
||||
socket.on('boardUpdate', handleBoardUpdate);
|
||||
socket.on('boardDelete', handleBoardDelete);
|
||||
@@ -202,13 +308,14 @@ const createSocketEventsChannel = () =>
|
||||
|
||||
socket.on('listCreate', handleListCreate);
|
||||
socket.on('listUpdate', handleListUpdate);
|
||||
socket.on('listSort', handleListSort);
|
||||
socket.on('listClear', handleListClear);
|
||||
socket.on('listDelete', handleListDelete);
|
||||
|
||||
socket.on('labelCreate', handleLabelCreate);
|
||||
socket.on('labelUpdate', handleLabelUpdate);
|
||||
socket.on('labelDelete', handleLabelDelete);
|
||||
|
||||
socket.on('cardsUpdate', handleCardsUpdate);
|
||||
socket.on('cardCreate', handleCardCreate);
|
||||
socket.on('cardUpdate', handleCardUpdate);
|
||||
socket.on('cardDelete', handleCardDelete);
|
||||
@@ -219,6 +326,10 @@ const createSocketEventsChannel = () =>
|
||||
socket.on('cardLabelCreate', handleLabelToCardAdd);
|
||||
socket.on('cardLabelDelete', handleLabelFromCardRemove);
|
||||
|
||||
socket.on('taskListCreate', handleTaskListCreate);
|
||||
socket.on('taskListUpdate', handleTaskListUpdate);
|
||||
socket.on('taskListDelete', handleTaskListDelete);
|
||||
|
||||
socket.on('taskCreate', handleTaskCreate);
|
||||
socket.on('taskUpdate', handleTaskUpdate);
|
||||
socket.on('taskDelete', handleTaskDelete);
|
||||
@@ -227,19 +338,38 @@ const createSocketEventsChannel = () =>
|
||||
socket.on('attachmentUpdate', handleAttachmentUpdate);
|
||||
socket.on('attachmentDelete', handleAttachmentDelete);
|
||||
|
||||
socket.on('customFieldGroupCreate', handleCustomFieldGroupCreate);
|
||||
socket.on('customFieldGroupUpdate', handleCustomFieldGroupUpdate);
|
||||
socket.on('customFieldGroupDelete', handleCustomFieldGroupDelete);
|
||||
|
||||
socket.on('customFieldCreate', handleCustomFieldCreate);
|
||||
socket.on('customFieldUpdate', handleCustomFieldUpdate);
|
||||
socket.on('customFieldDelete', handleCustomFieldDelete);
|
||||
|
||||
socket.on('customFieldValueUpdate', handleCustomFieldValueUpdate);
|
||||
socket.on('customFieldValueDelete', handleCustomFieldValueDelete);
|
||||
|
||||
socket.on('commentCreate', handleCommentCreate);
|
||||
socket.on('commentUpdate', handleCommentUpdate);
|
||||
socket.on('commentDelete', handleCommentDelete);
|
||||
|
||||
socket.on('actionCreate', handleActivityCreate);
|
||||
socket.on('actionUpdate', handleActivityUpdate);
|
||||
socket.on('actionDelete', handleActivityDelete);
|
||||
|
||||
socket.on('notificationCreate', handleNotificationCreate);
|
||||
socket.on('notificationUpdate', handleNotificationUpdate);
|
||||
|
||||
socket.on('notificationServiceCreate', handleNotificationServiceCreate);
|
||||
socket.on('notificationServiceUpdate', handleNotificationServiceUpdate);
|
||||
socket.on('notificationServiceDelete', handleNotificationServiceDelete);
|
||||
|
||||
return () => {
|
||||
socket.off('disconnect', handleDisconnect);
|
||||
socket.off('reconnect', handleReconnect);
|
||||
|
||||
socket.off('logout', handleLogout);
|
||||
|
||||
socket.off('configUpdate', handleConfigUpdate);
|
||||
|
||||
socket.off('userCreate', handleUserCreate);
|
||||
socket.off('userUpdate', handleUserUpdate);
|
||||
socket.off('userDelete', handleUserDelete);
|
||||
@@ -251,6 +381,13 @@ const createSocketEventsChannel = () =>
|
||||
socket.off('projectManagerCreate', handleProjectManagerCreate);
|
||||
socket.off('projectManagerDelete', handleProjectManagerDelete);
|
||||
|
||||
socket.off('backgroundImageCreate', handleBackgroundImageCreate);
|
||||
socket.off('backgroundImageDelete', handleBackgroundImageDelete);
|
||||
|
||||
socket.off('baseCustomFieldGroupCreate', handleBaseCustomFieldGroupCreate);
|
||||
socket.off('baseCustomFieldGroupUpdate', handleBaseCustomFieldGroupUpdate);
|
||||
socket.off('baseCustomFieldGroupDelete', handleBaseCustomFieldGroupDelete);
|
||||
|
||||
socket.off('boardCreate', handleBoardCreate);
|
||||
socket.off('boardUpdate', handleBoardUpdate);
|
||||
socket.off('boardDelete', handleBoardDelete);
|
||||
@@ -261,13 +398,14 @@ const createSocketEventsChannel = () =>
|
||||
|
||||
socket.off('listCreate', handleListCreate);
|
||||
socket.off('listUpdate', handleListUpdate);
|
||||
socket.off('listSort', handleListSort);
|
||||
socket.off('listClear', handleListClear);
|
||||
socket.off('listDelete', handleListDelete);
|
||||
|
||||
socket.off('labelCreate', handleLabelCreate);
|
||||
socket.off('labelUpdate', handleLabelUpdate);
|
||||
socket.off('labelDelete', handleLabelDelete);
|
||||
|
||||
socket.off('cardsUpdate', handleCardsUpdate);
|
||||
socket.off('cardCreate', handleCardCreate);
|
||||
socket.off('cardUpdate', handleCardUpdate);
|
||||
socket.off('cardDelete', handleCardDelete);
|
||||
@@ -278,6 +416,10 @@ const createSocketEventsChannel = () =>
|
||||
socket.off('cardLabelCreate', handleLabelToCardAdd);
|
||||
socket.off('cardLabelDelete', handleLabelFromCardRemove);
|
||||
|
||||
socket.off('taskListCreate', handleTaskListCreate);
|
||||
socket.off('taskListUpdate', handleTaskListUpdate);
|
||||
socket.off('taskListDelete', handleTaskListDelete);
|
||||
|
||||
socket.off('taskCreate', handleTaskCreate);
|
||||
socket.off('taskUpdate', handleTaskUpdate);
|
||||
socket.off('taskDelete', handleTaskDelete);
|
||||
@@ -286,12 +428,29 @@ const createSocketEventsChannel = () =>
|
||||
socket.off('attachmentUpdate', handleAttachmentUpdate);
|
||||
socket.off('attachmentDelete', handleAttachmentDelete);
|
||||
|
||||
socket.off('customFieldGroupCreate', handleCustomFieldGroupCreate);
|
||||
socket.off('customFieldGroupUpdate', handleCustomFieldGroupUpdate);
|
||||
socket.off('customFieldGroupDelete', handleCustomFieldGroupDelete);
|
||||
|
||||
socket.off('customFieldCreate', handleCustomFieldCreate);
|
||||
socket.off('customFieldUpdate', handleCustomFieldUpdate);
|
||||
socket.off('customFieldDelete', handleCustomFieldDelete);
|
||||
|
||||
socket.off('customFieldValueUpdate', handleCustomFieldValueUpdate);
|
||||
socket.off('customFieldValueDelete', handleCustomFieldValueDelete);
|
||||
|
||||
socket.off('commentCreate', handleCommentCreate);
|
||||
socket.off('commentUpdate', handleCommentUpdate);
|
||||
socket.off('commentDelete', handleCommentDelete);
|
||||
|
||||
socket.off('actionCreate', handleActivityCreate);
|
||||
socket.off('actionUpdate', handleActivityUpdate);
|
||||
socket.off('actionDelete', handleActivityDelete);
|
||||
|
||||
socket.off('notificationCreate', handleNotificationCreate);
|
||||
socket.off('notificationUpdate', handleNotificationUpdate);
|
||||
|
||||
socket.off('notificationServiceCreate', handleNotificationServiceCreate);
|
||||
socket.off('notificationServiceUpdate', handleNotificationServiceUpdate);
|
||||
socket.off('notificationServiceDelete', handleNotificationServiceDelete);
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* taskListsWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.TASK_LIST_IN_CURRENT_CARD_CREATE, ({ payload: { data } }) =>
|
||||
services.createTaskListInCurrentCard(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_LIST_CREATE_HANDLE, ({ payload: { taskList } }) =>
|
||||
services.handleTaskListCreate(taskList),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_LIST_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateTaskList(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_LIST_UPDATE_HANDLE, ({ payload: { taskList } }) =>
|
||||
services.handleTaskListUpdate(taskList),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_LIST_MOVE, ({ payload: { id, index } }) =>
|
||||
services.moveTaskList(id, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_LIST_DELETE, ({ payload: { id } }) =>
|
||||
services.deleteTaskList(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_LIST_DELETE_HANDLE, ({ payload: { taskList } }) =>
|
||||
services.handleTaskListDelete(taskList),
|
||||
),
|
||||
]);
|
||||
}
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -5,8 +10,8 @@ import EntryActionTypes from '../../../constants/EntryActionTypes';
|
||||
|
||||
export default function* tasksWatchers() {
|
||||
yield all([
|
||||
takeEvery(EntryActionTypes.TASK_IN_CURRENT_CARD_CREATE, ({ payload: { data } }) =>
|
||||
services.createTaskInCurrentCard(data),
|
||||
takeEvery(EntryActionTypes.TASK_CREATE, ({ payload: { taskListId, data } }) =>
|
||||
services.createTask(taskListId, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_CREATE_HANDLE, ({ payload: { task } }) =>
|
||||
services.handleTaskCreate(task),
|
||||
@@ -17,8 +22,8 @@ export default function* tasksWatchers() {
|
||||
takeEvery(EntryActionTypes.TASK_UPDATE_HANDLE, ({ payload: { task } }) =>
|
||||
services.handleTaskUpdate(task),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_MOVE, ({ payload: { id, index } }) =>
|
||||
services.moveTask(id, index),
|
||||
takeEvery(EntryActionTypes.TASK_MOVE, ({ payload: { id, taskListId, index } }) =>
|
||||
services.moveTask(id, taskListId, index),
|
||||
),
|
||||
takeEvery(EntryActionTypes.TASK_DELETE, ({ payload: { id } }) => services.deleteTask(id)),
|
||||
takeEvery(EntryActionTypes.TASK_DELETE_HANDLE, ({ payload: { task } }) =>
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -71,6 +76,9 @@ export default function* usersWatchers() {
|
||||
takeEvery(EntryActionTypes.USER_TO_CURRENT_CARD_ADD, ({ payload: { id } }) =>
|
||||
services.addUserToCurrentCard(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_USER_TO_CURRENT_CARD_ADD, () =>
|
||||
services.addCurrentUserToCurrentCard(),
|
||||
),
|
||||
takeEvery(EntryActionTypes.USER_TO_CARD_ADD_HANDLE, ({ payload: { cardMembership } }) =>
|
||||
services.handleUserToCardAdd(cardMembership),
|
||||
),
|
||||
@@ -80,11 +88,15 @@ export default function* usersWatchers() {
|
||||
takeEvery(EntryActionTypes.USER_FROM_CURRENT_CARD_REMOVE, ({ payload: { id } }) =>
|
||||
services.removeUserFromCurrentCard(id),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_USER_FROM_CURRENT_CARD_REMOVE, () =>
|
||||
services.removeCurrentUserFromCurrentCard(),
|
||||
),
|
||||
takeEvery(EntryActionTypes.USER_FROM_CARD_REMOVE_HANDLE, ({ payload: { cardMembership } }) =>
|
||||
services.handleUserFromCardRemove(cardMembership),
|
||||
),
|
||||
takeEvery(EntryActionTypes.USER_TO_FILTER_IN_CURRENT_BOARD_ADD, ({ payload: { id } }) =>
|
||||
services.addUserToFilterInCurrentBoard(id),
|
||||
takeEvery(
|
||||
EntryActionTypes.USER_TO_FILTER_IN_CURRENT_BOARD_ADD,
|
||||
({ payload: { id, replace } }) => services.addUserToFilterInCurrentBoard(id, replace),
|
||||
),
|
||||
takeEvery(EntryActionTypes.USER_FROM_FILTER_IN_CURRENT_BOARD_REMOVE, ({ payload: { id } }) =>
|
||||
services.removeUserFromFilterInCurrentBoard(id),
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { call } from 'redux-saga/effects';
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, select } from 'redux-saga/effects';
|
||||
|
||||
import loginSaga from './login';
|
||||
import coreSaga from './core';
|
||||
import { getAccessToken } from '../utils/access-token-storage';
|
||||
import selectors from '../selectors';
|
||||
|
||||
export default function* rootSaga() {
|
||||
const accessToken = yield call(getAccessToken);
|
||||
const accessToken = yield select(selectors.selectAccessToken);
|
||||
|
||||
if (!accessToken) {
|
||||
yield call(loginSaga);
|
||||
|
||||
@@ -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 { all, call, cancel, fork, take } from 'redux-saga/effects';
|
||||
|
||||
import watchers from './watchers';
|
||||
@@ -8,8 +13,7 @@ export default function* loginSaga() {
|
||||
const watcherTasks = yield all(watchers.map((watcher) => fork(watcher)));
|
||||
|
||||
yield fork(services.initializeLogin);
|
||||
|
||||
yield take([ActionTypes.AUTHENTICATE__SUCCESS, ActionTypes.USING_OIDC_AUTHENTICATE__SUCCESS]);
|
||||
yield take([ActionTypes.AUTHENTICATE__SUCCESS, ActionTypes.WITH_OIDC_AUTHENTICATE__SUCCESS]);
|
||||
|
||||
yield cancel(watcherTasks);
|
||||
yield call(services.goToRoot);
|
||||
|
||||
@@ -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 router from './router';
|
||||
import login from './login';
|
||||
|
||||
|
||||
@@ -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 { nanoid } from 'nanoid';
|
||||
import { call, put, select } from 'redux-saga/effects';
|
||||
import { replace } from '../../../lib/redux-router';
|
||||
@@ -29,7 +34,7 @@ export function* authenticate(data) {
|
||||
yield put(actions.authenticate.success(accessToken));
|
||||
}
|
||||
|
||||
export function* authenticateUsingOidc() {
|
||||
export function* authenticateWithOidc() {
|
||||
const oidcConfig = yield select(selectors.selectOidcConfig);
|
||||
|
||||
const state = nanoid();
|
||||
@@ -45,7 +50,7 @@ export function* authenticateUsingOidc() {
|
||||
window.location.href = redirectUrl;
|
||||
}
|
||||
|
||||
export function* authenticateUsingOidcCallback() {
|
||||
export function* authenticateWithOidcCallback() {
|
||||
// https://github.com/plankanban/planka/issues/511#issuecomment-1771385639
|
||||
const params = new URLSearchParams(window.location.hash.substring(1) || window.location.search);
|
||||
|
||||
@@ -59,7 +64,7 @@ export function* authenticateUsingOidcCallback() {
|
||||
|
||||
if (params.get('error') !== null) {
|
||||
yield put(
|
||||
actions.authenticateUsingOidc.failure(
|
||||
actions.authenticateWithOidc.failure(
|
||||
new Error(
|
||||
`OIDC Authorization error: ${params.get('error')}: ${params.get('error_description')}`,
|
||||
),
|
||||
@@ -71,14 +76,14 @@ export function* authenticateUsingOidcCallback() {
|
||||
const code = params.get('code');
|
||||
if (code === null) {
|
||||
yield put(
|
||||
actions.authenticateUsingOidc.failure(new Error('Invalid OIDC response: no code parameter')),
|
||||
actions.authenticateWithOidc.failure(new Error('Invalid OIDC response: no code parameter')),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.get('state') !== state) {
|
||||
yield put(
|
||||
actions.authenticateUsingOidc.failure(
|
||||
actions.authenticateWithOidc.failure(
|
||||
new Error('Unable to process OIDC response: state mismatch'),
|
||||
),
|
||||
);
|
||||
@@ -87,7 +92,7 @@ export function* authenticateUsingOidcCallback() {
|
||||
|
||||
if (nonce === null) {
|
||||
yield put(
|
||||
actions.authenticateUsingOidc.failure(
|
||||
actions.authenticateWithOidc.failure(
|
||||
new Error('Unable to process OIDC response: no nonce issued'),
|
||||
),
|
||||
);
|
||||
@@ -96,17 +101,17 @@ export function* authenticateUsingOidcCallback() {
|
||||
|
||||
let accessToken;
|
||||
try {
|
||||
({ item: accessToken } = yield call(api.exchangeForAccessTokenUsingOidc, {
|
||||
({ item: accessToken } = yield call(api.exchangeForAccessTokenWithOidc, {
|
||||
code,
|
||||
nonce,
|
||||
}));
|
||||
} catch (error) {
|
||||
yield put(actions.authenticateUsingOidc.failure(error));
|
||||
yield put(actions.authenticateWithOidc.failure(error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield call(setAccessToken, accessToken);
|
||||
yield put(actions.authenticateUsingOidc.success(accessToken));
|
||||
yield put(actions.authenticateWithOidc.success(accessToken));
|
||||
}
|
||||
|
||||
export function* clearAuthenticateError() {
|
||||
@@ -116,7 +121,7 @@ export function* clearAuthenticateError() {
|
||||
export default {
|
||||
initializeLogin,
|
||||
authenticate,
|
||||
authenticateUsingOidc,
|
||||
authenticateUsingOidcCallback,
|
||||
authenticateWithOidc,
|
||||
authenticateWithOidcCallback,
|
||||
clearAuthenticateError,
|
||||
};
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import { call, put, select, take } from 'redux-saga/effects';
|
||||
import { push } from '../../../lib/redux-router';
|
||||
|
||||
import { authenticateUsingOidc, authenticateUsingOidcCallback } from './login';
|
||||
import { authenticateWithOidc, authenticateWithOidcCallback } from './login';
|
||||
import selectors from '../../../selectors';
|
||||
import ActionTypes from '../../../constants/ActionTypes';
|
||||
import Paths from '../../../constants/Paths';
|
||||
|
||||
export function* goTo(pathname) {
|
||||
yield put(push(pathname));
|
||||
}
|
||||
|
||||
export function* goToLogin() {
|
||||
yield put(push(Paths.LOGIN));
|
||||
yield call(goTo, Paths.LOGIN);
|
||||
}
|
||||
|
||||
export function* goToRoot() {
|
||||
yield put(push(Paths.ROOT));
|
||||
yield call(goTo, Paths.ROOT);
|
||||
}
|
||||
|
||||
export function* handleLocationChange() {
|
||||
@@ -46,14 +55,14 @@ export function* handleLocationChange() {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
|
||||
if (params.has('authenticateWithOidc')) {
|
||||
yield call(authenticateUsingOidc);
|
||||
yield call(authenticateWithOidc);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case Paths.OIDC_CALLBACK:
|
||||
yield call(authenticateUsingOidcCallback);
|
||||
yield call(authenticateWithOidcCallback);
|
||||
|
||||
break;
|
||||
default:
|
||||
@@ -61,6 +70,7 @@ export function* handleLocationChange() {
|
||||
}
|
||||
|
||||
export default {
|
||||
goTo,
|
||||
goToLogin,
|
||||
goToRoot,
|
||||
handleLocationChange,
|
||||
|
||||
@@ -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 router from './router';
|
||||
import login from './login';
|
||||
|
||||
|
||||
@@ -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 { all, takeEvery } from 'redux-saga/effects';
|
||||
|
||||
import services from '../services';
|
||||
@@ -8,7 +13,7 @@ export default function* loginWatchers() {
|
||||
takeEvery(EntryActionTypes.AUTHENTICATE, ({ payload: { data } }) =>
|
||||
services.authenticate(data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.USING_OIDC_AUTHENTICATE, () => services.authenticateUsingOidc()),
|
||||
takeEvery(EntryActionTypes.WITH_OIDC_AUTHENTICATE, () => services.authenticateWithOidc()),
|
||||
takeEvery(EntryActionTypes.AUTHENTICATE_ERROR_CLEAR, () => services.clearAuthenticateError()),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -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 { takeEvery } from 'redux-saga/effects';
|
||||
import { LOCATION_CHANGE_HANDLE } from '../../../lib/redux-router';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user