feat: Add ability to move lists between boards (#1208)
This commit is contained in:
@@ -58,10 +58,34 @@ updateList.failure = (id, error) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleListUpdate = (list) => ({
|
const handleListUpdate = (
|
||||||
|
list,
|
||||||
|
isFetched,
|
||||||
|
users,
|
||||||
|
cards,
|
||||||
|
cardMemberships,
|
||||||
|
cardLabels,
|
||||||
|
taskLists,
|
||||||
|
tasks,
|
||||||
|
attachments,
|
||||||
|
customFieldGroups,
|
||||||
|
customFields,
|
||||||
|
customFieldValues,
|
||||||
|
) => ({
|
||||||
type: ActionTypes.LIST_UPDATE_HANDLE,
|
type: ActionTypes.LIST_UPDATE_HANDLE,
|
||||||
payload: {
|
payload: {
|
||||||
list,
|
list,
|
||||||
|
isFetched,
|
||||||
|
users,
|
||||||
|
cards,
|
||||||
|
cardMemberships,
|
||||||
|
cardLabels,
|
||||||
|
taskLists,
|
||||||
|
tasks,
|
||||||
|
attachments,
|
||||||
|
customFieldGroups,
|
||||||
|
customFields,
|
||||||
|
customFieldValues,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import { useSteps } from '../../../hooks';
|
|||||||
import { ListTypes } from '../../../constants/Enums';
|
import { ListTypes } from '../../../constants/Enums';
|
||||||
import EditColorStep from './EditColorStep';
|
import EditColorStep from './EditColorStep';
|
||||||
import SortStep from './SortStep';
|
import SortStep from './SortStep';
|
||||||
|
import MoveStep from './MoveStep';
|
||||||
import SelectListTypeStep from '../SelectListTypeStep';
|
import SelectListTypeStep from '../SelectListTypeStep';
|
||||||
import ConfirmationStep from '../../common/ConfirmationStep';
|
import ConfirmationStep from '../../common/ConfirmationStep';
|
||||||
import ArchiveCardsStep from '../../cards/ArchiveCardsStep';
|
import ArchiveCardsStep from '../../cards/ArchiveCardsStep';
|
||||||
@@ -26,6 +27,7 @@ const StepTypes = {
|
|||||||
EDIT_TYPE: 'EDIT_TYPE',
|
EDIT_TYPE: 'EDIT_TYPE',
|
||||||
EDIT_COLOR: 'EDIT_COLOR',
|
EDIT_COLOR: 'EDIT_COLOR',
|
||||||
SORT: 'SORT',
|
SORT: 'SORT',
|
||||||
|
MOVE: 'MOVE',
|
||||||
ARCHIVE_CARDS: 'ARCHIVE_CARDS',
|
ARCHIVE_CARDS: 'ARCHIVE_CARDS',
|
||||||
DELETE: 'DELETE',
|
DELETE: 'DELETE',
|
||||||
};
|
};
|
||||||
@@ -76,6 +78,10 @@ const ActionsStep = React.memo(({ listId, onNameEdit, onCardAdd, onClose }) => {
|
|||||||
openStep(StepTypes.SORT);
|
openStep(StepTypes.SORT);
|
||||||
}, [openStep]);
|
}, [openStep]);
|
||||||
|
|
||||||
|
const handleMoveClick = useCallback(() => {
|
||||||
|
openStep(StepTypes.MOVE);
|
||||||
|
}, [openStep]);
|
||||||
|
|
||||||
const handleArchiveCardsClick = useCallback(() => {
|
const handleArchiveCardsClick = useCallback(() => {
|
||||||
openStep(StepTypes.ARCHIVE_CARDS);
|
openStep(StepTypes.ARCHIVE_CARDS);
|
||||||
}, [openStep]);
|
}, [openStep]);
|
||||||
@@ -102,6 +108,8 @@ const ActionsStep = React.memo(({ listId, onNameEdit, onCardAdd, onClose }) => {
|
|||||||
return <EditColorStep listId={listId} onBack={handleBack} onClose={onClose} />;
|
return <EditColorStep listId={listId} onBack={handleBack} onClose={onClose} />;
|
||||||
case StepTypes.SORT:
|
case StepTypes.SORT:
|
||||||
return <SortStep listId={listId} onBack={handleBack} onClose={onClose} />;
|
return <SortStep listId={listId} onBack={handleBack} onClose={onClose} />;
|
||||||
|
case StepTypes.MOVE:
|
||||||
|
return <MoveStep id={listId} onBack={handleBack} onClose={onClose} />;
|
||||||
case StepTypes.ARCHIVE_CARDS:
|
case StepTypes.ARCHIVE_CARDS:
|
||||||
return <ArchiveCardsStep listId={listId} onBack={handleBack} onClose={onClose} />;
|
return <ArchiveCardsStep listId={listId} onBack={handleBack} onClose={onClose} />;
|
||||||
case StepTypes.DELETE:
|
case StepTypes.DELETE:
|
||||||
@@ -157,6 +165,12 @@ const ActionsStep = React.memo(({ listId, onNameEdit, onCardAdd, onClose }) => {
|
|||||||
context: 'title',
|
context: 'title',
|
||||||
})}
|
})}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item className={styles.menuItem} onClick={handleMoveClick}>
|
||||||
|
<Icon name="share square outline" className={styles.menuItemIcon} />
|
||||||
|
{t('action.moveList', {
|
||||||
|
context: 'title',
|
||||||
|
})}
|
||||||
|
</Menu.Item>
|
||||||
{list.type === ListTypes.CLOSED && (
|
{list.type === ListTypes.CLOSED && (
|
||||||
<Menu.Item className={styles.menuItem} onClick={handleArchiveCardsClick}>
|
<Menu.Item className={styles.menuItem} onClick={handleArchiveCardsClick}>
|
||||||
<Icon name="folder open outline" className={styles.menuItemIcon} />
|
<Icon name="folder open outline" className={styles.menuItemIcon} />
|
||||||
|
|||||||
@@ -0,0 +1,133 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React, { useMemo, useCallback } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { Button, Dropdown, Form } from 'semantic-ui-react';
|
||||||
|
import { Popup } from '../../../lib/custom-ui';
|
||||||
|
|
||||||
|
import selectors from '../../../selectors';
|
||||||
|
import entryActions from '../../../entry-actions';
|
||||||
|
import { useForm } from '../../../hooks';
|
||||||
|
|
||||||
|
import styles from './MoveStep.module.scss';
|
||||||
|
|
||||||
|
const MoveStep = React.memo(({ id, onBack, onClose }) => {
|
||||||
|
const selectListById = useMemo(() => selectors.makeSelectListById(), []);
|
||||||
|
const selectBoardById = useMemo(() => selectors.makeSelectBoardById(), []);
|
||||||
|
|
||||||
|
const projectsToBoards = useSelector(
|
||||||
|
selectors.selectProjectsToBoardsWithEditorRightsForCurrentUser,
|
||||||
|
);
|
||||||
|
|
||||||
|
const list = useSelector((state) => selectListById(state, id));
|
||||||
|
const projectId = useSelector((state) => selectBoardById(state, list.boardId).projectId);
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
const [t] = useTranslation();
|
||||||
|
|
||||||
|
const defaultPath = useMemo(
|
||||||
|
() => ({
|
||||||
|
projectId,
|
||||||
|
boardId: list.boardId,
|
||||||
|
}),
|
||||||
|
[list.boardId, projectId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const [path, handleFieldChange] = useForm(() => ({
|
||||||
|
projectId: null,
|
||||||
|
boardId: null,
|
||||||
|
...defaultPath,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const selectedProject = useMemo(
|
||||||
|
() => projectsToBoards.find((project) => project.id === path.projectId) || null,
|
||||||
|
[projectsToBoards, path.projectId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const selectedBoard = useMemo(
|
||||||
|
() =>
|
||||||
|
(selectedProject && selectedProject.boards.find((board) => board.id === path.boardId)) ||
|
||||||
|
null,
|
||||||
|
[selectedProject, path.boardId],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleSubmit = useCallback(() => {
|
||||||
|
if (selectedBoard.id !== defaultPath.boardId) {
|
||||||
|
dispatch(entryActions.transferList(id, selectedBoard.id));
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose();
|
||||||
|
}, [id, onClose, dispatch, defaultPath, selectedBoard]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Popup.Header onBack={onBack}>
|
||||||
|
{t('common.moveList', {
|
||||||
|
context: 'title',
|
||||||
|
})}
|
||||||
|
</Popup.Header>
|
||||||
|
<Popup.Content>
|
||||||
|
<Form onSubmit={handleSubmit}>
|
||||||
|
<div className={styles.text}>{t('common.project')}</div>
|
||||||
|
<Dropdown
|
||||||
|
fluid
|
||||||
|
selection
|
||||||
|
name="projectId"
|
||||||
|
options={projectsToBoards.map((project) => ({
|
||||||
|
text: project.name,
|
||||||
|
value: project.id,
|
||||||
|
}))}
|
||||||
|
value={selectedProject && selectedProject.id}
|
||||||
|
placeholder={
|
||||||
|
projectsToBoards.length === 0 ? t('common.noProjects') : t('common.selectProject')
|
||||||
|
}
|
||||||
|
disabled={projectsToBoards.length === 0}
|
||||||
|
className={styles.field}
|
||||||
|
onChange={handleFieldChange}
|
||||||
|
/>
|
||||||
|
{selectedProject && (
|
||||||
|
<>
|
||||||
|
<div className={styles.text}>{t('common.board')}</div>
|
||||||
|
<Dropdown
|
||||||
|
fluid
|
||||||
|
selection
|
||||||
|
name="boardId"
|
||||||
|
options={selectedProject.boards.map((board) => ({
|
||||||
|
text: board.name,
|
||||||
|
value: board.id,
|
||||||
|
}))}
|
||||||
|
value={selectedBoard && selectedBoard.id}
|
||||||
|
placeholder={
|
||||||
|
selectedProject.boards.length === 0
|
||||||
|
? t('common.noBoards')
|
||||||
|
: t('common.selectBoard')
|
||||||
|
}
|
||||||
|
disabled={selectedProject.boards.length === 0}
|
||||||
|
className={styles.field}
|
||||||
|
onChange={handleFieldChange}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<Button positive content={t('action.move')} disabled={!selectedBoard} />
|
||||||
|
</Form>
|
||||||
|
</Popup.Content>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
MoveStep.propTypes = {
|
||||||
|
id: PropTypes.string.isRequired,
|
||||||
|
onBack: PropTypes.func,
|
||||||
|
onClose: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
MoveStep.defaultProps = {
|
||||||
|
onBack: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MoveStep;
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
:global(#app) {
|
||||||
|
.field {
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text {
|
||||||
|
color: #444444;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -164,6 +164,7 @@ export default {
|
|||||||
LIST_UPDATE: `${PREFIX}/LIST_UPDATE`,
|
LIST_UPDATE: `${PREFIX}/LIST_UPDATE`,
|
||||||
LIST_UPDATE_HANDLE: `${PREFIX}/LIST_UPDATE_HANDLE`,
|
LIST_UPDATE_HANDLE: `${PREFIX}/LIST_UPDATE_HANDLE`,
|
||||||
LIST_MOVE: `${PREFIX}/LIST_MOVE`,
|
LIST_MOVE: `${PREFIX}/LIST_MOVE`,
|
||||||
|
LIST_TRANSFER: `${PREFIX}/LIST_TRANSFER`,
|
||||||
LIST_SORT: `${PREFIX}/LIST_SORT`,
|
LIST_SORT: `${PREFIX}/LIST_SORT`,
|
||||||
LIST_CARDS_TO_ARCHIVE_LIST_MOVE: `${PREFIX}/LIST_CARDS_TO_ARCHIVE_LIST_MOVE`,
|
LIST_CARDS_TO_ARCHIVE_LIST_MOVE: `${PREFIX}/LIST_CARDS_TO_ARCHIVE_LIST_MOVE`,
|
||||||
TRASH_LIST_IN_CURRENT_BOARD_CLEAR: `${PREFIX}/TRASH_LIST_IN_CURRENT_BOARD_CLEAR`,
|
TRASH_LIST_IN_CURRENT_BOARD_CLEAR: `${PREFIX}/TRASH_LIST_IN_CURRENT_BOARD_CLEAR`,
|
||||||
|
|||||||
@@ -42,6 +42,15 @@ const moveList = (id, index) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const transferList = (id, boardId, index = 0) => ({
|
||||||
|
type: EntryActionTypes.LIST_TRANSFER,
|
||||||
|
payload: {
|
||||||
|
id,
|
||||||
|
boardId,
|
||||||
|
index,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const sortList = (id, data) => {
|
const sortList = (id, data) => {
|
||||||
return {
|
return {
|
||||||
type: EntryActionTypes.LIST_SORT,
|
type: EntryActionTypes.LIST_SORT,
|
||||||
@@ -92,6 +101,7 @@ export default {
|
|||||||
updateList,
|
updateList,
|
||||||
handleListUpdate,
|
handleListUpdate,
|
||||||
moveList,
|
moveList,
|
||||||
|
transferList,
|
||||||
sortList,
|
sortList,
|
||||||
moveListCardsToArchiveList,
|
moveListCardsToArchiveList,
|
||||||
clearTrashListInCurrentBoard,
|
clearTrashListInCurrentBoard,
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'نقل البطاقة',
|
moveCard_title: 'نقل البطاقة',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'الاسم',
|
name: 'الاسم',
|
||||||
newEmail: 'بريد إلكتروني جديد',
|
newEmail: 'بريد إلكتروني جديد',
|
||||||
@@ -408,6 +409,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'نقل',
|
move: 'نقل',
|
||||||
moveCard_title: 'نقل البطاقة',
|
moveCard_title: 'نقل البطاقة',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'حذف',
|
remove: 'حذف',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Преместване на карта',
|
moveCard_title: 'Преместване на карта',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Име',
|
name: 'Име',
|
||||||
newEmail: 'Нов имейл',
|
newEmail: 'Нов имейл',
|
||||||
@@ -413,6 +414,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Преместване',
|
move: 'Преместване',
|
||||||
moveCard_title: 'Преместване на карта',
|
moveCard_title: 'Преместване на карта',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Премахване',
|
remove: 'Премахване',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Přesunout kartu',
|
moveCard_title: 'Přesunout kartu',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Moje vlastní',
|
myOwn_title: 'Moje vlastní',
|
||||||
name: 'Jméno',
|
name: 'Jméno',
|
||||||
newEmail: 'Nový e-mail',
|
newEmail: 'Nový e-mail',
|
||||||
@@ -423,6 +424,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Vytvořit sdílený projekt',
|
makeProjectShared_title: 'Vytvořit sdílený projekt',
|
||||||
move: 'Přesunout',
|
move: 'Přesunout',
|
||||||
moveCard_title: 'Přesunout kartu',
|
moveCard_title: 'Přesunout kartu',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Odstranit',
|
remove: 'Odstranit',
|
||||||
removeAssignee: 'Odstranit přiřazení',
|
removeAssignee: 'Odstranit přiřazení',
|
||||||
removeColor: 'Smazat barvu',
|
removeColor: 'Smazat barvu',
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Flyt kort',
|
moveCard_title: 'Flyt kort',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Egne',
|
myOwn_title: 'Egne',
|
||||||
name: 'Navn',
|
name: 'Navn',
|
||||||
newEmail: 'Ny e-mail',
|
newEmail: 'Ny e-mail',
|
||||||
@@ -433,6 +434,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Del projekt',
|
makeProjectShared_title: 'Del projekt',
|
||||||
move: 'Flyt',
|
move: 'Flyt',
|
||||||
moveCard_title: 'Flyt kort',
|
moveCard_title: 'Flyt kort',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Fjern',
|
remove: 'Fjern',
|
||||||
removeAssignee: 'Fjern ansvarlig',
|
removeAssignee: 'Fjern ansvarlig',
|
||||||
removeColor: 'Fjern farve',
|
removeColor: 'Fjern farve',
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Karte verschieben',
|
moveCard_title: 'Karte verschieben',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Meine eigenen',
|
myOwn_title: 'Meine eigenen',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
newEmail: 'Neue E-Mail-Adresse',
|
newEmail: 'Neue E-Mail-Adresse',
|
||||||
@@ -438,6 +439,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Projekt freigeben',
|
makeProjectShared_title: 'Projekt freigeben',
|
||||||
move: 'Verschieben',
|
move: 'Verschieben',
|
||||||
moveCard_title: 'Karte bewegen',
|
moveCard_title: 'Karte bewegen',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Löschen',
|
remove: 'Löschen',
|
||||||
removeAssignee: 'Zuständigen entfernen',
|
removeAssignee: 'Zuständigen entfernen',
|
||||||
removeColor: 'Farbe löschen',
|
removeColor: 'Farbe löschen',
|
||||||
|
|||||||
@@ -233,6 +233,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Μετακίνηση κάρτας',
|
moveCard_title: 'Μετακίνηση κάρτας',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Δικά μου',
|
myOwn_title: 'Δικά μου',
|
||||||
name: 'Όνομα',
|
name: 'Όνομα',
|
||||||
newEmail: 'Νέο e-mail',
|
newEmail: 'Νέο e-mail',
|
||||||
@@ -449,6 +450,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Κάντε το έργο κοινόχρηστο',
|
makeProjectShared_title: 'Κάντε το έργο κοινόχρηστο',
|
||||||
move: 'Μετακίνηση',
|
move: 'Μετακίνηση',
|
||||||
moveCard_title: 'Μετακίνηση κάρτας',
|
moveCard_title: 'Μετακίνηση κάρτας',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Αφαίρεση',
|
remove: 'Αφαίρεση',
|
||||||
removeAssignee: 'Αφαίρεση υπευθύνου',
|
removeAssignee: 'Αφαίρεση υπευθύνου',
|
||||||
removeColor: 'Αφαίρεση χρώματος',
|
removeColor: 'Αφαίρεση χρώματος',
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ export default {
|
|||||||
moreActions: 'More actions',
|
moreActions: 'More actions',
|
||||||
moreActions_title: 'More Actions',
|
moreActions_title: 'More Actions',
|
||||||
moveCard_title: 'Move Card',
|
moveCard_title: 'Move Card',
|
||||||
|
moveList_title: 'Move List',
|
||||||
myOwn_title: 'My Own',
|
myOwn_title: 'My Own',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
newEmail: 'New e-mail',
|
newEmail: 'New e-mail',
|
||||||
@@ -432,6 +433,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Make Project Shared',
|
makeProjectShared_title: 'Make Project Shared',
|
||||||
move: 'Move',
|
move: 'Move',
|
||||||
moveCard_title: 'Move Card',
|
moveCard_title: 'Move Card',
|
||||||
|
moveList_title: 'Move List',
|
||||||
remove: 'Remove',
|
remove: 'Remove',
|
||||||
removeAssignee: 'Remove assignee',
|
removeAssignee: 'Remove assignee',
|
||||||
removeColor: 'Remove color',
|
removeColor: 'Remove color',
|
||||||
|
|||||||
@@ -217,6 +217,7 @@ export default {
|
|||||||
moreActions: 'More actions',
|
moreActions: 'More actions',
|
||||||
moreActions_title: 'More Actions',
|
moreActions_title: 'More Actions',
|
||||||
moveCard_title: 'Move Card',
|
moveCard_title: 'Move Card',
|
||||||
|
moveList_title: 'Move List',
|
||||||
myOwn_title: 'My Own',
|
myOwn_title: 'My Own',
|
||||||
name: 'Name',
|
name: 'Name',
|
||||||
newEmail: 'New e-mail',
|
newEmail: 'New e-mail',
|
||||||
@@ -427,6 +428,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Make Project Shared',
|
makeProjectShared_title: 'Make Project Shared',
|
||||||
move: 'Move',
|
move: 'Move',
|
||||||
moveCard_title: 'Move Card',
|
moveCard_title: 'Move Card',
|
||||||
|
moveList_title: 'Move List',
|
||||||
remove: 'Remove',
|
remove: 'Remove',
|
||||||
removeAssignee: 'Remove assignee',
|
removeAssignee: 'Remove assignee',
|
||||||
removeColor: 'Remove color',
|
removeColor: 'Remove color',
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Mover tarjeta',
|
moveCard_title: 'Mover tarjeta',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Propios',
|
myOwn_title: 'Propios',
|
||||||
name: 'Nombre',
|
name: 'Nombre',
|
||||||
newEmail: 'Nuevo correo',
|
newEmail: 'Nuevo correo',
|
||||||
@@ -432,6 +433,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Hacer proyecto compartido',
|
makeProjectShared_title: 'Hacer proyecto compartido',
|
||||||
move: 'Mover',
|
move: 'Mover',
|
||||||
moveCard_title: 'Mover Tarjeta',
|
moveCard_title: 'Mover Tarjeta',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Remover',
|
remove: 'Remover',
|
||||||
removeAssignee: 'Eliminar asignado',
|
removeAssignee: 'Eliminar asignado',
|
||||||
removeColor: 'Eliminar color',
|
removeColor: 'Eliminar color',
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Liiguta kaart',
|
moveCard_title: 'Liiguta kaart',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Minu omanik',
|
myOwn_title: 'Minu omanik',
|
||||||
name: 'Nimi',
|
name: 'Nimi',
|
||||||
newEmail: 'Uus e-post',
|
newEmail: 'Uus e-post',
|
||||||
@@ -431,6 +432,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Muuda projekt jagatavaks',
|
makeProjectShared_title: 'Muuda projekt jagatavaks',
|
||||||
move: 'Liiguta',
|
move: 'Liiguta',
|
||||||
moveCard_title: 'Liiguta kaart',
|
moveCard_title: 'Liiguta kaart',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Eemalda',
|
remove: 'Eemalda',
|
||||||
removeAssignee: 'Eemalda vastutaja',
|
removeAssignee: 'Eemalda vastutaja',
|
||||||
removeColor: 'Eemalda värv',
|
removeColor: 'Eemalda värv',
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'انتقال کارت',
|
moveCard_title: 'انتقال کارت',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'نام',
|
name: 'نام',
|
||||||
newEmail: 'ایمیل جدید',
|
newEmail: 'ایمیل جدید',
|
||||||
@@ -410,6 +411,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'انتقال',
|
move: 'انتقال',
|
||||||
moveCard_title: 'انتقال کارت',
|
moveCard_title: 'انتقال کارت',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'حذف',
|
remove: 'حذف',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Siirrä kortti',
|
moveCard_title: 'Siirrä kortti',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Omat',
|
myOwn_title: 'Omat',
|
||||||
name: 'Nimi',
|
name: 'Nimi',
|
||||||
newEmail: 'Uusi sähköposti',
|
newEmail: 'Uusi sähköposti',
|
||||||
@@ -431,6 +432,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Jaa projekti',
|
makeProjectShared_title: 'Jaa projekti',
|
||||||
move: 'Siirrä',
|
move: 'Siirrä',
|
||||||
moveCard_title: 'Siirrä kortti',
|
moveCard_title: 'Siirrä kortti',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Poista',
|
remove: 'Poista',
|
||||||
removeAssignee: 'Poista vastuuhenkilö',
|
removeAssignee: 'Poista vastuuhenkilö',
|
||||||
removeColor: 'Poista väri',
|
removeColor: 'Poista väri',
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Déplacer la carte',
|
moveCard_title: 'Déplacer la carte',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Mes projets privés',
|
myOwn_title: 'Mes projets privés',
|
||||||
name: 'Nom',
|
name: 'Nom',
|
||||||
newEmail: 'Nouvel e-mail',
|
newEmail: 'Nouvel e-mail',
|
||||||
@@ -435,6 +436,7 @@ export default {
|
|||||||
makeProjectShared_title: "Transformer le projet en projet d'équipe",
|
makeProjectShared_title: "Transformer le projet en projet d'équipe",
|
||||||
move: 'Déplacer',
|
move: 'Déplacer',
|
||||||
moveCard_title: 'Déplacer la carte',
|
moveCard_title: 'Déplacer la carte',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Supprimer',
|
remove: 'Supprimer',
|
||||||
removeAssignee: 'Retirer le responsable',
|
removeAssignee: 'Retirer le responsable',
|
||||||
removeColor: 'Supprimer la couleur',
|
removeColor: 'Supprimer la couleur',
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ export default {
|
|||||||
moreActions: 'További műveletek',
|
moreActions: 'További műveletek',
|
||||||
moreActions_title: 'További műveletek',
|
moreActions_title: 'További műveletek',
|
||||||
moveCard_title: 'Kártya áthelyezése',
|
moveCard_title: 'Kártya áthelyezése',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Saját',
|
myOwn_title: 'Saját',
|
||||||
name: 'Név',
|
name: 'Név',
|
||||||
newEmail: 'Új e-mail',
|
newEmail: 'Új e-mail',
|
||||||
@@ -432,6 +433,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Projekt megosztása',
|
makeProjectShared_title: 'Projekt megosztása',
|
||||||
move: 'Áthelyezés',
|
move: 'Áthelyezés',
|
||||||
moveCard_title: 'Kártya áthelyezése',
|
moveCard_title: 'Kártya áthelyezése',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Eltávolítás',
|
remove: 'Eltávolítás',
|
||||||
removeAssignee: 'Felelős eltávolítása',
|
removeAssignee: 'Felelős eltávolítása',
|
||||||
removeColor: 'Szín eltávolítása',
|
removeColor: 'Szín eltávolítása',
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Pindahkan Kartu',
|
moveCard_title: 'Pindahkan Kartu',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Nama',
|
name: 'Nama',
|
||||||
newEmail: 'E-mail baru',
|
newEmail: 'E-mail baru',
|
||||||
@@ -412,6 +413,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Pindah',
|
move: 'Pindah',
|
||||||
moveCard_title: 'Pindahkan Kartu',
|
moveCard_title: 'Pindahkan Kartu',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Hapus',
|
remove: 'Hapus',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -224,6 +224,7 @@ export default {
|
|||||||
moreActions: 'Altre azioni',
|
moreActions: 'Altre azioni',
|
||||||
moreActions_title: 'Altre azioni',
|
moreActions_title: 'Altre azioni',
|
||||||
moveCard_title: 'Sposta scheda',
|
moveCard_title: 'Sposta scheda',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Personali',
|
myOwn_title: 'Personali',
|
||||||
name: 'Nome',
|
name: 'Nome',
|
||||||
newEmail: 'Nuova e-mail',
|
newEmail: 'Nuova e-mail',
|
||||||
@@ -436,6 +437,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Rendi progetto condiviso',
|
makeProjectShared_title: 'Rendi progetto condiviso',
|
||||||
move: 'Muovi',
|
move: 'Muovi',
|
||||||
moveCard_title: 'Muovi scheda',
|
moveCard_title: 'Muovi scheda',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Rimuovi',
|
remove: 'Rimuovi',
|
||||||
removeAssignee: 'Rimuovi assegnatario',
|
removeAssignee: 'Rimuovi assegnatario',
|
||||||
removeColor: 'Remove colore',
|
removeColor: 'Remove colore',
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'カードを移動',
|
moveCard_title: 'カードを移動',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: '名前',
|
name: '名前',
|
||||||
newEmail: '新しいEメール',
|
newEmail: '新しいEメール',
|
||||||
@@ -412,6 +413,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: '移動',
|
move: '移動',
|
||||||
moveCard_title: 'カードを移動',
|
moveCard_title: 'カードを移動',
|
||||||
|
moveList_title: null,
|
||||||
remove: '削除',
|
remove: '削除',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -205,6 +205,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: '카드 이동',
|
moveCard_title: '카드 이동',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: '이름',
|
name: '이름',
|
||||||
newEmail: '새 이메일',
|
newEmail: '새 이메일',
|
||||||
@@ -411,6 +412,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: '이동',
|
move: '이동',
|
||||||
moveCard_title: '카드 이동',
|
moveCard_title: '카드 이동',
|
||||||
|
moveList_title: null,
|
||||||
remove: '제거',
|
remove: '제거',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: '색상 제거',
|
removeColor: '색상 제거',
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Kaart verplaatsen',
|
moveCard_title: 'Kaart verplaatsen',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Naam',
|
name: 'Naam',
|
||||||
newEmail: 'Nieuwe e-mail',
|
newEmail: 'Nieuwe e-mail',
|
||||||
@@ -413,6 +414,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Verplaatsen',
|
move: 'Verplaatsen',
|
||||||
moveCard_title: 'Kaart verplaatsen',
|
moveCard_title: 'Kaart verplaatsen',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Verwijderen',
|
remove: 'Verwijderen',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -214,6 +214,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Przenoszenie Karty',
|
moveCard_title: 'Przenoszenie Karty',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Moje',
|
myOwn_title: 'Moje',
|
||||||
name: 'Nazwa',
|
name: 'Nazwa',
|
||||||
newEmail: 'Nowy e-mail',
|
newEmail: 'Nowy e-mail',
|
||||||
@@ -423,6 +424,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Udostępnij Projekt',
|
makeProjectShared_title: 'Udostępnij Projekt',
|
||||||
move: 'Przenieś',
|
move: 'Przenieś',
|
||||||
moveCard_title: 'Przenieś Kartę',
|
moveCard_title: 'Przenieś Kartę',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Usuń',
|
remove: 'Usuń',
|
||||||
removeAssignee: 'Usuń osobę przypisaną',
|
removeAssignee: 'Usuń osobę przypisaną',
|
||||||
removeColor: 'Usuń kolor',
|
removeColor: 'Usuń kolor',
|
||||||
|
|||||||
@@ -224,6 +224,7 @@ export default {
|
|||||||
moreActions: 'Mais ações',
|
moreActions: 'Mais ações',
|
||||||
moreActions_title: 'Mais Ações',
|
moreActions_title: 'Mais Ações',
|
||||||
moveCard_title: 'Mover Cartão',
|
moveCard_title: 'Mover Cartão',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Meus',
|
myOwn_title: 'Meus',
|
||||||
name: 'Nome',
|
name: 'Nome',
|
||||||
newEmail: 'Novo e-mail',
|
newEmail: 'Novo e-mail',
|
||||||
@@ -435,6 +436,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Tornar Projeto Compartilhado',
|
makeProjectShared_title: 'Tornar Projeto Compartilhado',
|
||||||
move: 'Mover',
|
move: 'Mover',
|
||||||
moveCard_title: 'Mover Cartão',
|
moveCard_title: 'Mover Cartão',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Remover',
|
remove: 'Remover',
|
||||||
removeAssignee: 'Remover responsável',
|
removeAssignee: 'Remover responsável',
|
||||||
removeColor: 'Remover cor',
|
removeColor: 'Remover cor',
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Mover Cartão',
|
moveCard_title: 'Mover Cartão',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Nome',
|
name: 'Nome',
|
||||||
newEmail: 'Novo e-mail',
|
newEmail: 'Novo e-mail',
|
||||||
@@ -414,6 +415,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Mover',
|
move: 'Mover',
|
||||||
moveCard_title: 'Mover Cartão',
|
moveCard_title: 'Mover Cartão',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Remover',
|
remove: 'Remover',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Mutați cardul',
|
moveCard_title: 'Mutați cardul',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Nume',
|
name: 'Nume',
|
||||||
newEmail: 'Email nou',
|
newEmail: 'Email nou',
|
||||||
@@ -413,6 +414,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Mutați',
|
move: 'Mutați',
|
||||||
moveCard_title: 'Mutați cardul',
|
moveCard_title: 'Mutați cardul',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Eliminați',
|
remove: 'Eliminați',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -221,6 +221,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Перемещение карточки',
|
moveCard_title: 'Перемещение карточки',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Мой собственный',
|
myOwn_title: 'Мой собственный',
|
||||||
name: 'Имя',
|
name: 'Имя',
|
||||||
newEmail: 'Новый e-mail',
|
newEmail: 'Новый e-mail',
|
||||||
@@ -427,6 +428,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Сделать проект общим',
|
makeProjectShared_title: 'Сделать проект общим',
|
||||||
move: 'Переместить',
|
move: 'Переместить',
|
||||||
moveCard_title: 'Переместить карточку',
|
moveCard_title: 'Переместить карточку',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Убрать',
|
remove: 'Убрать',
|
||||||
removeAssignee: 'Удалить исполнителя',
|
removeAssignee: 'Удалить исполнителя',
|
||||||
removeColor: 'Удалить цвет',
|
removeColor: 'Удалить цвет',
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Presunúť kartu',
|
moveCard_title: 'Presunúť kartu',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Meno',
|
name: 'Meno',
|
||||||
newEmail: 'Nový e-mail',
|
newEmail: 'Nový e-mail',
|
||||||
@@ -412,6 +413,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Presunúť',
|
move: 'Presunúť',
|
||||||
moveCard_title: 'Presunúť kartu',
|
moveCard_title: 'Presunúť kartu',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Odstrániť',
|
remove: 'Odstrániť',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -207,6 +207,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Премести картицу',
|
moveCard_title: 'Премести картицу',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Име',
|
name: 'Име',
|
||||||
newEmail: 'Нова е-пошта',
|
newEmail: 'Нова е-пошта',
|
||||||
@@ -412,6 +413,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Премести',
|
move: 'Премести',
|
||||||
moveCard_title: 'Премести картицу',
|
moveCard_title: 'Премести картицу',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Уклони',
|
remove: 'Уклони',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Premesti karticu',
|
moveCard_title: 'Premesti karticu',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Ime',
|
name: 'Ime',
|
||||||
newEmail: 'Nova e-pošta',
|
newEmail: 'Nova e-pošta',
|
||||||
@@ -409,6 +410,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Premesti',
|
move: 'Premesti',
|
||||||
moveCard_title: 'Premesti karticu',
|
moveCard_title: 'Premesti karticu',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Ukloni',
|
remove: 'Ukloni',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -206,6 +206,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Flytta kort',
|
moveCard_title: 'Flytta kort',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Namn',
|
name: 'Namn',
|
||||||
newEmail: 'Ny e-mail',
|
newEmail: 'Ny e-mail',
|
||||||
@@ -411,6 +412,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Flytta',
|
move: 'Flytta',
|
||||||
moveCard_title: 'Flytta kort',
|
moveCard_title: 'Flytta kort',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Ta bort',
|
remove: 'Ta bort',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: 'Kartı Taşı',
|
moveCard_title: 'Kartı Taşı',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'isim',
|
name: 'isim',
|
||||||
newEmail: 'Yeni e-posta adresi',
|
newEmail: 'Yeni e-posta adresi',
|
||||||
@@ -409,6 +410,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: 'Taşı',
|
move: 'Taşı',
|
||||||
moveCard_title: 'Kartı Taşı',
|
moveCard_title: 'Kartı Taşı',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Sil',
|
remove: 'Sil',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -219,6 +219,7 @@ export default {
|
|||||||
moreActions: 'Більше дій',
|
moreActions: 'Більше дій',
|
||||||
moreActions_title: 'Більше дій',
|
moreActions_title: 'Більше дій',
|
||||||
moveCard_title: 'Перемістити Картку',
|
moveCard_title: 'Перемістити Картку',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: 'Моя власна',
|
myOwn_title: 'Моя власна',
|
||||||
name: 'Назва',
|
name: 'Назва',
|
||||||
newEmail: 'Нова електронна пошта',
|
newEmail: 'Нова електронна пошта',
|
||||||
@@ -429,6 +430,7 @@ export default {
|
|||||||
makeProjectShared_title: 'Зробити Проект спільним',
|
makeProjectShared_title: 'Зробити Проект спільним',
|
||||||
move: 'Перемістити',
|
move: 'Перемістити',
|
||||||
moveCard_title: 'Перемістити Картку',
|
moveCard_title: 'Перемістити Картку',
|
||||||
|
moveList_title: null,
|
||||||
remove: 'Видалити',
|
remove: 'Видалити',
|
||||||
removeAssignee: 'Видалити правонаступника',
|
removeAssignee: 'Видалити правонаступника',
|
||||||
removeColor: 'Видалити колір',
|
removeColor: 'Видалити колір',
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: "Kartani Ko'chirish",
|
moveCard_title: "Kartani Ko'chirish",
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: 'Ism',
|
name: 'Ism',
|
||||||
newEmail: 'Yangi e-mail',
|
newEmail: 'Yangi e-mail',
|
||||||
@@ -408,6 +409,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: "Ko'chirish",
|
move: "Ko'chirish",
|
||||||
moveCard_title: "Kartani Ko'chirish",
|
moveCard_title: "Kartani Ko'chirish",
|
||||||
|
moveList_title: null,
|
||||||
remove: "O'chirish",
|
remove: "O'chirish",
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: '移动卡片',
|
moveCard_title: '移动卡片',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: '我的',
|
myOwn_title: '我的',
|
||||||
name: '姓名',
|
name: '姓名',
|
||||||
newEmail: '新邮箱',
|
newEmail: '新邮箱',
|
||||||
@@ -410,6 +411,7 @@ export default {
|
|||||||
makeProjectShared_title: '将项目设为共享',
|
makeProjectShared_title: '将项目设为共享',
|
||||||
move: '移动',
|
move: '移动',
|
||||||
moveCard_title: '移动卡片',
|
moveCard_title: '移动卡片',
|
||||||
|
moveList_title: null,
|
||||||
remove: '删除',
|
remove: '删除',
|
||||||
removeAssignee: '移除负责人',
|
removeAssignee: '移除负责人',
|
||||||
removeColor: '移除颜色',
|
removeColor: '移除颜色',
|
||||||
|
|||||||
@@ -201,6 +201,7 @@ export default {
|
|||||||
moreActions: null,
|
moreActions: null,
|
||||||
moreActions_title: null,
|
moreActions_title: null,
|
||||||
moveCard_title: '移動卡片',
|
moveCard_title: '移動卡片',
|
||||||
|
moveList_title: null,
|
||||||
myOwn_title: null,
|
myOwn_title: null,
|
||||||
name: '姓名',
|
name: '姓名',
|
||||||
newEmail: '新郵箱',
|
newEmail: '新郵箱',
|
||||||
@@ -405,6 +406,7 @@ export default {
|
|||||||
makeProjectShared_title: null,
|
makeProjectShared_title: null,
|
||||||
move: '移動',
|
move: '移動',
|
||||||
moveCard_title: '移動卡片',
|
moveCard_title: '移動卡片',
|
||||||
|
moveList_title: null,
|
||||||
remove: '刪除',
|
remove: '刪除',
|
||||||
removeAssignee: null,
|
removeAssignee: null,
|
||||||
removeColor: null,
|
removeColor: null,
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
case ActionTypes.CARD_UPDATE_HANDLE:
|
case ActionTypes.CARD_UPDATE_HANDLE:
|
||||||
if (payload.attachments) {
|
if (payload.attachments) {
|
||||||
payload.attachments.forEach((attachment) => {
|
payload.attachments.forEach((attachment) => {
|
||||||
|
|||||||
@@ -88,6 +88,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
if (payload.cards) {
|
if (payload.cards) {
|
||||||
payload.cards.forEach((card) => {
|
payload.cards.forEach((card) => {
|
||||||
Card.upsert(card);
|
Card.upsert(card);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
case ActionTypes.CARD_UPDATE_HANDLE:
|
case ActionTypes.CARD_UPDATE_HANDLE:
|
||||||
if (payload.customFields) {
|
if (payload.customFields) {
|
||||||
payload.customFields.forEach((customField) => {
|
payload.customFields.forEach((customField) => {
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
case ActionTypes.CARD_UPDATE_HANDLE:
|
case ActionTypes.CARD_UPDATE_HANDLE:
|
||||||
if (payload.customFieldGroups) {
|
if (payload.customFieldGroups) {
|
||||||
payload.customFieldGroups.forEach((customFieldGroup) => {
|
payload.customFieldGroups.forEach((customFieldGroup) => {
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
case ActionTypes.CARD_UPDATE_HANDLE:
|
case ActionTypes.CARD_UPDATE_HANDLE:
|
||||||
if (payload.customFieldValues) {
|
if (payload.customFieldValues) {
|
||||||
payload.customFieldValues.forEach((customFieldValue) => {
|
payload.customFieldValues.forEach((customFieldValue) => {
|
||||||
|
|||||||
@@ -135,6 +135,9 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.LIST_UPDATE: {
|
case ActionTypes.LIST_UPDATE: {
|
||||||
const listModel = List.withId(payload.id);
|
const listModel = List.withId(payload.id);
|
||||||
|
|
||||||
|
if (payload.data.boardId && payload.data.boardId !== listModel.boardId) {
|
||||||
|
listModel.deleteWithRelated();
|
||||||
|
} else {
|
||||||
let isClosed;
|
let isClosed;
|
||||||
if (payload.data.type) {
|
if (payload.data.type) {
|
||||||
const changedTypeState = getChangedTypeState(listModel, payload.data);
|
const changedTypeState = getChangedTypeState(listModel, payload.data);
|
||||||
@@ -159,13 +162,20 @@ export default class extends BaseModel {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// TODO: refactor
|
||||||
case ActionTypes.LIST_UPDATE_HANDLE: {
|
case ActionTypes.LIST_UPDATE_HANDLE: {
|
||||||
const listModel = List.withId(payload.list.id);
|
const listModel = List.withId(payload.list.id);
|
||||||
|
|
||||||
if (listModel) {
|
if (listModel) {
|
||||||
|
if (payload.list.boardId === null || payload.isFetched) {
|
||||||
|
listModel.deleteWithRelated();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (payload.list.boardId !== null) {
|
||||||
const changedTypeState = getChangedTypeState(listModel, payload.list);
|
const changedTypeState = getChangedTypeState(listModel, payload.list);
|
||||||
|
|
||||||
let isClosed;
|
let isClosed;
|
||||||
@@ -188,7 +198,8 @@ export default class extends BaseModel {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
} else if (payload.list.boardId !== null) {
|
||||||
List.upsert(prepareList(payload.list));
|
List.upsert(prepareList(payload.list));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
case ActionTypes.CARD_UPDATE_HANDLE:
|
case ActionTypes.CARD_UPDATE_HANDLE:
|
||||||
if (payload.tasks) {
|
if (payload.tasks) {
|
||||||
payload.tasks.forEach((task) => {
|
payload.tasks.forEach((task) => {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
case ActionTypes.CARD_UPDATE_HANDLE:
|
case ActionTypes.CARD_UPDATE_HANDLE:
|
||||||
if (payload.taskLists) {
|
if (payload.taskLists) {
|
||||||
payload.taskLists.forEach((taskList) => {
|
payload.taskLists.forEach((taskList) => {
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ export default class extends BaseModel {
|
|||||||
case ActionTypes.LOCATION_CHANGE_HANDLE:
|
case ActionTypes.LOCATION_CHANGE_HANDLE:
|
||||||
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
case ActionTypes.PROJECT_UPDATE_HANDLE:
|
||||||
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
|
||||||
|
case ActionTypes.LIST_UPDATE_HANDLE:
|
||||||
case ActionTypes.CARD_UPDATE_HANDLE:
|
case ActionTypes.CARD_UPDATE_HANDLE:
|
||||||
if (payload.users) {
|
if (payload.users) {
|
||||||
payload.users.forEach((user) => {
|
payload.users.forEach((user) => {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
import { call, put, select } from 'redux-saga/effects';
|
import { call, put, select } from 'redux-saga/effects';
|
||||||
import toast from 'react-hot-toast';
|
import toast from 'react-hot-toast';
|
||||||
|
|
||||||
|
import { goToBoard } from './router';
|
||||||
import request from '../request';
|
import request from '../request';
|
||||||
import selectors from '../../../selectors';
|
import selectors from '../../../selectors';
|
||||||
import actions from '../../../actions';
|
import actions from '../../../actions';
|
||||||
@@ -65,7 +66,71 @@ export function* updateList(id, data) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function* handleListUpdate(list) {
|
export function* handleListUpdate(list) {
|
||||||
yield put(actions.handleListUpdate(list));
|
const currentCard = yield select(selectors.selectCurrentCard);
|
||||||
|
|
||||||
|
let fetch = false;
|
||||||
|
if (list.boardId) {
|
||||||
|
const isAvailableForCurrentUser = yield select(
|
||||||
|
selectors.selectIsListWithIdAvailableForCurrentUser,
|
||||||
|
list.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
fetch = !isAvailableForCurrentUser;
|
||||||
|
}
|
||||||
|
|
||||||
|
let users;
|
||||||
|
let cards;
|
||||||
|
let cardMemberships;
|
||||||
|
let cardLabels;
|
||||||
|
let taskLists;
|
||||||
|
let tasks;
|
||||||
|
let attachments;
|
||||||
|
let customFieldGroups;
|
||||||
|
let customFields;
|
||||||
|
let customFieldValues;
|
||||||
|
|
||||||
|
if (fetch) {
|
||||||
|
try {
|
||||||
|
({
|
||||||
|
item: list, // eslint-disable-line no-param-reassign
|
||||||
|
included: {
|
||||||
|
users,
|
||||||
|
cards,
|
||||||
|
cardMemberships,
|
||||||
|
cardLabels,
|
||||||
|
taskLists,
|
||||||
|
tasks,
|
||||||
|
attachments,
|
||||||
|
customFieldGroups,
|
||||||
|
customFields,
|
||||||
|
customFieldValues,
|
||||||
|
},
|
||||||
|
} = yield call(request, api.getList, list.id));
|
||||||
|
} catch {
|
||||||
|
fetch = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield put(
|
||||||
|
actions.handleListUpdate(
|
||||||
|
list,
|
||||||
|
fetch,
|
||||||
|
users,
|
||||||
|
cards,
|
||||||
|
cardMemberships,
|
||||||
|
cardLabels,
|
||||||
|
taskLists,
|
||||||
|
tasks,
|
||||||
|
attachments,
|
||||||
|
customFieldGroups,
|
||||||
|
customFields,
|
||||||
|
customFieldValues,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (list.boardId === null && currentCard && list.id === currentCard.listId) {
|
||||||
|
yield call(goToBoard, currentCard.boardId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* moveList(id, index) {
|
export function* moveList(id, index) {
|
||||||
@@ -77,6 +142,19 @@ export function* moveList(id, index) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function* transferList(id, boardId) {
|
||||||
|
const currentCard = yield select(selectors.selectCurrentCard);
|
||||||
|
|
||||||
|
// TODO: hack?
|
||||||
|
if (currentCard && id === currentCard.listId) {
|
||||||
|
yield call(goToBoard, currentCard.boardId);
|
||||||
|
}
|
||||||
|
|
||||||
|
yield call(updateList, id, {
|
||||||
|
boardId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function* sortList(id, data) {
|
export function* sortList(id, data) {
|
||||||
yield put(actions.sortList(id, data));
|
yield put(actions.sortList(id, data));
|
||||||
|
|
||||||
@@ -190,6 +268,7 @@ export default {
|
|||||||
updateList,
|
updateList,
|
||||||
handleListUpdate,
|
handleListUpdate,
|
||||||
moveList,
|
moveList,
|
||||||
|
transferList,
|
||||||
sortList,
|
sortList,
|
||||||
moveListCardsToArchiveList,
|
moveListCardsToArchiveList,
|
||||||
clearTrashListInCurrentBoard,
|
clearTrashListInCurrentBoard,
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ export default function* listsWatchers() {
|
|||||||
takeEvery(EntryActionTypes.LIST_SORT, ({ payload: { id, data } }) =>
|
takeEvery(EntryActionTypes.LIST_SORT, ({ payload: { id, data } }) =>
|
||||||
services.sortList(id, data),
|
services.sortList(id, data),
|
||||||
),
|
),
|
||||||
|
takeEvery(EntryActionTypes.LIST_TRANSFER, ({ payload: { id, boardId, index } }) =>
|
||||||
|
services.transferList(id, boardId, index),
|
||||||
|
),
|
||||||
takeEvery(EntryActionTypes.LIST_CARDS_TO_ARCHIVE_LIST_MOVE, ({ payload: { id } }) =>
|
takeEvery(EntryActionTypes.LIST_CARDS_TO_ARCHIVE_LIST_MOVE, ({ payload: { id } }) =>
|
||||||
services.moveListCardsToArchiveList(id),
|
services.moveListCardsToArchiveList(id),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { createSelector } from 'redux-orm';
|
|||||||
|
|
||||||
import orm from '../orm';
|
import orm from '../orm';
|
||||||
import { selectPath } from './router';
|
import { selectPath } from './router';
|
||||||
|
import { selectCurrentUserId } from './users';
|
||||||
import { isLocalId } from '../utils/local-id';
|
import { isLocalId } from '../utils/local-id';
|
||||||
import { BoardContexts, ListTypes } from '../constants/Enums';
|
import { BoardContexts, ListTypes } from '../constants/Enums';
|
||||||
|
|
||||||
@@ -64,6 +65,22 @@ export const makeSelectFilteredCardIdsByListId = () =>
|
|||||||
|
|
||||||
export const selectFilteredCardIdsByListId = makeSelectFilteredCardIdsByListId();
|
export const selectFilteredCardIdsByListId = makeSelectFilteredCardIdsByListId();
|
||||||
|
|
||||||
|
export const selectIsListWithIdAvailableForCurrentUser = createSelector(
|
||||||
|
orm,
|
||||||
|
(_, id) => id,
|
||||||
|
(state) => selectCurrentUserId(state),
|
||||||
|
({ List, User }, id, currentUserId) => {
|
||||||
|
const listModel = List.withId(id);
|
||||||
|
|
||||||
|
if (!listModel) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentUserModel = User.withId(currentUserId);
|
||||||
|
return listModel.isAvailableForUser(currentUserModel);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const selectCurrentListId = createSelector(
|
export const selectCurrentListId = createSelector(
|
||||||
orm,
|
orm,
|
||||||
(state) => selectPath(state).boardId,
|
(state) => selectPath(state).boardId,
|
||||||
@@ -154,6 +171,7 @@ export default {
|
|||||||
selectCardIdsByListId,
|
selectCardIdsByListId,
|
||||||
makeSelectFilteredCardIdsByListId,
|
makeSelectFilteredCardIdsByListId,
|
||||||
selectFilteredCardIdsByListId,
|
selectFilteredCardIdsByListId,
|
||||||
|
selectIsListWithIdAvailableForCurrentUser,
|
||||||
selectCurrentListId,
|
selectCurrentListId,
|
||||||
selectCurrentList,
|
selectCurrentList,
|
||||||
selectFirstFiniteListId,
|
selectFirstFiniteListId,
|
||||||
|
|||||||
@@ -197,6 +197,35 @@ export const selectFavoriteProjectIdsForCurrentUser = createSelector(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectProjectsToBoardsWithEditorRightsForCurrentUser = createSelector(
|
||||||
|
orm,
|
||||||
|
(state) => selectCurrentUserId(state),
|
||||||
|
({ User }, id) => {
|
||||||
|
if (!id) {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
const userModel = User.withId(id);
|
||||||
|
|
||||||
|
if (!userModel) {
|
||||||
|
return userModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
return userModel.getMembershipProjectsModelArray().map((projectModel) => ({
|
||||||
|
...projectModel.ref,
|
||||||
|
boards: projectModel.getBoardsModelArrayForUserWithId(id).flatMap((boardModel) => {
|
||||||
|
const boardMembersipModel = boardModel.getMembershipModelByUserId(id);
|
||||||
|
|
||||||
|
if (boardMembersipModel.role !== BoardMembershipRoles.EDITOR) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return boardModel.ref;
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
export const selectProjectsToListsWithEditorRightsForCurrentUser = createSelector(
|
export const selectProjectsToListsWithEditorRightsForCurrentUser = createSelector(
|
||||||
orm,
|
orm,
|
||||||
(state) => selectCurrentUserId(state),
|
(state) => selectCurrentUserId(state),
|
||||||
@@ -334,6 +363,7 @@ export default {
|
|||||||
selectFilteredProjectIdsForCurrentUser,
|
selectFilteredProjectIdsForCurrentUser,
|
||||||
selectFilteredProjctIdsByGroupForCurrentUser,
|
selectFilteredProjctIdsByGroupForCurrentUser,
|
||||||
selectFavoriteProjectIdsForCurrentUser,
|
selectFavoriteProjectIdsForCurrentUser,
|
||||||
|
selectProjectsToBoardsWithEditorRightsForCurrentUser,
|
||||||
selectProjectsToListsWithEditorRightsForCurrentUser,
|
selectProjectsToListsWithEditorRightsForCurrentUser,
|
||||||
selectBoardIdsForCurrentUser,
|
selectBoardIdsForCurrentUser,
|
||||||
selectNotificationIdsForCurrentUser,
|
selectNotificationIdsForCurrentUser,
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ const Errors = {
|
|||||||
LIST_NOT_FOUND: {
|
LIST_NOT_FOUND: {
|
||||||
listNotFound: 'List not found',
|
listNotFound: 'List not found',
|
||||||
},
|
},
|
||||||
|
BOARD_NOT_FOUND: {
|
||||||
|
boardNotFound: 'Board not found',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@@ -20,6 +23,7 @@ module.exports = {
|
|||||||
...idInput,
|
...idInput,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
|
boardId: idInput,
|
||||||
type: {
|
type: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
isIn: List.FINITE_TYPES,
|
isIn: List.FINITE_TYPES,
|
||||||
@@ -47,6 +51,9 @@ module.exports = {
|
|||||||
listNotFound: {
|
listNotFound: {
|
||||||
responseType: 'notFound',
|
responseType: 'notFound',
|
||||||
},
|
},
|
||||||
|
boardNotFound: {
|
||||||
|
responseType: 'notFound',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
async fn(inputs) {
|
async fn(inputs) {
|
||||||
@@ -59,7 +66,7 @@ module.exports = {
|
|||||||
let { list } = pathToProject;
|
let { list } = pathToProject;
|
||||||
const { board, project } = pathToProject;
|
const { board, project } = pathToProject;
|
||||||
|
|
||||||
const boardMembership = await BoardMembership.qm.getOneByBoardIdAndUserId(
|
let boardMembership = await BoardMembership.qm.getOneByBoardIdAndUserId(
|
||||||
board.id,
|
board.id,
|
||||||
currentUser.id,
|
currentUser.id,
|
||||||
);
|
);
|
||||||
@@ -76,13 +83,39 @@ module.exports = {
|
|||||||
throw Errors.NOT_ENOUGH_RIGHTS;
|
throw Errors.NOT_ENOUGH_RIGHTS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nextProject;
|
||||||
|
let nextBoard;
|
||||||
|
|
||||||
|
if (!_.isUndefined(inputs.boardId)) {
|
||||||
|
({ board: nextBoard, project: nextProject } = await sails.helpers.boards
|
||||||
|
.getPathToProjectById(inputs.boardId)
|
||||||
|
.intercept('pathNotFound', () => Errors.BOARD_NOT_FOUND));
|
||||||
|
|
||||||
|
boardMembership = await BoardMembership.qm.getOneByBoardIdAndUserId(
|
||||||
|
nextBoard.id,
|
||||||
|
currentUser.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!boardMembership) {
|
||||||
|
throw Errors.BOARD_NOT_FOUND; // Forbidden
|
||||||
|
}
|
||||||
|
|
||||||
|
if (boardMembership.role !== BoardMembership.Roles.EDITOR) {
|
||||||
|
throw Errors.NOT_ENOUGH_RIGHTS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const values = _.pick(inputs, ['type', 'position', 'name', 'color']);
|
const values = _.pick(inputs, ['type', 'position', 'name', 'color']);
|
||||||
|
|
||||||
list = await sails.helpers.lists.updateOne.with({
|
list = await sails.helpers.lists.updateOne.with({
|
||||||
values,
|
|
||||||
project,
|
project,
|
||||||
board,
|
board,
|
||||||
record: list,
|
record: list,
|
||||||
|
values: {
|
||||||
|
...values,
|
||||||
|
project: nextProject,
|
||||||
|
board: nextBoard,
|
||||||
|
},
|
||||||
actorUser: currentUser,
|
actorUser: currentUser,
|
||||||
request: this.req,
|
request: this.req,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -0,0 +1,279 @@
|
|||||||
|
/*!
|
||||||
|
* Copyright (c) 2024 PLANKA Software GmbH
|
||||||
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
const { POSITION_GAP } = require('../../../constants');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
inputs: {
|
||||||
|
idOrIds: {
|
||||||
|
type: 'json',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
boardId: {
|
||||||
|
type: 'ref',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
withBaseCustomFieldGroups: {
|
||||||
|
type: 'boolean',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
async fn(inputs) {
|
||||||
|
const cardIds = _.isString(inputs.idOrIds) ? [inputs.idOrIds] : inputs.idOrIds;
|
||||||
|
|
||||||
|
const boardCustomFieldGroups = await CustomFieldGroup.qm.getByBoardId(inputs.boardId);
|
||||||
|
const boardCustomFieldGroupIds = sails.helpers.utils.mapRecords(boardCustomFieldGroups);
|
||||||
|
|
||||||
|
const boardCustomFields =
|
||||||
|
await CustomField.qm.getByCustomFieldGroupIds(boardCustomFieldGroupIds);
|
||||||
|
|
||||||
|
const cardsCustomFieldGroups = await CustomFieldGroup.qm.getByCardIds(cardIds);
|
||||||
|
const customFieldGroupsByCardId = _.groupBy(cardsCustomFieldGroups, 'cardId');
|
||||||
|
|
||||||
|
let basedBoardCustomFieldGroups;
|
||||||
|
let basedCardCustomFieldGroups;
|
||||||
|
let baseCustomFieldGroupById;
|
||||||
|
let customFieldsByBaseCustomFieldGroupId;
|
||||||
|
|
||||||
|
if (inputs.withBaseCustomFieldGroups) {
|
||||||
|
basedBoardCustomFieldGroups = boardCustomFieldGroups.filter(
|
||||||
|
({ baseCustomFieldGroupId }) => baseCustomFieldGroupId,
|
||||||
|
);
|
||||||
|
|
||||||
|
basedCardCustomFieldGroups = cardsCustomFieldGroups.filter(
|
||||||
|
({ baseCustomFieldGroupId }) => baseCustomFieldGroupId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const basedCustomFieldGroups = [
|
||||||
|
...basedBoardCustomFieldGroups,
|
||||||
|
...basedCardCustomFieldGroups,
|
||||||
|
];
|
||||||
|
|
||||||
|
const baseCustomFieldGroupIds = sails.helpers.utils.mapRecords(
|
||||||
|
basedCustomFieldGroups,
|
||||||
|
'baseCustomFieldGroupId',
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
|
||||||
|
const baseCustomFieldGroups = await BaseCustomFieldGroup.qm.getByIds(baseCustomFieldGroupIds);
|
||||||
|
baseCustomFieldGroupById = _.keyBy(baseCustomFieldGroups, 'id');
|
||||||
|
|
||||||
|
const baseCustomFields = await CustomField.qm.getByBaseCustomFieldGroupIds(
|
||||||
|
Object.keys(baseCustomFieldGroupById),
|
||||||
|
);
|
||||||
|
|
||||||
|
customFieldsByBaseCustomFieldGroupId = _.groupBy(baseCustomFields, 'baseCustomFieldGroupId');
|
||||||
|
}
|
||||||
|
|
||||||
|
let idsTotal = (boardCustomFieldGroups.length + boardCustomFields.length) * cardIds.length;
|
||||||
|
|
||||||
|
if (inputs.withBaseCustomFieldGroups) {
|
||||||
|
idsTotal += basedBoardCustomFieldGroups.reduce((result, customFieldGroup) => {
|
||||||
|
const customFieldsItem =
|
||||||
|
customFieldsByBaseCustomFieldGroupId[customFieldGroup.baseCustomFieldGroupId];
|
||||||
|
|
||||||
|
return result + (customFieldsItem ? customFieldsItem.length : 0) * cardIds.length;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
idsTotal += basedCardCustomFieldGroups.reduce((result, customFieldGroup) => {
|
||||||
|
const customFieldsItem =
|
||||||
|
customFieldsByBaseCustomFieldGroupId[customFieldGroup.baseCustomFieldGroupId];
|
||||||
|
|
||||||
|
return result + (customFieldsItem ? customFieldsItem.length : 0);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ids = await sails.helpers.utils.generateIds(idsTotal);
|
||||||
|
|
||||||
|
const nextCustomFieldGroupIdByCustomFieldGroupIdByCardId = {};
|
||||||
|
const nextCustomFieldGroupsValues = (
|
||||||
|
await Promise.all(
|
||||||
|
cardIds.map(async (cardId) => {
|
||||||
|
const customFieldGroupIdByCustomFieldGroupId = {};
|
||||||
|
const customFieldGroupsValues = boardCustomFieldGroups.map((customFieldGroup, index) => {
|
||||||
|
const id = ids.shift();
|
||||||
|
customFieldGroupIdByCustomFieldGroupId[customFieldGroup.id] = id;
|
||||||
|
|
||||||
|
const values = {
|
||||||
|
..._.pick(customFieldGroup, ['baseCustomFieldGroupId', 'name']),
|
||||||
|
id,
|
||||||
|
cardId,
|
||||||
|
position: POSITION_GAP * (index + 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (inputs.withBaseCustomFieldGroups && customFieldGroup.baseCustomFieldGroupId) {
|
||||||
|
values.baseCustomFieldGroupId = null;
|
||||||
|
|
||||||
|
if (!customFieldGroup.name) {
|
||||||
|
values.name =
|
||||||
|
baseCustomFieldGroupById[customFieldGroup.baseCustomFieldGroupId].name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return values;
|
||||||
|
});
|
||||||
|
|
||||||
|
nextCustomFieldGroupIdByCustomFieldGroupIdByCardId[cardId] =
|
||||||
|
customFieldGroupIdByCustomFieldGroupId;
|
||||||
|
|
||||||
|
if (customFieldGroupsValues.length > 0) {
|
||||||
|
const cardCustomFieldGroups = customFieldGroupsByCardId[cardId];
|
||||||
|
|
||||||
|
if (cardCustomFieldGroups && cardCustomFieldGroups.length > 0) {
|
||||||
|
const { position } = customFieldGroupsValues[customFieldGroupsValues.length - 1];
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
cardCustomFieldGroups.map((customFieldGroup) =>
|
||||||
|
CustomFieldGroup.qm.updateOne(customFieldGroup.id, {
|
||||||
|
position: customFieldGroup.position + position,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return customFieldGroupsValues;
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
).flat();
|
||||||
|
|
||||||
|
await CustomFieldGroup.qm.create(nextCustomFieldGroupsValues);
|
||||||
|
|
||||||
|
if (inputs.withBaseCustomFieldGroups) {
|
||||||
|
await CustomFieldGroup.qm.update(
|
||||||
|
{
|
||||||
|
cardId: cardIds,
|
||||||
|
baseCustomFieldGroupId: {
|
||||||
|
'!=': null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
baseCustomFieldGroupId: null,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const unnamedCustomFieldGroups = basedCardCustomFieldGroups.filter(({ name }) => !name);
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
unnamedCustomFieldGroups.map((customFieldGroup) =>
|
||||||
|
CustomFieldGroup.qm.updateOne(customFieldGroup.id, {
|
||||||
|
name: baseCustomFieldGroupById[customFieldGroup.baseCustomFieldGroupId].name,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextCustomFieldIdByCustomFieldIdByCardId = {};
|
||||||
|
const nextCustomFieldsValues = cardIds.flatMap((cardId) => {
|
||||||
|
const customFieldIdByCustomFieldId = {};
|
||||||
|
const customFieldsValues = boardCustomFields.map((customField) => {
|
||||||
|
const id = ids.shift();
|
||||||
|
customFieldIdByCustomFieldId[customField.id] = id;
|
||||||
|
|
||||||
|
return {
|
||||||
|
..._.pick(customField, ['name', 'showOnFrontOfCard', 'position']),
|
||||||
|
id,
|
||||||
|
customFieldGroupId:
|
||||||
|
nextCustomFieldGroupIdByCustomFieldGroupIdByCardId[cardId][
|
||||||
|
customField.customFieldGroupId
|
||||||
|
],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
nextCustomFieldIdByCustomFieldIdByCardId[cardId] = customFieldIdByCustomFieldId;
|
||||||
|
return customFieldsValues;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (inputs.withBaseCustomFieldGroups) {
|
||||||
|
cardIds.forEach((cardId) => {
|
||||||
|
basedBoardCustomFieldGroups.forEach((customFieldGroup) => {
|
||||||
|
const customFieldsItem =
|
||||||
|
customFieldsByBaseCustomFieldGroupId[customFieldGroup.baseCustomFieldGroupId];
|
||||||
|
|
||||||
|
if (!customFieldsItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
customFieldsItem.forEach((customField) => {
|
||||||
|
const id = ids.shift();
|
||||||
|
|
||||||
|
nextCustomFieldIdByCustomFieldIdByCardId[cardId][
|
||||||
|
`${customFieldGroup.id}:${customField.id}`
|
||||||
|
] = id;
|
||||||
|
|
||||||
|
nextCustomFieldsValues.push({
|
||||||
|
..._.pick(customField, ['name', 'showOnFrontOfCard', 'position']),
|
||||||
|
id,
|
||||||
|
customFieldGroupId:
|
||||||
|
nextCustomFieldGroupIdByCustomFieldGroupIdByCardId[cardId][customFieldGroup.id],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
basedCardCustomFieldGroups.forEach((customFieldGroup) => {
|
||||||
|
const customFieldsItem =
|
||||||
|
customFieldsByBaseCustomFieldGroupId[customFieldGroup.baseCustomFieldGroupId];
|
||||||
|
|
||||||
|
if (!customFieldsItem) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
customFieldsItem.forEach((customField) => {
|
||||||
|
const id = ids.shift();
|
||||||
|
|
||||||
|
nextCustomFieldIdByCustomFieldIdByCardId[customFieldGroup.cardId][
|
||||||
|
`${customFieldGroup.id}:${customField.id}`
|
||||||
|
] = id;
|
||||||
|
|
||||||
|
nextCustomFieldsValues.push({
|
||||||
|
..._.pick(customField, ['name', 'showOnFrontOfCard', 'position']),
|
||||||
|
id,
|
||||||
|
customFieldGroupId: customFieldGroup.id,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await CustomField.qm.create(nextCustomFieldsValues);
|
||||||
|
|
||||||
|
const customFieldGroupIds = boardCustomFieldGroupIds;
|
||||||
|
if (inputs.withBaseCustomFieldGroups) {
|
||||||
|
customFieldGroupIds.push(...sails.helpers.utils.mapRecords(basedCardCustomFieldGroups));
|
||||||
|
}
|
||||||
|
|
||||||
|
const customFieldValues = await CustomFieldValue.qm.getByCardIds(cardIds, {
|
||||||
|
customFieldGroupIdOrIds: customFieldGroupIds,
|
||||||
|
});
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
customFieldValues.map((customFieldValue) => {
|
||||||
|
const updateValues = {
|
||||||
|
customFieldGroupId:
|
||||||
|
nextCustomFieldGroupIdByCustomFieldGroupIdByCardId[customFieldValue.cardId][
|
||||||
|
customFieldValue.customFieldGroupId
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const nextCustomFieldIdByCustomFieldId =
|
||||||
|
nextCustomFieldIdByCustomFieldIdByCardId[customFieldValue.cardId];
|
||||||
|
|
||||||
|
if (nextCustomFieldIdByCustomFieldId) {
|
||||||
|
const nextCustomFieldId =
|
||||||
|
nextCustomFieldIdByCustomFieldId[
|
||||||
|
`${customFieldValue.customFieldGroupId}:${customFieldValue.customFieldId}`
|
||||||
|
] || nextCustomFieldIdByCustomFieldId[customFieldValue.customFieldId];
|
||||||
|
|
||||||
|
if (nextCustomFieldId) {
|
||||||
|
updateValues.customFieldId = nextCustomFieldId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return CustomFieldValue.qm.updateOne(customFieldValue.id, updateValues);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -3,8 +3,6 @@
|
|||||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const { POSITION_GAP } = require('../../../constants');
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
inputs: {
|
inputs: {
|
||||||
record: {
|
record: {
|
||||||
@@ -186,194 +184,10 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const boardCustomFieldGroups = await CustomFieldGroup.qm.getByBoardId(inputs.board.id);
|
await sails.helpers.cards.detachCustomFields(
|
||||||
const boardCustomFieldGroupIds = sails.helpers.utils.mapRecords(boardCustomFieldGroups);
|
inputs.record.id,
|
||||||
|
inputs.board.id,
|
||||||
const boardCustomFields =
|
!!values.project,
|
||||||
await CustomField.qm.getByCustomFieldGroupIds(boardCustomFieldGroupIds);
|
|
||||||
|
|
||||||
const cardCustomFieldGroups = await CustomFieldGroup.qm.getByCardId(inputs.record.id);
|
|
||||||
|
|
||||||
let basedCardCustomFieldGroups;
|
|
||||||
let basedCustomFieldGroups;
|
|
||||||
let baseCustomFieldGroupById;
|
|
||||||
let customFieldsByBaseCustomFieldGroupId;
|
|
||||||
|
|
||||||
if (values.project) {
|
|
||||||
const basedBoardCustomFieldGroups = boardCustomFieldGroups.filter(
|
|
||||||
({ baseCustomFieldGroupId }) => baseCustomFieldGroupId,
|
|
||||||
);
|
|
||||||
|
|
||||||
basedCardCustomFieldGroups = cardCustomFieldGroups.filter(
|
|
||||||
({ baseCustomFieldGroupId }) => baseCustomFieldGroupId,
|
|
||||||
);
|
|
||||||
|
|
||||||
basedCustomFieldGroups = [...basedBoardCustomFieldGroups, ...basedCardCustomFieldGroups];
|
|
||||||
|
|
||||||
const baseCustomFieldGroupIds = sails.helpers.utils.mapRecords(
|
|
||||||
basedCustomFieldGroups,
|
|
||||||
'baseCustomFieldGroupId',
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
|
|
||||||
const baseCustomFieldGroups =
|
|
||||||
await BaseCustomFieldGroup.qm.getByIds(baseCustomFieldGroupIds);
|
|
||||||
|
|
||||||
baseCustomFieldGroupById = _.keyBy(baseCustomFieldGroups, 'id');
|
|
||||||
|
|
||||||
const baseCustomFields = await CustomField.qm.getByBaseCustomFieldGroupIds(
|
|
||||||
Object.keys(baseCustomFieldGroupById),
|
|
||||||
);
|
|
||||||
|
|
||||||
customFieldsByBaseCustomFieldGroupId = _.groupBy(
|
|
||||||
baseCustomFields,
|
|
||||||
'baseCustomFieldGroupId',
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let idsTotal = boardCustomFieldGroups.length + boardCustomFields.length;
|
|
||||||
|
|
||||||
if (values.project) {
|
|
||||||
idsTotal += basedCustomFieldGroups.reduce((result, customFieldGroup) => {
|
|
||||||
const customFieldsItem =
|
|
||||||
customFieldsByBaseCustomFieldGroupId[customFieldGroup.baseCustomFieldGroupId];
|
|
||||||
|
|
||||||
return result + (customFieldsItem ? customFieldsItem.length : 0);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
const ids = await sails.helpers.utils.generateIds(idsTotal);
|
|
||||||
|
|
||||||
const nextCustomFieldGroupIdByCustomFieldGroupId = {};
|
|
||||||
const nextCustomFieldGroupsValues = boardCustomFieldGroups.map(
|
|
||||||
(customFieldGroup, index) => {
|
|
||||||
const id = ids.shift();
|
|
||||||
nextCustomFieldGroupIdByCustomFieldGroupId[customFieldGroup.id] = id;
|
|
||||||
|
|
||||||
const nextValues = {
|
|
||||||
..._.pick(customFieldGroup, ['baseCustomFieldGroupId', 'name']),
|
|
||||||
id,
|
|
||||||
cardId: inputs.record.id,
|
|
||||||
position: POSITION_GAP * (index + 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
if (values.project && customFieldGroup.baseCustomFieldGroupId) {
|
|
||||||
nextValues.baseCustomFieldGroupId = null;
|
|
||||||
|
|
||||||
if (!customFieldGroup.name) {
|
|
||||||
nextValues.name =
|
|
||||||
baseCustomFieldGroupById[customFieldGroup.baseCustomFieldGroupId].name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nextValues;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if (nextCustomFieldGroupsValues.length > 0) {
|
|
||||||
const { position } = nextCustomFieldGroupsValues[nextCustomFieldGroupsValues.length - 1];
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
cardCustomFieldGroups.map((customFieldGroup) =>
|
|
||||||
CustomFieldGroup.qm.updateOne(customFieldGroup.id, {
|
|
||||||
position: customFieldGroup.position + position,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
await CustomFieldGroup.qm.create(nextCustomFieldGroupsValues);
|
|
||||||
|
|
||||||
if (values.project) {
|
|
||||||
await CustomFieldGroup.qm.update(
|
|
||||||
{
|
|
||||||
cardId: inputs.record.id,
|
|
||||||
baseCustomFieldGroupId: {
|
|
||||||
'!=': null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
baseCustomFieldGroupId: null,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
const unnamedCustomFieldGroups = basedCardCustomFieldGroups.filter(({ name }) => !name);
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
unnamedCustomFieldGroups.map((customFieldGroup) =>
|
|
||||||
CustomFieldGroup.qm.updateOne(customFieldGroup.id, {
|
|
||||||
name: baseCustomFieldGroupById[customFieldGroup.baseCustomFieldGroupId].name,
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const nextCustomFieldIdByCustomFieldId = {};
|
|
||||||
const nextCustomFieldsValues = boardCustomFields.map((customField) => {
|
|
||||||
const id = ids.shift();
|
|
||||||
nextCustomFieldIdByCustomFieldId[customField.id] = id;
|
|
||||||
|
|
||||||
return {
|
|
||||||
..._.pick(customField, ['name', 'showOnFrontOfCard', 'position']),
|
|
||||||
id,
|
|
||||||
customFieldGroupId:
|
|
||||||
nextCustomFieldGroupIdByCustomFieldGroupId[customField.customFieldGroupId],
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (values.project) {
|
|
||||||
basedCustomFieldGroups.forEach((customFieldGroup) => {
|
|
||||||
const customFieldsItem =
|
|
||||||
customFieldsByBaseCustomFieldGroupId[customFieldGroup.baseCustomFieldGroupId];
|
|
||||||
|
|
||||||
if (!customFieldsItem) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
customFieldsItem.forEach((customField) => {
|
|
||||||
const id = ids.shift();
|
|
||||||
nextCustomFieldIdByCustomFieldId[`${customFieldGroup.id}:${customField.id}`] = id;
|
|
||||||
|
|
||||||
nextCustomFieldsValues.push({
|
|
||||||
..._.pick(customField, ['name', 'showOnFrontOfCard', 'position']),
|
|
||||||
id,
|
|
||||||
customFieldGroupId:
|
|
||||||
nextCustomFieldGroupIdByCustomFieldGroupId[customFieldGroup.id] ||
|
|
||||||
customFieldGroup.id,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
await CustomField.qm.create(nextCustomFieldsValues);
|
|
||||||
|
|
||||||
const customFieldGroupIds = boardCustomFieldGroupIds;
|
|
||||||
if (values.project) {
|
|
||||||
customFieldGroupIds.push(...sails.helpers.utils.mapRecords(basedCardCustomFieldGroups));
|
|
||||||
}
|
|
||||||
|
|
||||||
const customFieldValues = await CustomFieldValue.qm.getByCardId(inputs.record.id, {
|
|
||||||
customFieldGroupIdOrIds: customFieldGroupIds,
|
|
||||||
});
|
|
||||||
|
|
||||||
await Promise.all(
|
|
||||||
customFieldValues.map((customFieldValue) => {
|
|
||||||
const updateValues = {
|
|
||||||
customFieldGroupId:
|
|
||||||
nextCustomFieldGroupIdByCustomFieldGroupId[customFieldValue.customFieldGroupId],
|
|
||||||
};
|
|
||||||
|
|
||||||
const nextCustomFieldId =
|
|
||||||
nextCustomFieldIdByCustomFieldId[
|
|
||||||
`${customFieldValue.customFieldGroupId}:${customFieldValue.customFieldId}`
|
|
||||||
] || nextCustomFieldIdByCustomFieldId[customFieldValue.customFieldId];
|
|
||||||
|
|
||||||
if (nextCustomFieldId) {
|
|
||||||
updateValues.customFieldId = nextCustomFieldId;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CustomFieldValue.qm.updateOne(customFieldValue.id, updateValues);
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,14 +30,35 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
exits: {
|
||||||
|
boardInValuesMustBelongToProject: {},
|
||||||
|
},
|
||||||
|
|
||||||
async fn(inputs) {
|
async fn(inputs) {
|
||||||
const { values } = inputs;
|
const { values } = inputs;
|
||||||
|
|
||||||
|
if (values.project && values.project.id === inputs.project.id) {
|
||||||
|
delete values.project;
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = values.project || inputs.project;
|
||||||
|
|
||||||
|
if (values.board) {
|
||||||
|
if (values.board.projectId !== project.id) {
|
||||||
|
throw 'boardInValuesMustBelongToProject';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.board.id === inputs.board.id) {
|
||||||
|
delete values.board;
|
||||||
|
} else {
|
||||||
|
values.boardId = values.board.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const board = values.board || inputs.board;
|
||||||
|
|
||||||
if (!_.isUndefined(values.position)) {
|
if (!_.isUndefined(values.position)) {
|
||||||
const lists = await sails.helpers.boards.getFiniteListsById(
|
const lists = await sails.helpers.boards.getFiniteListsById(board.id, inputs.record.id);
|
||||||
inputs.board.id,
|
|
||||||
inputs.record.id,
|
|
||||||
);
|
|
||||||
|
|
||||||
const { position, repositions } = sails.helpers.utils.insertToPositionables(
|
const { position, repositions } = sails.helpers.utils.insertToPositionables(
|
||||||
values.position,
|
values.position,
|
||||||
@@ -60,7 +81,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
sails.sockets.broadcast(`board:${inputs.board.id}`, 'listUpdate', {
|
sails.sockets.broadcast(`board:${board.id}`, 'listUpdate', {
|
||||||
item: {
|
item: {
|
||||||
id: reposition.record.id,
|
id: reposition.record.id,
|
||||||
position: reposition.position,
|
position: reposition.position,
|
||||||
@@ -72,9 +93,117 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cardIdsByLabelId;
|
||||||
|
let prevLabels;
|
||||||
|
|
||||||
|
if (values.board) {
|
||||||
|
const cards = await Card.qm.getByListId(inputs.record.id);
|
||||||
|
const cardIds = sails.helpers.utils.mapRecords(cards);
|
||||||
|
|
||||||
|
const cardLabels = await CardLabel.qm.getByCardIds(cardIds);
|
||||||
|
|
||||||
|
cardIdsByLabelId = cardLabels.reduce(
|
||||||
|
(result, { cardId, labelId }) => ({
|
||||||
|
...result,
|
||||||
|
[labelId]: [...(result[labelId] || []), cardId],
|
||||||
|
}),
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
|
prevLabels = await Label.qm.getByIds(Object.keys(cardIdsByLabelId));
|
||||||
|
|
||||||
|
const boardMemberUserIds = await sails.helpers.boards.getMemberUserIds(values.board.id);
|
||||||
|
|
||||||
|
await CardSubscription.qm.delete({
|
||||||
|
cardId: cardIds,
|
||||||
|
userId: {
|
||||||
|
'!=': boardMemberUserIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await CardMembership.qm.delete({
|
||||||
|
cardId: cardIds,
|
||||||
|
userId: {
|
||||||
|
'!=': boardMemberUserIds,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await CardLabel.qm.delete({
|
||||||
|
cardId: cardIds,
|
||||||
|
});
|
||||||
|
|
||||||
|
const taskLists = await TaskList.qm.getByCardIds(cardIds);
|
||||||
|
const taskListIds = sails.helpers.utils.mapRecords(taskLists);
|
||||||
|
|
||||||
|
await Task.qm.update(
|
||||||
|
{
|
||||||
|
taskListId: taskListIds,
|
||||||
|
assigneeUserId: {
|
||||||
|
'!=': boardMemberUserIds,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
assigneeUserId: null,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
await sails.helpers.cards.detachCustomFields(cardIds, inputs.board.id, !!values.project);
|
||||||
|
}
|
||||||
|
|
||||||
const { list, tasks } = await List.qm.updateOne(inputs.record.id, values);
|
const { list, tasks } = await List.qm.updateOne(inputs.record.id, values);
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
|
if (values.board) {
|
||||||
|
if (prevLabels.length > 0) {
|
||||||
|
const labels = await Label.qm.getByBoardId(list.boardId);
|
||||||
|
const labelByName = _.keyBy(labels, 'name');
|
||||||
|
|
||||||
|
const cardLabelsValues = (
|
||||||
|
await Promise.all(
|
||||||
|
prevLabels.map(async (label) => {
|
||||||
|
let labelId;
|
||||||
|
if (labelByName[label.name]) {
|
||||||
|
({ id: labelId } = labelByName[label.name]);
|
||||||
|
} else {
|
||||||
|
({ id: labelId } = await sails.helpers.labels.createOne.with({
|
||||||
|
project,
|
||||||
|
values: {
|
||||||
|
..._.omit(label, ['id', 'boardId', 'createdAt', 'updatedAt']),
|
||||||
|
board,
|
||||||
|
},
|
||||||
|
actorUser: inputs.actorUser,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
return cardIdsByLabelId[label.id].map((cardId) => ({
|
||||||
|
cardId,
|
||||||
|
labelId,
|
||||||
|
}));
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
).flat();
|
||||||
|
|
||||||
|
await CardLabel.qm.create(cardLabelsValues);
|
||||||
|
}
|
||||||
|
|
||||||
|
sails.sockets.broadcast(
|
||||||
|
`board:${inputs.board.id}`,
|
||||||
|
'listUpdate',
|
||||||
|
{
|
||||||
|
item: {
|
||||||
|
id: list.id,
|
||||||
|
boardId: null,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
inputs.request,
|
||||||
|
);
|
||||||
|
|
||||||
|
sails.sockets.broadcast(`board:${list.boardId}`, 'listUpdate', {
|
||||||
|
item: list,
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO: add transfer action
|
||||||
|
} else {
|
||||||
sails.sockets.broadcast(
|
sails.sockets.broadcast(
|
||||||
`board:${list.boardId}`,
|
`board:${list.boardId}`,
|
||||||
'listUpdate',
|
'listUpdate',
|
||||||
@@ -83,6 +212,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
inputs.request,
|
inputs.request,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (tasks) {
|
if (tasks) {
|
||||||
const taskListIds = sails.helpers.utils.mapRecords(tasks, 'taskListId', true);
|
const taskListIds = sails.helpers.utils.mapRecords(tasks, 'taskListId', true);
|
||||||
|
|||||||
@@ -3,7 +3,13 @@
|
|||||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const defaultFind = (criteria) => CustomFieldValue.find(criteria).sort('id');
|
const defaultFind = (criteria, { customFieldGroupIdOrIds }) => {
|
||||||
|
if (customFieldGroupIdOrIds) {
|
||||||
|
criteria.customFieldGroupId = customFieldGroupIdOrIds; // eslint-disable-line no-param-reassign
|
||||||
|
}
|
||||||
|
|
||||||
|
return CustomFieldValue.find(criteria).sort('id');
|
||||||
|
};
|
||||||
|
|
||||||
/* Query methods */
|
/* Query methods */
|
||||||
|
|
||||||
@@ -41,22 +47,21 @@ const createOrUpdateOne = async (values) => {
|
|||||||
|
|
||||||
const getByIds = (ids) => defaultFind(ids);
|
const getByIds = (ids) => defaultFind(ids);
|
||||||
|
|
||||||
const getByCardId = (cardId, { customFieldGroupIdOrIds } = {}) => {
|
const getByCardId = (cardId, { customFieldGroupIdOrIds } = {}) =>
|
||||||
const criteria = {
|
defaultFind(
|
||||||
|
{
|
||||||
cardId,
|
cardId,
|
||||||
};
|
},
|
||||||
|
{ customFieldGroupIdOrIds },
|
||||||
|
);
|
||||||
|
|
||||||
if (customFieldGroupIdOrIds) {
|
const getByCardIds = (cardIds, { customFieldGroupIdOrIds } = {}) =>
|
||||||
criteria.customFieldGroupId = customFieldGroupIdOrIds;
|
defaultFind(
|
||||||
}
|
{
|
||||||
|
|
||||||
return defaultFind(criteria);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getByCardIds = (cardIds) =>
|
|
||||||
defaultFind({
|
|
||||||
cardId: cardIds,
|
cardId: cardIds,
|
||||||
});
|
},
|
||||||
|
{ customFieldGroupIdOrIds },
|
||||||
|
);
|
||||||
|
|
||||||
const getByCustomFieldGroupId = (customFieldGroupId) =>
|
const getByCustomFieldGroupId = (customFieldGroupId) =>
|
||||||
defaultFind({
|
defaultFind({
|
||||||
|
|||||||
@@ -52,13 +52,13 @@ const getOneTrashByBoardId = (boardId) =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
const updateOne = async (criteria, values) => {
|
const updateOne = async (criteria, values) => {
|
||||||
if (values.type) {
|
if (values.boardId || values.type) {
|
||||||
return sails.getDatastore().transaction(async (db) => {
|
return sails.getDatastore().transaction(async (db) => {
|
||||||
const [whereQuery, whereQueryValues] = buildWhereQuery(criteria);
|
const [whereQuery, whereQueryValues] = buildWhereQuery(criteria);
|
||||||
|
|
||||||
const queryResult = await sails
|
const queryResult = await sails
|
||||||
.sendNativeQuery(
|
.sendNativeQuery(
|
||||||
`SELECT type FROM list WHERE ${whereQuery} LIMIT 1 FOR UPDATE`,
|
`SELECT board_id, type FROM list WHERE ${whereQuery} LIMIT 1 FOR UPDATE`,
|
||||||
whereQueryValues,
|
whereQueryValues,
|
||||||
)
|
)
|
||||||
.usingConnection(db);
|
.usingConnection(db);
|
||||||
@@ -68,6 +68,7 @@ const updateOne = async (criteria, values) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const prev = {
|
const prev = {
|
||||||
|
boardId: queryResult.rows[0].board_id,
|
||||||
type: queryResult.rows[0].type,
|
type: queryResult.rows[0].type,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -79,6 +80,17 @@ const updateOne = async (criteria, values) => {
|
|||||||
let tasks = [];
|
let tasks = [];
|
||||||
|
|
||||||
if (list) {
|
if (list) {
|
||||||
|
if (list.boardId !== prev.boardId) {
|
||||||
|
await Card.update(
|
||||||
|
{
|
||||||
|
listId: list.id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
boardId: list.boardId,
|
||||||
|
},
|
||||||
|
).usingConnection(db);
|
||||||
|
}
|
||||||
|
|
||||||
const prevTypeState = List.TYPE_STATE_BY_TYPE[prev.type];
|
const prevTypeState = List.TYPE_STATE_BY_TYPE[prev.type];
|
||||||
const typeState = List.TYPE_STATE_BY_TYPE[list.type];
|
const typeState = List.TYPE_STATE_BY_TYPE[list.type];
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user