mirror of
https://github.com/plankanban/planka.git
synced 2025-08-10 16:05:35 +02:00
Added sorting of lists. Added sorting for name, id, position, createdAt,
updatedAt, dueDate, creatorUserId
This commit is contained in:
parent
0d481703da
commit
44a3c2a2ec
18 changed files with 424 additions and 65 deletions
|
@ -89,6 +89,35 @@ const handleListDelete = (list) => ({
|
|||
},
|
||||
});
|
||||
|
||||
const sortList = (id) => ({
|
||||
type: ActionTypes.LIST_SORT,
|
||||
payload: {
|
||||
id,
|
||||
},
|
||||
});
|
||||
|
||||
sortList.success = (list) => ({
|
||||
type: ActionTypes.LIST_SORT__SUCCESS,
|
||||
payload: {
|
||||
list,
|
||||
},
|
||||
});
|
||||
|
||||
sortList.failure = (id, error) => ({
|
||||
type: ActionTypes.LIST_SORT__FAILURE,
|
||||
payload: {
|
||||
id,
|
||||
error,
|
||||
},
|
||||
});
|
||||
|
||||
const handleListSort = (list) => ({
|
||||
type: ActionTypes.LIST_SORT_HANDLE,
|
||||
payload: {
|
||||
list,
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
createList,
|
||||
handleListCreate,
|
||||
|
@ -96,4 +125,6 @@ export default {
|
|||
handleListUpdate,
|
||||
deleteList,
|
||||
handleListDelete,
|
||||
sortList,
|
||||
handleListSort,
|
||||
};
|
||||
|
|
|
@ -248,6 +248,8 @@ Card.propTypes = {
|
|||
onLabelUpdate: PropTypes.func.isRequired,
|
||||
onLabelMove: PropTypes.func.isRequired,
|
||||
onLabelDelete: PropTypes.func.isRequired,
|
||||
// onSortTitleAsc: PropTypes.func.isRequired,
|
||||
// onSortTitleDesc: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
Card.defaultProps = {
|
||||
|
|
|
@ -6,78 +6,108 @@ import { Popup } from '../../lib/custom-ui';
|
|||
|
||||
import { useSteps } from '../../hooks';
|
||||
import DeleteStep from '../DeleteStep';
|
||||
import SortStep from '../SortStep';
|
||||
|
||||
import styles from './ActionsStep.module.scss';
|
||||
|
||||
const StepTypes = {
|
||||
DELETE: 'DELETE',
|
||||
SORT: 'SORT',
|
||||
};
|
||||
|
||||
const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) => {
|
||||
const [t] = useTranslation();
|
||||
const [step, openStep, handleBack] = useSteps();
|
||||
const ActionsStep = React.memo(
|
||||
({ onNameEdit, onCardAdd, onDelete, onClose, onSort, selectedOption, setSelectedOption }) => {
|
||||
const [t] = useTranslation();
|
||||
const [step, openStep, handleBack] = useSteps();
|
||||
|
||||
const handleEditNameClick = useCallback(() => {
|
||||
onNameEdit();
|
||||
onClose();
|
||||
}, [onNameEdit, onClose]);
|
||||
const handleEditNameClick = useCallback(() => {
|
||||
onNameEdit();
|
||||
onClose();
|
||||
}, [onNameEdit, onClose]);
|
||||
|
||||
const handleAddCardClick = useCallback(() => {
|
||||
onCardAdd();
|
||||
onClose();
|
||||
}, [onCardAdd, onClose]);
|
||||
const handleAddCardClick = useCallback(() => {
|
||||
onCardAdd();
|
||||
onClose();
|
||||
}, [onCardAdd, onClose]);
|
||||
|
||||
const handleDeleteClick = useCallback(() => {
|
||||
openStep(StepTypes.DELETE);
|
||||
}, [openStep]);
|
||||
const handleDeleteClick = useCallback(() => {
|
||||
openStep(StepTypes.DELETE);
|
||||
}, [openStep]);
|
||||
|
||||
const handleSortClick = useCallback(() => {
|
||||
openStep(StepTypes.SORT);
|
||||
}, [openStep]);
|
||||
|
||||
if (step && step.type === StepTypes.DELETE) {
|
||||
return (
|
||||
<DeleteStep
|
||||
title="common.deleteList"
|
||||
content="common.areYouSureYouWantToDeleteThisList"
|
||||
buttonContent="action.deleteList"
|
||||
onConfirm={onDelete}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (step && step.type === StepTypes.SORT) {
|
||||
return (
|
||||
<SortStep
|
||||
title="common.sortList"
|
||||
content="common.areYouSureYouWantToSortThisList"
|
||||
buttonContent="action.sortList"
|
||||
onConfirm={onSort}
|
||||
onBack={handleBack}
|
||||
selectedOption={selectedOption}
|
||||
setSelectedOption={setSelectedOption}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (step && step.type === StepTypes.DELETE) {
|
||||
return (
|
||||
<DeleteStep
|
||||
title="common.deleteList"
|
||||
content="common.areYouSureYouWantToDeleteThisList"
|
||||
buttonContent="action.deleteList"
|
||||
onConfirm={onDelete}
|
||||
onBack={handleBack}
|
||||
/>
|
||||
<>
|
||||
<Popup.Header>
|
||||
{t('common.listActions', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Popup.Header>
|
||||
<Popup.Content>
|
||||
<Menu secondary vertical className={styles.menu}>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleEditNameClick}>
|
||||
{t('action.editTitle', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleAddCardClick}>
|
||||
{t('action.addCard', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleDeleteClick}>
|
||||
{t('action.deleteList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleSortClick}>
|
||||
{t('action.sortList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Popup.Content>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popup.Header>
|
||||
{t('common.listActions', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Popup.Header>
|
||||
<Popup.Content>
|
||||
<Menu secondary vertical className={styles.menu}>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleEditNameClick}>
|
||||
{t('action.editTitle', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleAddCardClick}>
|
||||
{t('action.addCard', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleDeleteClick}>
|
||||
{t('action.deleteList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
</Popup.Content>
|
||||
</>
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
ActionsStep.propTypes = {
|
||||
onNameEdit: PropTypes.func.isRequired,
|
||||
onCardAdd: PropTypes.func.isRequired,
|
||||
onDelete: PropTypes.func.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onSort: PropTypes.func.isRequired,
|
||||
selectedOption: PropTypes.string.isRequired,
|
||||
setSelectedOption: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default ActionsStep;
|
||||
|
|
|
@ -4,7 +4,7 @@ import classNames from 'classnames';
|
|||
import { useTranslation } from 'react-i18next';
|
||||
import { Draggable, Droppable } from 'react-beautiful-dnd';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { usePopup } from '../../lib/popup';
|
||||
import { usePopup, closePopup } from '../../lib/popup';
|
||||
|
||||
import DroppableTypes from '../../constants/DroppableTypes';
|
||||
import CardContainer from '../../containers/CardContainer';
|
||||
|
@ -19,6 +19,7 @@ const List = React.memo(
|
|||
({ id, index, name, isPersisted, cardIds, canEdit, onUpdate, onDelete, onCardCreate }) => {
|
||||
const [t] = useTranslation();
|
||||
const [isAddCardOpened, setIsAddCardOpened] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState('name');
|
||||
|
||||
const nameEdit = useRef(null);
|
||||
const listWrapper = useRef(null);
|
||||
|
@ -40,11 +41,11 @@ const List = React.memo(
|
|||
|
||||
const handleAddCardClick = useCallback(() => {
|
||||
setIsAddCardOpened(true);
|
||||
}, []);
|
||||
}, [setIsAddCardOpened]);
|
||||
|
||||
const handleAddCardClose = useCallback(() => {
|
||||
setIsAddCardOpened(false);
|
||||
}, []);
|
||||
}, [setIsAddCardOpened]);
|
||||
|
||||
const handleNameEdit = useCallback(() => {
|
||||
nameEdit.current.open();
|
||||
|
@ -52,7 +53,12 @@ const List = React.memo(
|
|||
|
||||
const handleCardAdd = useCallback(() => {
|
||||
setIsAddCardOpened(true);
|
||||
}, []);
|
||||
}, [setIsAddCardOpened]);
|
||||
|
||||
const onSort = useCallback(() => {
|
||||
onUpdate({ selectedOption: document.querySelector('input[name="sort"]:checked').value });
|
||||
closePopup();
|
||||
}, [onUpdate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isAddCardOpened) {
|
||||
|
@ -114,6 +120,9 @@ const List = React.memo(
|
|||
onNameEdit={handleNameEdit}
|
||||
onCardAdd={handleCardAdd}
|
||||
onDelete={onDelete}
|
||||
onSort={onSort}
|
||||
selectedOption={selectedOption}
|
||||
setSelectedOption={setSelectedOption}
|
||||
>
|
||||
<Button className={classNames(styles.headerButton, styles.target)}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
|
|
164
client/src/components/SortStep/SortStep.jsx
Normal file
164
client/src/components/SortStep/SortStep.jsx
Normal file
|
@ -0,0 +1,164 @@
|
|||
import React, { useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Popup } from '../../lib/custom-ui';
|
||||
|
||||
import styles from './SortStep.module.scss';
|
||||
|
||||
const SortStep = React.memo(
|
||||
({ title, content, buttonContent, onBack, onConfirm, selectedOption, setSelectedOption }) => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
const [checked, setChecked] = useState(false);
|
||||
|
||||
function handleChange(event) {
|
||||
setSelectedOption(event.target.id);
|
||||
}
|
||||
|
||||
const updateState = () => {
|
||||
if (checked) {
|
||||
setChecked(false);
|
||||
} else {
|
||||
setChecked(true);
|
||||
}
|
||||
};
|
||||
|
||||
function changeEvent(event) {
|
||||
handleChange(event);
|
||||
updateState();
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popup.Header onBack={onBack}>
|
||||
{t(title, {
|
||||
context: 'title',
|
||||
})}
|
||||
</Popup.Header>
|
||||
<Popup.Content>
|
||||
<div className={styles.content}>{t(content)}</div>
|
||||
<div>
|
||||
<label htmlFor="name">
|
||||
<input
|
||||
type="radio"
|
||||
id="name"
|
||||
name="sort"
|
||||
value="name"
|
||||
onChange={changeEvent}
|
||||
checked={selectedOption === 'name'}
|
||||
/>
|
||||
{t('action.sortByTitleList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<label htmlFor="id">
|
||||
<input
|
||||
type="radio"
|
||||
id="id"
|
||||
name="sort"
|
||||
value="id"
|
||||
onChange={changeEvent}
|
||||
checked={selectedOption === 'id'}
|
||||
/>
|
||||
{t('action.sortByIdList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</label>
|
||||
<br />
|
||||
<label htmlFor="position">
|
||||
<input
|
||||
type="radio"
|
||||
id="position"
|
||||
name="sort"
|
||||
value="position"
|
||||
onChange={changeEvent}
|
||||
checked={selectedOption === 'position'}
|
||||
/>
|
||||
{t('action.sortByPositionList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</label>
|
||||
<br />
|
||||
<label htmlFor="createdAt">
|
||||
<input
|
||||
type="radio"
|
||||
id="createdAt"
|
||||
name="sort"
|
||||
value="createdAt"
|
||||
onChange={changeEvent}
|
||||
checked={selectedOption === 'createdAt'}
|
||||
/>
|
||||
{t('action.sortByCreatedAt', {
|
||||
context: 'title',
|
||||
})}
|
||||
</label>
|
||||
<br />
|
||||
<label htmlFor="updatedAt">
|
||||
<input
|
||||
type="radio"
|
||||
id="updatedAt"
|
||||
name="sort"
|
||||
value="updatedAt"
|
||||
onChange={changeEvent}
|
||||
checked={selectedOption === 'updatedAt'}
|
||||
/>
|
||||
{t('action.sortByUpdatedAtList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</label>
|
||||
<br />
|
||||
<label htmlFor="dueDate">
|
||||
<input
|
||||
type="radio"
|
||||
id="dueDate"
|
||||
name="sort"
|
||||
value="dueDate"
|
||||
onChange={changeEvent}
|
||||
checked={selectedOption === 'dueDate'}
|
||||
/>
|
||||
{t('action.sortByDueDateList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</label>
|
||||
<br />
|
||||
<label htmlFor="creatorUserId">
|
||||
<input
|
||||
type="radio"
|
||||
id="creatorUserId"
|
||||
name="sort"
|
||||
value="creatorUserId"
|
||||
onChange={changeEvent}
|
||||
checked={selectedOption === 'creatorUserId'}
|
||||
/>
|
||||
{t('action.sortByCreatorUserIdList', {
|
||||
context: 'title',
|
||||
})}
|
||||
</label>
|
||||
<br />
|
||||
</div>
|
||||
|
||||
<Button fluid negative content={t(buttonContent)} onClick={onConfirm} />
|
||||
</Popup.Content>
|
||||
</>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
SortStep.propTypes = {
|
||||
title: PropTypes.string.isRequired,
|
||||
content: PropTypes.string.isRequired,
|
||||
buttonContent: PropTypes.string.isRequired,
|
||||
onConfirm: PropTypes.func.isRequired,
|
||||
onBack: PropTypes.func,
|
||||
selectedOption: PropTypes.string.isRequired,
|
||||
setSelectedOption: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
SortStep.defaultProps = {
|
||||
onBack: undefined,
|
||||
};
|
||||
|
||||
export default SortStep;
|
7
client/src/components/SortStep/SortStep.module.scss
Normal file
7
client/src/components/SortStep/SortStep.module.scss
Normal file
|
@ -0,0 +1,7 @@
|
|||
:global(#app) {
|
||||
.content {
|
||||
color: #212121;
|
||||
padding-bottom: 6px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
}
|
3
client/src/components/SortStep/index.js
Normal file
3
client/src/components/SortStep/index.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import SortStep from './SortStep';
|
||||
|
||||
export default SortStep;
|
|
@ -172,6 +172,10 @@ export default {
|
|||
LIST_DELETE__SUCCESS: 'LIST_DELETE__SUCCESS',
|
||||
LIST_DELETE__FAILURE: 'LIST_DELETE__FAILURE',
|
||||
LIST_DELETE_HANDLE: 'LIST_DELETE_HANDLE',
|
||||
LIST_SORT: 'LIST_SORT',
|
||||
LIST_SORT__SUCCESS: 'LIST_SORT__SUCCESS',
|
||||
LIST_SORT__FAILURE: 'LIST_SORT__FAILURE',
|
||||
LIST_SORT_HANDLE: 'LIST_SORT_HANDLE',
|
||||
|
||||
/* Cards */
|
||||
|
||||
|
|
|
@ -120,6 +120,7 @@ export default {
|
|||
LIST_MOVE: `${PREFIX}/LIST_MOVE`,
|
||||
LIST_DELETE: `${PREFIX}/LIST_DELETE`,
|
||||
LIST_DELETE_HANDLE: `${PREFIX}/LIST_DELETE_HANDLE`,
|
||||
LIST_SORT_HANDLE: `${PREFIX}/LIST_SORT_HANDLE`,
|
||||
|
||||
/* Cards */
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ const mapDispatchToProps = (dispatch) =>
|
|||
onUpdate: entryActions.updateBoard,
|
||||
onMove: entryActions.moveBoard,
|
||||
onDelete: entryActions.deleteBoard,
|
||||
onSort: entryActions.sortBoard,
|
||||
},
|
||||
dispatch,
|
||||
);
|
||||
|
|
|
@ -35,6 +35,7 @@ const mapDispatchToProps = (dispatch, { id }) =>
|
|||
onUpdate: (data) => entryActions.updateList(id, data),
|
||||
onDelete: () => entryActions.deleteList(id),
|
||||
onCardCreate: (data, autoOpen) => entryActions.createCard(id, data, autoOpen),
|
||||
onSort: (data) => entryActions.sortList(id, data),
|
||||
},
|
||||
dispatch,
|
||||
);
|
||||
|
|
|
@ -51,6 +51,13 @@ const handleListDelete = (list) => ({
|
|||
},
|
||||
});
|
||||
|
||||
const handleListSort = (list) => ({
|
||||
type: EntryActionTypes.LIST_SORT_HANDLE,
|
||||
payload: {
|
||||
list,
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
createListInCurrentBoard,
|
||||
handleListCreate,
|
||||
|
@ -59,4 +66,5 @@ export default {
|
|||
moveList,
|
||||
deleteList,
|
||||
handleListDelete,
|
||||
handleListSort,
|
||||
};
|
||||
|
|
|
@ -32,6 +32,7 @@ export default {
|
|||
'Är du säker på att du vill ta bort den här kommentaren?',
|
||||
areYouSureYouWantToDeleteThisLabel: 'Är du säker på att du vill ta bort den här etiketten?',
|
||||
areYouSureYouWantToDeleteThisList: 'Är du säker på att du vill ta bort den här listan?',
|
||||
areYouSureYouWantToSortThisList: 'Är du säker på att du vill sortera den här listan?',
|
||||
areYouSureYouWantToDeleteThisProject: 'Är du säker på att du vill ta bort det här projektet?',
|
||||
areYouSureYouWantToDeleteThisTask: 'Är du säker på att du vill ta bort den här uppgiften?',
|
||||
areYouSureYouWantToDeleteThisUser: 'Är du säker på att du vill ta bort den här användaren?',
|
||||
|
@ -129,6 +130,7 @@ export default {
|
|||
selectList: 'Välj lista',
|
||||
selectProject: 'Välj projekt',
|
||||
settings: 'Inställningar',
|
||||
sortList: 'Sortera listan',
|
||||
stopwatch: 'Timer',
|
||||
subscribeToMyOwnCardsByDefault: 'Prenumerera på mina egna kort som standard',
|
||||
taskActions_title: 'Uppgiftsåtgärder',
|
||||
|
@ -205,6 +207,14 @@ export default {
|
|||
save: 'Spara',
|
||||
showAllAttachments: 'Visa alla bilagor ({{hidden}} dolda)',
|
||||
showFewerAttachments: 'Visa färre bilagor',
|
||||
sortByCreatedAt: ' Sortera på skapad',
|
||||
sortByCreatorUserIdList: ' Sortera på skapad av',
|
||||
sortByDueDateList: ' Sortera på förfallodatum',
|
||||
sortByIdList: ' Sortera på id',
|
||||
sortByPositionList: ' Sortera på position',
|
||||
sortByTitleList: ' Sortera på titel',
|
||||
sortByUpdatedAtList: ' Sortera på uppdaterad',
|
||||
sortList: 'Sortera listan',
|
||||
start: 'Starta',
|
||||
stop: 'Stoppa',
|
||||
subscribe: 'Prenumerera',
|
||||
|
|
|
@ -76,16 +76,77 @@ export default class extends BaseModel {
|
|||
|
||||
break;
|
||||
}
|
||||
case ActionTypes.LIST_SORT:
|
||||
List.withId(payload.id).sortList();
|
||||
break;
|
||||
case ActionTypes.LIST_SORT__SUCCESS:
|
||||
case ActionTypes.LIST_SORT_HANDLE: {
|
||||
const listModel = List.withId(payload.list.id);
|
||||
|
||||
if (listModel) {
|
||||
listModel.sortList();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
getOrderedCardsQuerySet() {
|
||||
getOrderedByIdCardsQuerySet() {
|
||||
return this.cards.orderBy('id');
|
||||
}
|
||||
|
||||
getOrderedByPositionCardsQuerySet() {
|
||||
return this.cards.orderBy('position');
|
||||
}
|
||||
|
||||
getOrderedByTitelCardsQuerySet() {
|
||||
return this.cards.orderBy('name');
|
||||
}
|
||||
|
||||
getOrderedByCreatedAtCardsQuerySet() {
|
||||
return this.cards.orderBy('createdAt');
|
||||
}
|
||||
|
||||
getOrderedByUpdatedAtCardsQuerySet() {
|
||||
return this.cards.orderBy('updatedAt');
|
||||
}
|
||||
|
||||
getOrderedByDueDateCardsQuerySet() {
|
||||
return this.cards.orderBy('dueDate');
|
||||
}
|
||||
|
||||
getFilteredOrderedCardsModelArray() {
|
||||
let cardModels = this.getOrderedCardsQuerySet().toModelArray();
|
||||
const sortby = this.selectedOption;
|
||||
|
||||
let cardModels = null;
|
||||
|
||||
switch (sortby) {
|
||||
case 'name':
|
||||
cardModels = this.getOrderedByTitelCardsQuerySet().toModelArray();
|
||||
break;
|
||||
case 'id':
|
||||
cardModels = this.getOrderedByIdCardsQuerySet().toModelArray();
|
||||
break;
|
||||
case 'position':
|
||||
cardModels = this.getOrderedByPositionCardsQuerySet().toModelArray();
|
||||
break;
|
||||
case 'createdAt':
|
||||
cardModels = this.getOrderedByCreatedAtCardsQuerySet().toModelArray();
|
||||
break;
|
||||
case 'updatedAt':
|
||||
cardModels = this.getOrderedByUpdatedAtCardsQuerySet().toModelArray();
|
||||
break;
|
||||
case 'dueDate':
|
||||
cardModels = this.getOrderedByDueDateCardsQuerySet().toModelArray();
|
||||
break;
|
||||
case 'creatorUserId':
|
||||
cardModels = this.getOrderedByDueDateCardsQuerySet().toModelArray();
|
||||
break;
|
||||
default:
|
||||
cardModels = this.getOrderedByPositionCardsQuerySet().toModelArray();
|
||||
}
|
||||
|
||||
const filterUserIds = this.board.filterUsers.toRefArray().map((user) => user.id);
|
||||
const filterLabelIds = this.board.filterLabels.toRefArray().map((label) => label.id);
|
||||
|
|
|
@ -61,6 +61,24 @@ export function* handleListUpdate(list) {
|
|||
yield put(actions.handleListUpdate(list));
|
||||
}
|
||||
|
||||
export function* sortList(id, data) {
|
||||
yield put(actions.sortList(id, data));
|
||||
|
||||
let list;
|
||||
try {
|
||||
({ item: list } = yield call(request, api.sortList, id, data));
|
||||
} catch (error) {
|
||||
yield put(actions.sortList.failure(id, error));
|
||||
return;
|
||||
}
|
||||
|
||||
yield put(actions.sortList.success(list));
|
||||
}
|
||||
|
||||
export function* handleListSort(list) {
|
||||
yield put(actions.handleListSort(list));
|
||||
}
|
||||
|
||||
export function* moveList(id, index) {
|
||||
const { boardId } = yield select(selectors.selectListById, id);
|
||||
const position = yield select(selectors.selectNextListPosition, boardId, index, id);
|
||||
|
|
|
@ -17,6 +17,9 @@ export default function* listsWatchers() {
|
|||
takeEvery(EntryActionTypes.LIST_UPDATE_HANDLE, ({ payload: { list } }) =>
|
||||
services.handleListUpdate(list),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LIST_SORT_HANDLE, ({ payload: { list } }) =>
|
||||
services.handleListSort(list),
|
||||
),
|
||||
takeEvery(EntryActionTypes.LIST_MOVE, ({ payload: { id, index } }) =>
|
||||
services.moveList(id, index),
|
||||
),
|
||||
|
|
|
@ -84,6 +84,10 @@ const createSocketEventsChannel = () =>
|
|||
emit(entryActions.handleListDelete(item));
|
||||
};
|
||||
|
||||
const handleListSort = ({ item }) => {
|
||||
emit(entryActions.handleListSort(item));
|
||||
};
|
||||
|
||||
const handleLabelCreate = ({ item }) => {
|
||||
emit(entryActions.handleLabelCreate(item));
|
||||
};
|
||||
|
@ -193,6 +197,7 @@ const createSocketEventsChannel = () =>
|
|||
socket.on('listCreate', handleListCreate);
|
||||
socket.on('listUpdate', handleListUpdate);
|
||||
socket.on('listDelete', handleListDelete);
|
||||
socket.on('listSort', handleListSort);
|
||||
|
||||
socket.on('labelCreate', handleLabelCreate);
|
||||
socket.on('labelUpdate', handleLabelUpdate);
|
||||
|
@ -249,6 +254,7 @@ const createSocketEventsChannel = () =>
|
|||
socket.off('listCreate', handleListCreate);
|
||||
socket.off('listUpdate', handleListUpdate);
|
||||
socket.off('listDelete', handleListDelete);
|
||||
socket.off('listSort', handleListSort);
|
||||
|
||||
socket.off('labelCreate', handleLabelCreate);
|
||||
socket.off('labelUpdate', handleLabelUpdate);
|
||||
|
|
12
package-lock.json
generated
12
package-lock.json
generated
|
@ -2039,9 +2039,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz",
|
||||
"integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==",
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
|
@ -3510,9 +3510,9 @@
|
|||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
|
||||
},
|
||||
"yaml": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.1.3.tgz",
|
||||
"integrity": "sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg=="
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz",
|
||||
"integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "17.6.2",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue