1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-19 05:09:43 +02:00

Preserve members and labels when transfer card to another board

This commit is contained in:
Maksim Eltyshev 2020-05-09 05:30:52 +05:00
parent 5e0b2b9f0a
commit 044fe17dbf
17 changed files with 321 additions and 64 deletions

View file

@ -34,11 +34,22 @@ export const createCardRequested = (localId, data) => ({
},
});
export const createCardSucceeded = (localId, card) => ({
export const createCardSucceeded = (
localId,
card,
cardMemberships,
cardLabels,
tasks,
attachments,
) => ({
type: ActionTypes.CARD_CREATE_SUCCEEDED,
payload: {
localId,
card,
cardMemberships,
cardLabels,
tasks,
attachments,
},
});
@ -50,10 +61,14 @@ export const createCardFailed = (localId, error) => ({
},
});
export const createCardReceived = (card) => ({
export const createCardReceived = (card, cardMemberships, cardLabels, tasks, attachments) => ({
type: ActionTypes.CARD_CREATE_RECEIVED,
payload: {
card,
cardMemberships,
cardLabels,
tasks,
attachments,
},
});

View file

@ -1,4 +1,5 @@
import socket from './socket';
import { transformAttachment } from './attachments';
/* Transformers */
@ -38,6 +39,10 @@ const createCard = (listId, data, headers) =>
socket.post(`/lists/${listId}/cards`, transformCardData(data), headers).then((body) => ({
...body,
item: transformCard(body.item),
included: {
...body.included,
attachments: body.included.attachments.map(transformAttachment),
},
}));
const getCard = (id, headers) =>
@ -64,12 +69,21 @@ const makeHandleCardCreate = (next) => (body) => {
next({
...body,
item: transformCard(body.item),
included: {
...body.included,
attachments: body.included.attachments.map(transformAttachment),
},
});
};
const makeHandleCardUpdate = makeHandleCardCreate;
const makeHandleCardUpdate = (next) => (body) => {
next({
...body,
item: transformCard(body.item),
});
};
const makeHandleCardDelete = makeHandleCardCreate;
const makeHandleCardDelete = makeHandleCardUpdate;
export default {
createCard,

View file

@ -20,6 +20,8 @@ export default class extends Model {
static reducer({ type, payload }, Attachment) {
switch (type) {
case ActionTypes.BOARD_FETCH_SUCCEEDED:
case ActionTypes.CARD_CREATE_SUCCEEDED:
case ActionTypes.CARD_CREATE_RECEIVED:
payload.attachments.forEach((attachment) => {
Attachment.upsert(attachment);
});

View file

@ -80,27 +80,15 @@ export default class extends Model {
break;
case ActionTypes.CARD_CREATE:
case ActionTypes.CARD_CREATE_RECEIVED:
case ActionTypes.CARD_FETCH_SUCCEEDED:
case ActionTypes.NOTIFICATION_CREATE_RECEIVED:
Card.upsert(payload.card);
break;
case ActionTypes.CARD_UPDATE: {
const card = Card.withId(payload.id);
// FIXME: hack
if (payload.data.boardId && payload.data.boardId !== card.boardId) {
card.isSubscribed = false;
card.users.clear();
card.labels.clear();
}
card.update(payload.data);
case ActionTypes.CARD_UPDATE:
Card.withId(payload.id).update(payload.data);
break;
}
case ActionTypes.CARD_DELETE:
Card.withId(payload.id).deleteWithRelated();
@ -109,11 +97,36 @@ export default class extends Model {
Card.withId(payload.localId).delete();
Card.upsert(payload.card);
break;
case ActionTypes.CARD_UPDATE_RECEIVED:
Card.withId(payload.card.id).update(payload.card);
payload.cardMemberships.forEach(({ cardId, userId }) => {
Card.withId(cardId).users.add(userId);
});
payload.cardLabels.forEach(({ cardId, labelId }) => {
Card.withId(cardId).labels.add(labelId);
});
break;
case ActionTypes.CARD_CREATE_RECEIVED:
Card.upsert(payload.card);
payload.cardMemberships.forEach(({ cardId, userId }) => {
Card.withId(cardId).users.add(userId);
});
payload.cardLabels.forEach(({ cardId, labelId }) => {
Card.withId(cardId).labels.add(labelId);
});
break;
case ActionTypes.CARD_UPDATE_RECEIVED: {
const card = Card.withId(payload.card.id);
if (card) {
card.update(payload.card);
}
break;
}
case ActionTypes.CARD_DELETE_RECEIVED:
Card.withId(payload.card.id).deleteWithRelated();
@ -177,6 +190,7 @@ export default class extends Model {
deleteWithRelated() {
this.tasks.delete();
this.attachments.delete();
this.actions.delete();
this.delete();

View file

@ -21,6 +21,8 @@ export default class extends Model {
static reducer({ type, payload }, Task) {
switch (type) {
case ActionTypes.BOARD_FETCH_SUCCEEDED:
case ActionTypes.CARD_CREATE_SUCCEEDED:
case ActionTypes.CARD_CREATE_RECEIVED:
payload.tasks.forEach((task) => {
Task.upsert(task);
});

View file

@ -26,9 +26,19 @@ export function* createCardRequest(listId, localId, data) {
);
try {
const { item } = yield call(request, api.createCard, listId, data);
const {
item,
included: { cardMemberships, cardLabels, tasks, attachments },
} = yield call(request, api.createCard, listId, data);
const action = createCardSucceeded(localId, item);
const action = createCardSucceeded(
localId,
item,
cardMemberships,
cardLabels,
tasks,
attachments,
);
yield put(action);
return {

View file

@ -2,11 +2,19 @@ import { call, put, select } from 'redux-saga/effects';
import { goToBoardService } from './router';
import { createCardRequest, deleteCardRequest, updateCardRequest } from '../requests';
import { nextCardPositionSelector, pathSelector } from '../../../selectors';
import {
boardByIdSelector,
cardByIdSelector,
listByIdSelector,
nextCardPositionSelector,
pathSelector,
} from '../../../selectors';
import { createCard, deleteCard, updateCard } from '../../../actions';
import { createLocalId } from '../../../utils/local-id';
export function* createCardService(listId, data) {
const { boardId } = yield select(listByIdSelector, listId);
const nextData = {
...data,
position: yield select(nextCardPositionSelector, listId),
@ -18,6 +26,7 @@ export function* createCardService(listId, data) {
createCard({
...nextData,
listId,
boardId,
id: localId,
}),
);
@ -52,19 +61,40 @@ export function* moveCurrentCardService(listId, index) {
}
export function* transferCardService(id, boardId, listId, index) {
const position = yield select(nextCardPositionSelector, listId, index, id);
const { cardId: currentCardId, boardId: currentBoardId } = yield select(pathSelector);
yield call(updateCardService, id, {
boardId,
listId,
position,
});
if (id === currentCardId) {
yield call(goToBoardService, currentBoardId);
}
const card = yield select(cardByIdSelector, id);
const board = yield select(boardByIdSelector, boardId);
yield put(deleteCard(id));
if (board.isFetching === false) {
const position = yield select(nextCardPositionSelector, listId, index, id);
yield put(
createCard({
...card,
listId,
boardId,
position,
}),
);
yield call(updateCardRequest, id, {
listId,
boardId,
position,
});
}
}
export function* transferCurrentCardService(boardId, listId, index) {
const { cardId, boardId: currentBoardId } = yield select(pathSelector);
const { cardId } = yield select(pathSelector);
yield call(goToBoardService, currentBoardId);
yield call(transferCardService, cardId, boardId, listId, index);
}

View file

@ -163,8 +163,8 @@ export function* deleteLabelReceivedService(label) {
yield put(deleteLabelReceived(label));
}
export function* createCardReceivedService(card) {
yield put(createCardReceived(card));
export function* createCardReceivedService(card, cardMemberships, cardLabels, tasks, attachments) {
yield put(createCardReceived(card, cardMemberships, cardLabels, tasks, attachments));
}
export function* updateCardReceivedService(card) {

View file

@ -116,9 +116,11 @@ const createSocketEventsChannel = () =>
emit([deleteLabelReceivedService, item]);
};
const handleCardCreate = api.makeHandleCardCreate(({ item }) => {
emit([createCardReceivedService, item]);
});
const handleCardCreate = api.makeHandleCardCreate(
({ item, included: { cardMemberships, cardLabels, tasks, attachments } }) => {
emit([createCardReceivedService, item, cardMemberships, cardLabels, tasks, attachments]);
},
);
const handleCardUpdate = api.makeHandleCardUpdate(({ item }) => {
emit([updateCardReceivedService, item]);