Added card archiving functionality and created status column with corresponding migrations

- Implemented the option to archive cards in the system, with support in both backend and frontend.
- Created 'status' column in the cards table to manage archiving status.
- Developed necessary database migrations for the new column.
- Reused the delete confirmation popup to confirm archiving, minimizing code changes.
- Modifications made to backend handlers and frontend UI to support the archiving functionality.
pull/724/head
Robson Ventura Rodrigues 2 years ago
parent 03825c3bed
commit 60c514b63f

@ -49,6 +49,13 @@ updateCard.success = (card) => ({
}, },
}); });
updateCard.archive_success = (card) => ({
type: ActionTypes.CARD_ARCHIVE__SUCCESS,
payload: {
card,
},
});
updateCard.failure = (id, error) => ({ updateCard.failure = (id, error) => ({
type: ActionTypes.CARD_UPDATE__FAILURE, type: ActionTypes.CARD_UPDATE__FAILURE,
payload: { payload: {

@ -6,7 +6,7 @@ import { Button, Form } from 'semantic-ui-react';
import { Input, Popup } from '../../lib/custom-ui'; import { Input, Popup } from '../../lib/custom-ui';
import { useForm, useSteps } from '../../hooks'; import { useForm, useSteps } from '../../hooks';
import DeleteStep from '../DeleteStep'; import ConfirmStep from '../ConfirmStep';
import styles from './EditStep.module.scss'; import styles from './EditStep.module.scss';
@ -54,7 +54,7 @@ const EditStep = React.memo(({ defaultData, onUpdate, onDelete, onClose }) => {
if (step && step.type === StepTypes.DELETE) { if (step && step.type === StepTypes.DELETE) {
return ( return (
<DeleteStep <ConfirmStep
title="common.deleteBoard" title="common.deleteBoard"
content="common.areYouSureYouWantToDeleteThisBoard" content="common.areYouSureYouWantToDeleteThisBoard"
buttonContent="action.deleteBoard" buttonContent="action.deleteBoard"

@ -11,9 +11,10 @@ import LabelsStep from '../LabelsStep';
import DueDateEditStep from '../DueDateEditStep'; import DueDateEditStep from '../DueDateEditStep';
import StopwatchEditStep from '../StopwatchEditStep'; import StopwatchEditStep from '../StopwatchEditStep';
import CardMoveStep from '../CardMoveStep'; import CardMoveStep from '../CardMoveStep';
import DeleteStep from '../DeleteStep'; import ConfirmStep from '../ConfirmStep';
import styles from './ActionsStep.module.scss'; import styles from './ActionsStep.module.scss';
import { CardStatus } from '../../constants/Enums';
const StepTypes = { const StepTypes = {
USERS: 'USERS', USERS: 'USERS',
@ -22,6 +23,7 @@ const StepTypes = {
EDIT_STOPWATCH: 'EDIT_STOPWATCH', EDIT_STOPWATCH: 'EDIT_STOPWATCH',
MOVE: 'MOVE', MOVE: 'MOVE',
DELETE: 'DELETE', DELETE: 'DELETE',
ARCHIVE: 'ARCHIVE',
}; };
const ActionsStep = React.memo( const ActionsStep = React.memo(
@ -48,6 +50,7 @@ const ActionsStep = React.memo(
onLabelMove, onLabelMove,
onLabelDelete, onLabelDelete,
onClose, onClose,
onArchive,
}) => { }) => {
const [t] = useTranslation(); const [t] = useTranslation();
const [step, openStep, handleBack] = useSteps(); const [step, openStep, handleBack] = useSteps();
@ -82,6 +85,10 @@ const ActionsStep = React.memo(
onClose(); onClose();
}, [onDuplicate, onClose]); }, [onDuplicate, onClose]);
const handleArchiveClick = useCallback(() => {
openStep(StepTypes.ARCHIVE);
}, [openStep]);
const handleDeleteClick = useCallback(() => { const handleDeleteClick = useCallback(() => {
openStep(StepTypes.DELETE); openStep(StepTypes.DELETE);
}, [openStep]); }, [openStep]);
@ -162,7 +169,7 @@ const ActionsStep = React.memo(
); );
case StepTypes.DELETE: case StepTypes.DELETE:
return ( return (
<DeleteStep <ConfirmStep
title="common.deleteCard" title="common.deleteCard"
content="common.areYouSureYouWantToDeleteThisCard" content="common.areYouSureYouWantToDeleteThisCard"
buttonContent="action.deleteCard" buttonContent="action.deleteCard"
@ -170,6 +177,16 @@ const ActionsStep = React.memo(
onBack={handleBack} onBack={handleBack}
/> />
); );
case StepTypes.ARCHIVE:
return (
<ConfirmStep
title="common.archiveCard_title"
content="common.areYouSureYouWantToArchiveThisCard"
buttonContent="action.archiveCard"
onConfirm={onArchive}
onBack={handleBack}
/>
);
default: default:
} }
} }
@ -218,6 +235,11 @@ const ActionsStep = React.memo(
context: 'title', context: 'title',
})} })}
</Menu.Item> </Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleArchiveClick}>
{t('action.archiveCard', {
context: 'title',
})}
</Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleDeleteClick}> <Menu.Item className={styles.menuItem} onClick={handleDeleteClick}>
{t('action.deleteCard', { {t('action.deleteCard', {
context: 'title', context: 'title',
@ -255,6 +277,7 @@ ActionsStep.propTypes = {
onLabelMove: PropTypes.func.isRequired, onLabelMove: PropTypes.func.isRequired,
onLabelDelete: PropTypes.func.isRequired, onLabelDelete: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
onArchive: PropTypes.func.isRequired,
}; };
export default ActionsStep; export default ActionsStep;

@ -17,6 +17,7 @@ import DueDate from '../DueDate';
import Stopwatch from '../Stopwatch'; import Stopwatch from '../Stopwatch';
import styles from './Card.module.scss'; import styles from './Card.module.scss';
import { CardStatus } from '../../constants/Enums';
const Card = React.memo( const Card = React.memo(
({ ({
@ -81,6 +82,13 @@ const Card = React.memo(
[onUpdate], [onUpdate],
); );
const handleArchiveClick = useCallback(() => {
onUpdate({
status: CardStatus.ARCHIVED,
});
onClose();
}, [onUpdate]);
const handleNameEdit = useCallback(() => { const handleNameEdit = useCallback(() => {
nameEdit.current.open(); nameEdit.current.open();
}, []); }, []);
@ -197,6 +205,7 @@ const Card = React.memo(
onLabelUpdate={onLabelUpdate} onLabelUpdate={onLabelUpdate}
onLabelMove={onLabelMove} onLabelMove={onLabelMove}
onLabelDelete={onLabelDelete} onLabelDelete={onLabelDelete}
onArchive={handleArchiveClick}
> >
<Button className={classNames(styles.actionsButton, styles.target)}> <Button className={classNames(styles.actionsButton, styles.target)}>
<Icon fitted name="pencil" size="small" /> <Icon fitted name="pencil" size="small" />

@ -9,7 +9,7 @@ import { Markdown } from '../../../lib/custom-ui';
import getDateFormat from '../../../utils/get-date-format'; import getDateFormat from '../../../utils/get-date-format';
import CommentEdit from './CommentEdit'; import CommentEdit from './CommentEdit';
import User from '../../User'; import User from '../../User';
import DeleteStep from '../../DeleteStep'; import ConfirmStep from '../../ConfirmStep';
import styles from './ItemComment.module.scss'; import styles from './ItemComment.module.scss';
@ -23,7 +23,7 @@ const ItemComment = React.memo(
commentEdit.current.open(); commentEdit.current.open();
}, []); }, []);
const DeletePopup = usePopup(DeleteStep); const DeletePopup = usePopup(ConfirmStep);
return ( return (
<Comment> <Comment>

@ -6,7 +6,7 @@ import { Button, Form } from 'semantic-ui-react';
import { Input, Popup } from '../../../lib/custom-ui'; import { Input, Popup } from '../../../lib/custom-ui';
import { useForm, useSteps } from '../../../hooks'; import { useForm, useSteps } from '../../../hooks';
import DeleteStep from '../../DeleteStep'; import ConfirmStep from '../../ConfirmStep';
import styles from './EditStep.module.scss'; import styles from './EditStep.module.scss';
@ -54,7 +54,7 @@ const EditStep = React.memo(({ defaultData, onUpdate, onDelete, onClose }) => {
if (step && step.type === StepTypes.DELETE) { if (step && step.type === StepTypes.DELETE) {
return ( return (
<DeleteStep <ConfirmStep
title="common.deleteAttachment" title="common.deleteAttachment"
content="common.areYouSureYouWantToDeleteThisAttachment" content="common.areYouSureYouWantToDeleteThisAttachment"
buttonContent="action.deleteAttachment" buttonContent="action.deleteAttachment"

@ -23,9 +23,10 @@ import LabelsStep from '../LabelsStep';
import DueDateEditStep from '../DueDateEditStep'; import DueDateEditStep from '../DueDateEditStep';
import StopwatchEditStep from '../StopwatchEditStep'; import StopwatchEditStep from '../StopwatchEditStep';
import CardMoveStep from '../CardMoveStep'; import CardMoveStep from '../CardMoveStep';
import DeleteStep from '../DeleteStep'; import ConfirmStep from '../ConfirmStep';
import styles from './CardModal.module.scss'; import styles from './CardModal.module.scss';
import { CardStatus } from '../../constants/Enums';
const CardModal = React.memo( const CardModal = React.memo(
({ ({
@ -141,6 +142,13 @@ const CardModal = React.memo(
}); });
}, [isSubscribed, onUpdate]); }, [isSubscribed, onUpdate]);
const handleArchiveClick = useCallback(() => {
onUpdate({
status: CardStatus.ARCHIVED,
});
onClose();
}, [onUpdate, onClose]);
const handleDuplicateClick = useCallback(() => { const handleDuplicateClick = useCallback(() => {
onDuplicate(); onDuplicate();
onClose(); onClose();
@ -168,7 +176,7 @@ const CardModal = React.memo(
const DueDateEditPopup = usePopup(DueDateEditStep); const DueDateEditPopup = usePopup(DueDateEditStep);
const StopwatchEditPopup = usePopup(StopwatchEditStep); const StopwatchEditPopup = usePopup(StopwatchEditStep);
const CardMovePopup = usePopup(CardMoveStep); const CardMovePopup = usePopup(CardMoveStep);
const DeletePopup = usePopup(DeleteStep); const DeletePopup = usePopup(ConfirmStep);
const userIds = users.map((user) => user.id); const userIds = users.map((user) => user.id);
const labelIds = labels.map((label) => label.id); const labelIds = labels.map((label) => label.id);
@ -506,6 +514,19 @@ const CardModal = React.memo(
<Icon name="copy outline" className={styles.actionIcon} /> <Icon name="copy outline" className={styles.actionIcon} />
{t('action.duplicate')} {t('action.duplicate')}
</Button> </Button>
<DeletePopup
title="common.archiveCard"
content="common.areYouSureYouWantToArchiveThisCard"
buttonContent="action.archiveCard"
onConfirm={handleArchiveClick}
>
<Button fluid className={styles.actionButton}>
<Icon name="archive icon" className={styles.actionIcon} />
{t('action.archive')}
</Button>
</DeletePopup>
<DeletePopup <DeletePopup
title="common.deleteCard" title="common.deleteCard"
content="common.areYouSureYouWantToDeleteThisCard" content="common.areYouSureYouWantToDeleteThisCard"

@ -5,7 +5,7 @@ import { Menu } from 'semantic-ui-react';
import { Popup } from '../../../lib/custom-ui'; import { Popup } from '../../../lib/custom-ui';
import { useSteps } from '../../../hooks'; import { useSteps } from '../../../hooks';
import DeleteStep from '../../DeleteStep'; import ConfirmStep from '../../ConfirmStep';
import styles from './ActionsStep.module.scss'; import styles from './ActionsStep.module.scss';
@ -28,7 +28,7 @@ const ActionsStep = React.memo(({ onNameEdit, onDelete, onClose }) => {
if (step && step.type === StepTypes.DELETE) { if (step && step.type === StepTypes.DELETE) {
return ( return (
<DeleteStep <ConfirmStep
title="common.deleteTask" title="common.deleteTask"
content="common.areYouSureYouWantToDeleteThisTask" content="common.areYouSureYouWantToDeleteThisTask"
buttonContent="action.deleteTask" buttonContent="action.deleteTask"

@ -4,9 +4,9 @@ import { useTranslation } from 'react-i18next';
import { Button } from 'semantic-ui-react'; import { Button } from 'semantic-ui-react';
import { Popup } from '../../lib/custom-ui'; import { Popup } from '../../lib/custom-ui';
import styles from './DeleteStep.module.scss'; import styles from './ConfirmStep.module.scss';
const DeleteStep = React.memo(({ title, content, buttonContent, onConfirm, onBack }) => { const ConfirmStep = React.memo(({ title, content, buttonContent, onConfirm, onBack }) => {
const [t] = useTranslation(); const [t] = useTranslation();
return ( return (
@ -24,7 +24,7 @@ const DeleteStep = React.memo(({ title, content, buttonContent, onConfirm, onBac
); );
}); });
DeleteStep.propTypes = { ConfirmStep.propTypes = {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
content: PropTypes.string.isRequired, content: PropTypes.string.isRequired,
buttonContent: PropTypes.string.isRequired, buttonContent: PropTypes.string.isRequired,
@ -32,8 +32,8 @@ DeleteStep.propTypes = {
onBack: PropTypes.func, onBack: PropTypes.func,
}; };
DeleteStep.defaultProps = { ConfirmStep.defaultProps = {
onBack: undefined, onBack: undefined,
}; };
export default DeleteStep; export default ConfirmStep;

@ -0,0 +1,3 @@
import ConfirmStep from './ConfirmStep';
export default ConfirmStep;

@ -1,3 +0,0 @@
import DeleteStep from './DeleteStep';
export default DeleteStep;

@ -8,7 +8,7 @@ import { Popup } from '../../lib/custom-ui';
import { useForm, useSteps } from '../../hooks'; import { useForm, useSteps } from '../../hooks';
import LabelColors from '../../constants/LabelColors'; import LabelColors from '../../constants/LabelColors';
import Editor from './Editor'; import Editor from './Editor';
import DeleteStep from '../DeleteStep'; import ConfirmStep from '../ConfirmStep';
import styles from './EditStep.module.scss'; import styles from './EditStep.module.scss';
@ -46,7 +46,7 @@ const EditStep = React.memo(({ defaultData, onUpdate, onDelete, onBack }) => {
if (step && step.type === StepTypes.DELETE) { if (step && step.type === StepTypes.DELETE) {
return ( return (
<DeleteStep <ConfirmStep
title="common.deleteLabel" title="common.deleteLabel"
content="common.areYouSureYouWantToDeleteThisLabel" content="common.areYouSureYouWantToDeleteThisLabel"
buttonContent="action.deleteLabel" buttonContent="action.deleteLabel"

@ -5,7 +5,7 @@ import { Menu } from 'semantic-ui-react';
import { Popup } from '../../lib/custom-ui'; import { Popup } from '../../lib/custom-ui';
import { useSteps } from '../../hooks'; import { useSteps } from '../../hooks';
import DeleteStep from '../DeleteStep'; import ConfirmStep from '../ConfirmStep';
import styles from './ActionsStep.module.scss'; import styles from './ActionsStep.module.scss';
@ -33,7 +33,7 @@ const ActionsStep = React.memo(({ onNameEdit, onCardAdd, onDelete, onClose }) =>
if (step && step.type === StepTypes.DELETE) { if (step && step.type === StepTypes.DELETE) {
return ( return (
<DeleteStep <ConfirmStep
title="common.deleteList" title="common.deleteList"
content="common.areYouSureYouWantToDeleteThisList" content="common.areYouSureYouWantToDeleteThisList"
buttonContent="action.deleteList" buttonContent="action.deleteList"

@ -6,7 +6,7 @@ import { Button } from 'semantic-ui-react';
import { useSteps } from '../../hooks'; import { useSteps } from '../../hooks';
import User from '../User'; import User from '../User';
import DeleteStep from '../DeleteStep'; import ConfirmStep from '../ConfirmStep';
import styles from './ActionsStep.module.scss'; import styles from './ActionsStep.module.scss';
@ -71,7 +71,7 @@ const ActionsStep = React.memo(
} }
case StepTypes.DELETE: case StepTypes.DELETE:
return ( return (
<DeleteStep <ConfirmStep
title={membership.user.isCurrent ? leaveConfirmationTitle : deleteConfirmationTitle} title={membership.user.isCurrent ? leaveConfirmationTitle : deleteConfirmationTitle}
content={ content={
membership.user.isCurrent ? leaveConfirmationContent : deleteConfirmationContent membership.user.isCurrent ? leaveConfirmationContent : deleteConfirmationContent

@ -5,14 +5,14 @@ import { Button, Divider, Header, Tab } from 'semantic-ui-react';
import { usePopup } from '../../../lib/popup'; import { usePopup } from '../../../lib/popup';
import InformationEdit from './InformationEdit'; import InformationEdit from './InformationEdit';
import DeleteStep from '../../DeleteStep'; import ConfirmStep from '../../ConfirmStep';
import styles from './GeneralPane.module.scss'; import styles from './GeneralPane.module.scss';
const GeneralPane = React.memo(({ name, onUpdate, onDelete }) => { const GeneralPane = React.memo(({ name, onUpdate, onDelete }) => {
const [t] = useTranslation(); const [t] = useTranslation();
const DeletePopup = usePopup(DeleteStep); const DeletePopup = usePopup(ConfirmStep);
return ( return (
<Tab.Pane attached={false} className={styles.wrapper}> <Tab.Pane attached={false} className={styles.wrapper}>

@ -10,7 +10,7 @@ import UserInformationEditStep from '../../UserInformationEditStep';
import UserUsernameEditStep from '../../UserUsernameEditStep'; import UserUsernameEditStep from '../../UserUsernameEditStep';
import UserEmailEditStep from '../../UserEmailEditStep'; import UserEmailEditStep from '../../UserEmailEditStep';
import UserPasswordEditStep from '../../UserPasswordEditStep'; import UserPasswordEditStep from '../../UserPasswordEditStep';
import DeleteStep from '../../DeleteStep'; import ConfirmStep from '../../ConfirmStep';
import styles from './ActionsStep.module.scss'; import styles from './ActionsStep.module.scss';
@ -110,7 +110,7 @@ const ActionsStep = React.memo(
); );
case StepTypes.DELETE: case StepTypes.DELETE:
return ( return (
<DeleteStep <ConfirmStep
title="common.deleteUser" title="common.deleteUser"
content="common.areYouSureYouWantToDeleteThisUser" content="common.areYouSureYouWantToDeleteThisUser"
buttonContent="action.deleteUser" buttonContent="action.deleteUser"

@ -201,6 +201,7 @@ export default {
CARD_DELETE__SUCCESS: 'CARD_DELETE__SUCCESS', CARD_DELETE__SUCCESS: 'CARD_DELETE__SUCCESS',
CARD_DELETE__FAILURE: 'CARD_DELETE__FAILURE', CARD_DELETE__FAILURE: 'CARD_DELETE__FAILURE',
CARD_DELETE_HANDLE: 'CARD_DELETE_HANDLE', CARD_DELETE_HANDLE: 'CARD_DELETE_HANDLE',
CARD_ARCHIVE__SUCCESS: 'CARD_ARCHIVE__SUCCESS',
/* Tasks */ /* Tasks */

@ -13,3 +13,8 @@ export const ActivityTypes = {
MOVE_CARD: 'moveCard', MOVE_CARD: 'moveCard',
COMMENT_CARD: 'commentCard', COMMENT_CARD: 'commentCard',
}; };
export const CardStatus = {
ACTIVE: 'active',
ARCHIVED: 'archived',
};

@ -184,6 +184,7 @@ export default {
createLabel: 'Vytvořit štítek', createLabel: 'Vytvořit štítek',
createNewLabel: 'Vytvořit nový štítek', createNewLabel: 'Vytvořit nový štítek',
createProject: 'Vytvořit projekt', createProject: 'Vytvořit projekt',
archive: 'Archivovat',
delete: 'Smazat', delete: 'Smazat',
deleteAttachment: 'Smazat přílohu', deleteAttachment: 'Smazat přílohu',
deleteAvatar: 'Smazat avatar', deleteAvatar: 'Smazat avatar',

@ -164,6 +164,7 @@ export default {
createLabel: 'Opret mærkat', createLabel: 'Opret mærkat',
createNewLabel: 'Opret nyt mærkat', createNewLabel: 'Opret nyt mærkat',
createProject: 'Opret projekt', createProject: 'Opret projekt',
archive: 'Archivovat',
delete: 'Slet', delete: 'Slet',
deleteAttachment: 'Slet vedhæftning', deleteAttachment: 'Slet vedhæftning',
deleteAvatar: 'Slet profilbillede', deleteAvatar: 'Slet profilbillede',

@ -174,6 +174,7 @@ export default {
createLabel: 'Label erstellen', createLabel: 'Label erstellen',
createNewLabel: 'Neues Label erstellen', createNewLabel: 'Neues Label erstellen',
createProject: 'Projekt erstellen', createProject: 'Projekt erstellen',
archive: 'Archivieren',
delete: 'Löschen', delete: 'Löschen',
deleteAttachment: 'Anhang löschen', deleteAttachment: 'Anhang löschen',
deleteAvatar: 'Avatar löschen', deleteAvatar: 'Avatar löschen',

@ -26,6 +26,7 @@ export default {
areYouSureYouWantToDeleteThisAttachment: 'Are you sure you want to delete this attachment?', areYouSureYouWantToDeleteThisAttachment: 'Are you sure you want to delete this attachment?',
areYouSureYouWantToDeleteThisBoard: 'Are you sure you want to delete this board?', areYouSureYouWantToDeleteThisBoard: 'Are you sure you want to delete this board?',
areYouSureYouWantToDeleteThisCard: 'Are you sure you want to delete this card?', areYouSureYouWantToDeleteThisCard: 'Are you sure you want to delete this card?',
areYouSureYouWantToArchiveThisCard: 'Are you sure you want to archive this card?',
areYouSureYouWantToDeleteThisComment: 'Are you sure you want to delete this comment?', areYouSureYouWantToDeleteThisComment: 'Are you sure you want to delete this comment?',
areYouSureYouWantToDeleteThisLabel: 'Are you sure you want to delete this label?', areYouSureYouWantToDeleteThisLabel: 'Are you sure you want to delete this label?',
areYouSureYouWantToDeleteThisList: 'Are you sure you want to delete this list?', areYouSureYouWantToDeleteThisList: 'Are you sure you want to delete this list?',
@ -64,6 +65,7 @@ export default {
deleteAttachment_title: 'Delete Attachment', deleteAttachment_title: 'Delete Attachment',
deleteBoard_title: 'Delete Board', deleteBoard_title: 'Delete Board',
deleteCard_title: 'Delete Card', deleteCard_title: 'Delete Card',
archiveCard_title: 'Archive Card',
deleteComment_title: 'Delete Comment', deleteComment_title: 'Delete Comment',
deleteLabel_title: 'Delete Label', deleteLabel_title: 'Delete Label',
deleteList_title: 'Delete List', deleteList_title: 'Delete List',
@ -181,12 +183,15 @@ export default {
createLabel: 'Create label', createLabel: 'Create label',
createNewLabel: 'Create new label', createNewLabel: 'Create new label',
createProject: 'Create project', createProject: 'Create project',
archive: 'Archive',
delete: 'Delete', delete: 'Delete',
deleteAttachment: 'Delete attachment', deleteAttachment: 'Delete attachment',
deleteAvatar: 'Delete avatar', deleteAvatar: 'Delete avatar',
deleteBoard: 'Delete board', deleteBoard: 'Delete board',
deleteCard: 'Delete card', deleteCard: 'Delete card',
deleteCard_title: 'Delete Card', deleteCard_title: 'Delete Card',
archiveCard_title: 'Archive Card',
archiveCard: 'Archive card',
deleteComment: 'Delete comment', deleteComment: 'Delete comment',
deleteImage: 'Delete image', deleteImage: 'Delete image',
deleteLabel: 'Delete label', deleteLabel: 'Delete label',

@ -28,6 +28,7 @@ export default {
areYouSureYouWantToDeleteThisAttachment: '¿Estás seguro de que quieres borrar este adjunto?', areYouSureYouWantToDeleteThisAttachment: '¿Estás seguro de que quieres borrar este adjunto?',
areYouSureYouWantToDeleteThisBoard: '¿Estás seguro de que quieres borrar este tablero?', areYouSureYouWantToDeleteThisBoard: '¿Estás seguro de que quieres borrar este tablero?',
areYouSureYouWantToDeleteThisCard: '¿Estás seguro de que quieres borrar esta tarjeta?', areYouSureYouWantToDeleteThisCard: '¿Estás seguro de que quieres borrar esta tarjeta?',
areYouSureYouWantToArchiveThisCard: '¿Estás seguro de que quieres archivar esta tarjeta?',
areYouSureYouWantToDeleteThisComment: '¿Estás seguro de que quieres borrar este comentario?', areYouSureYouWantToDeleteThisComment: '¿Estás seguro de que quieres borrar este comentario?',
areYouSureYouWantToDeleteThisLabel: '¿Estás seguro de que quieres borrar esta etiqueta?', areYouSureYouWantToDeleteThisLabel: '¿Estás seguro de que quieres borrar esta etiqueta?',
areYouSureYouWantToDeleteThisList: '¿Estás seguro de que quieres borrar esta lista?', areYouSureYouWantToDeleteThisList: '¿Estás seguro de que quieres borrar esta lista?',
@ -56,6 +57,7 @@ export default {
deleteAttachment_title: 'Eliminar Adjunto', deleteAttachment_title: 'Eliminar Adjunto',
deleteBoard_title: 'Borrar Tablero', deleteBoard_title: 'Borrar Tablero',
deleteCard_title: 'Borrar tarjeta', deleteCard_title: 'Borrar tarjeta',
archiveCard_title: 'Archivar Tarjeta',
deleteComment_title: 'Borrar Comentario', deleteComment_title: 'Borrar Comentario',
deleteLabel_title: 'Borrar Etiqueta', deleteLabel_title: 'Borrar Etiqueta',
deleteList_title: 'Borrar Lista', deleteList_title: 'Borrar Lista',
@ -153,12 +155,15 @@ export default {
createLabel: 'Crear etiqueta', createLabel: 'Crear etiqueta',
createNewLabel: 'Crear una nueva etiqueta', createNewLabel: 'Crear una nueva etiqueta',
createProject: 'Crear proyecto', createProject: 'Crear proyecto',
archive: 'Archivar',
delete: 'Borrar', delete: 'Borrar',
deleteAttachment: 'Borrar adjuntos', deleteAttachment: 'Borrar adjuntos',
deleteAvatar: 'Borrar avatar', deleteAvatar: 'Borrar avatar',
deleteBoard: 'Borrar tablero', deleteBoard: 'Borrar tablero',
deleteCard: 'Borrar tarjeta', deleteCard: 'Borrar tarjeta',
deleteCard_title: 'Borrar tarjeta', deleteCard_title: 'Borrar tarjeta',
archiveCard: 'Archivar tarjeta',
archiveCard_title: 'Archivar Tarjeta',
deleteComment: 'Borrar comentario', deleteComment: 'Borrar comentario',
deleteImage: 'Borrar imagen', deleteImage: 'Borrar imagen',
deleteLabel: 'Borrar etiqueta', deleteLabel: 'Borrar etiqueta',

@ -153,6 +153,7 @@ export default {
createLabel: 'Créer une étiquette', createLabel: 'Créer une étiquette',
createNewLabel: 'Créer une nouvelle étiquette', createNewLabel: 'Créer une nouvelle étiquette',
createProject: 'Créer un projet', createProject: 'Créer un projet',
archive: 'Archiver',
delete: 'Supprimer', delete: 'Supprimer',
deleteAttachment: 'Supprimer la pièce jointe', deleteAttachment: 'Supprimer la pièce jointe',
deleteAvatar: "Supprimer l'avatar", deleteAvatar: "Supprimer l'avatar",

@ -175,6 +175,7 @@ export default {
createLabel: 'Címke létrehozása', createLabel: 'Címke létrehozása',
createNewLabel: 'Új címke létrehozása', createNewLabel: 'Új címke létrehozása',
createProject: 'Projekt létrehozása', createProject: 'Projekt létrehozása',
archive: 'Archiválás',
delete: 'Törlés', delete: 'Törlés',
deleteAttachment: 'Melléklet törlése', deleteAttachment: 'Melléklet törlése',
deleteAvatar: 'Avatar törlése', deleteAvatar: 'Avatar törlése',

@ -185,6 +185,7 @@ export default {
createLabel: 'Tambah label', createLabel: 'Tambah label',
createNewLabel: 'Tambah label baru', createNewLabel: 'Tambah label baru',
createProject: 'Tambah proyek', createProject: 'Tambah proyek',
archive: 'Arsipkan',
delete: 'Hapus', delete: 'Hapus',
deleteAttachment: 'Hapus lampiran', deleteAttachment: 'Hapus lampiran',
deleteAvatar: 'Hapus avatar', deleteAvatar: 'Hapus avatar',

@ -180,6 +180,7 @@ export default {
createLabel: 'Crea etichetta', createLabel: 'Crea etichetta',
createNewLabel: 'Crea nuova etichetta', createNewLabel: 'Crea nuova etichetta',
createProject: 'Crea progetto', createProject: 'Crea progetto',
archive: 'Archiviare',
delete: 'Elimina', delete: 'Elimina',
deleteAttachment: 'Elimina allegato', deleteAttachment: 'Elimina allegato',
deleteAvatar: 'Elimina avatar', deleteAvatar: 'Elimina avatar',

@ -185,6 +185,7 @@ export default {
createLabel: 'ラベルを作成', createLabel: 'ラベルを作成',
createNewLabel: '新しいラベルを作成', createNewLabel: '新しいラベルを作成',
createProject: 'プロジェクトを作成', createProject: 'プロジェクトを作成',
archive: 'アーカイブ',
delete: '削除', delete: '削除',
deleteAttachment: '添付ファイルを削除', deleteAttachment: '添付ファイルを削除',
deleteAvatar: 'アバターを削除', deleteAvatar: 'アバターを削除',

@ -186,6 +186,7 @@ export default {
createLabel: 'Label aanmaken', createLabel: 'Label aanmaken',
createNewLabel: 'Nieuw label aanmaken', createNewLabel: 'Nieuw label aanmaken',
createProject: 'Project aanmaken', createProject: 'Project aanmaken',
archive: 'Archiveren',
delete: 'Verwijderen', delete: 'Verwijderen',
deleteAttachment: 'Bijlage verwijderen', deleteAttachment: 'Bijlage verwijderen',
deleteAvatar: 'Avatar verwijderen', deleteAvatar: 'Avatar verwijderen',

@ -153,6 +153,7 @@ export default {
createLabel: 'Utwórz oznaczenie', createLabel: 'Utwórz oznaczenie',
createNewLabel: 'Utwórz nowe oznaczenie', createNewLabel: 'Utwórz nowe oznaczenie',
createProject: 'Utwórz projekt', createProject: 'Utwórz projekt',
archive: 'Archiwizować',
delete: 'Usuń', delete: 'Usuń',
deleteAttachment: 'Usuń załącznik', deleteAttachment: 'Usuń załącznik',
deleteAvatar: 'Usuń avatar', deleteAvatar: 'Usuń avatar',

@ -30,6 +30,7 @@ export default {
areYouSureYouWantToDeleteThisAttachment: 'Tem certeza de que deseja excluir este anexo?', areYouSureYouWantToDeleteThisAttachment: 'Tem certeza de que deseja excluir este anexo?',
areYouSureYouWantToDeleteThisBoard: 'Tem certeza de que deseja excluir este quadro?', areYouSureYouWantToDeleteThisBoard: 'Tem certeza de que deseja excluir este quadro?',
areYouSureYouWantToDeleteThisCard: 'Tem certeza de que deseja excluir este cartão?', areYouSureYouWantToDeleteThisCard: 'Tem certeza de que deseja excluir este cartão?',
areYouSureYouWantToArchiveThisCard: 'Tem certeza de que deseja arquivar este cartão?',
areYouSureYouWantToDeleteThisComment: 'Tem certeza de que deseja excluir este comentário?', areYouSureYouWantToDeleteThisComment: 'Tem certeza de que deseja excluir este comentário?',
areYouSureYouWantToDeleteThisLabel: 'Tem certeza de que deseja excluir este rótulo?', areYouSureYouWantToDeleteThisLabel: 'Tem certeza de que deseja excluir este rótulo?',
areYouSureYouWantToDeleteThisList: 'Tem certeza de que deseja excluir esta lista?', areYouSureYouWantToDeleteThisList: 'Tem certeza de que deseja excluir esta lista?',
@ -67,6 +68,7 @@ export default {
deleteAttachment_title: 'Excluir Anexo', deleteAttachment_title: 'Excluir Anexo',
deleteBoard_title: 'Excluir Quadro', deleteBoard_title: 'Excluir Quadro',
deleteCard_title: 'Excluir Cartão', deleteCard_title: 'Excluir Cartão',
archiveCard_title: 'Arquivar Cartão',
deleteComment_title: 'Excluir Comentário', deleteComment_title: 'Excluir Comentário',
deleteLabel_title: 'Excluir Rótulo', deleteLabel_title: 'Excluir Rótulo',
deleteList_title: 'Excluir Lista', deleteList_title: 'Excluir Lista',
@ -185,12 +187,15 @@ export default {
createLabel: 'Criar rótulo', createLabel: 'Criar rótulo',
createNewLabel: 'Criar novo rótulo', createNewLabel: 'Criar novo rótulo',
createProject: 'Criar projeto', createProject: 'Criar projeto',
archive: 'Arquivar',
delete: 'Excluir', delete: 'Excluir',
deleteAttachment: 'Excluir anexo', deleteAttachment: 'Excluir anexo',
deleteAvatar: 'Excluir avatar', deleteAvatar: 'Excluir avatar',
deleteBoard: 'Excluir quadro', deleteBoard: 'Excluir quadro',
deleteCard: 'Excluir cartão', deleteCard: 'Excluir cartão',
deleteCard_title: 'Excluir Cartão', deleteCard_title: 'Excluir Cartão',
archiveCard: 'Arquivar cartão',
archiveCard_title: 'Arquivar Cartão',
deleteComment: 'Excluir comentário', deleteComment: 'Excluir comentário',
deleteImage: 'Excluir imagem', deleteImage: 'Excluir imagem',
deleteLabel: 'Excluir rótulo', deleteLabel: 'Excluir rótulo',

@ -186,6 +186,7 @@ export default {
createLabel: 'Creați eticheta', createLabel: 'Creați eticheta',
createNewLabel: 'Creați o nouă etichetă', createNewLabel: 'Creați o nouă etichetă',
createProject: 'Creați proiect', createProject: 'Creați proiect',
archive: 'Arhiva',
delete: 'Ștergeți', delete: 'Ștergeți',
deleteAttachment: 'Ștergeți atașamentul', deleteAttachment: 'Ștergeți atașamentul',
deleteAvatar: 'Ștergeți avatarul', deleteAvatar: 'Ștergeți avatarul',

@ -187,6 +187,7 @@ export default {
createLabel: 'Создать метку', createLabel: 'Создать метку',
createNewLabel: 'Создать новую метку', createNewLabel: 'Создать новую метку',
createProject: 'Создать проект', createProject: 'Создать проект',
archive: 'Архивировать',
delete: 'Удалить', delete: 'Удалить',
deleteAttachment: 'Удалить вложение', deleteAttachment: 'Удалить вложение',
deleteAvatar: 'Удалить аватар', deleteAvatar: 'Удалить аватар',

@ -165,6 +165,7 @@ export default {
createLabel: 'Vytvoriť štítok', createLabel: 'Vytvoriť štítok',
createNewLabel: 'Vytvoriť nový štítok', createNewLabel: 'Vytvoriť nový štítok',
createProject: 'Vytvoriť projekt', createProject: 'Vytvoriť projekt',
archive: 'Archivovať',
delete: 'Zmazať', delete: 'Zmazať',
deleteAttachment: 'Zmazať prílohu', deleteAttachment: 'Zmazať prílohu',
deleteAvatar: 'Zmazať avatar', deleteAvatar: 'Zmazať avatar',

@ -167,6 +167,7 @@ export default {
createLabel: 'Skapa etikett', createLabel: 'Skapa etikett',
createNewLabel: 'Skapa ny etikett', createNewLabel: 'Skapa ny etikett',
createProject: 'Skapa projekt', createProject: 'Skapa projekt',
archive: 'Arkivera',
delete: 'Ta Bort', delete: 'Ta Bort',
deleteAttachment: 'Ta bort bilaga', deleteAttachment: 'Ta bort bilaga',
deleteAvatar: 'Ta bort avatar', deleteAvatar: 'Ta bort avatar',

@ -168,6 +168,7 @@ export default {
createLabel: 'Etiket Oluştur', createLabel: 'Etiket Oluştur',
createNewLabel: 'Yeni etiket oluştur', createNewLabel: 'Yeni etiket oluştur',
createProject: 'Proje oluştur', createProject: 'Proje oluştur',
archive: 'Arşivlemek',
delete: 'Sil', delete: 'Sil',
deleteAttachment: 'Eki sil', deleteAttachment: 'Eki sil',
deleteAvatar: 'Avatarı sil', deleteAvatar: 'Avatarı sil',

@ -181,6 +181,7 @@ export default {
createLabel: 'Створити мітку', createLabel: 'Створити мітку',
createNewLabel: 'Створити нову мітку', createNewLabel: 'Створити нову мітку',
createProject: 'Створити проект', createProject: 'Створити проект',
archive: 'Архівувати',
delete: 'Видалити', delete: 'Видалити',
deleteAttachment: 'Видалити вкладення', deleteAttachment: 'Видалити вкладення',
deleteAvatar: 'Видалити аватар', deleteAvatar: 'Видалити аватар',

@ -160,6 +160,7 @@ export default {
createLabel: 'Yorliq yaratish', createLabel: 'Yorliq yaratish',
createNewLabel: 'Yangi yorliq yaratish', createNewLabel: 'Yangi yorliq yaratish',
createProject: 'Loyiha yaratish', createProject: 'Loyiha yaratish',
archive: 'Arxivlash',
delete: "O'chirish", delete: "O'chirish",
deleteAttachment: "Ilovani o'chirish", deleteAttachment: "Ilovani o'chirish",
deleteAvatar: "Avatarni o'chirish", deleteAvatar: "Avatarni o'chirish",

@ -177,6 +177,7 @@ export default {
createLabel: '创建标签', createLabel: '创建标签',
createNewLabel: '创建新标签', createNewLabel: '创建新标签',
createProject: '创建项目', createProject: '创建项目',
archive: '归档',
delete: '删除', delete: '删除',
deleteAttachment: '删除附件', deleteAttachment: '删除附件',
deleteAvatar: '删除头像', deleteAvatar: '删除头像',

@ -4,7 +4,7 @@ import { attr, fk, many, oneToOne } from 'redux-orm';
import BaseModel from './BaseModel'; import BaseModel from './BaseModel';
import ActionTypes from '../constants/ActionTypes'; import ActionTypes from '../constants/ActionTypes';
import Config from '../constants/Config'; import Config from '../constants/Config';
import { ActivityTypes } from '../constants/Enums'; import { ActivityTypes, CardStatus } from '../constants/Enums';
export default class extends BaseModel { export default class extends BaseModel {
static modelName = 'Card'; static modelName = 'Card';
@ -16,6 +16,9 @@ export default class extends BaseModel {
description: attr(), description: attr(),
dueDate: attr(), dueDate: attr(),
stopwatch: attr(), stopwatch: attr(),
status: attr({
getDefault: () => CardStatus.ACTIVE,
}),
isSubscribed: attr({ isSubscribed: attr({
getDefault: () => false, getDefault: () => false,
}), }),
@ -202,6 +205,7 @@ export default class extends BaseModel {
'listId', 'listId',
'position', 'position',
'name', 'name',
'status',
'description', 'description',
'dueDate', 'dueDate',
'stopwatch', 'stopwatch',
@ -235,9 +239,9 @@ export default class extends BaseModel {
} }
case ActionTypes.CARD_DELETE: case ActionTypes.CARD_DELETE:
Card.withId(payload.id).deleteWithRelated(); Card.withId(payload.id).deleteWithRelated();
break; break;
case ActionTypes.CARD_DELETE__SUCCESS: case ActionTypes.CARD_DELETE__SUCCESS:
case ActionTypes.CARD_ARCHIVE__SUCCESS:
case ActionTypes.CARD_DELETE_HANDLE: { case ActionTypes.CARD_DELETE_HANDLE: {
const cardModel = Card.withId(payload.card.id); const cardModel = Card.withId(payload.card.id);

@ -7,6 +7,7 @@ import actions from '../../../actions';
import api from '../../../api'; import api from '../../../api';
import i18n from '../../../i18n'; import i18n from '../../../i18n';
import { createLocalId } from '../../../utils/local-id'; import { createLocalId } from '../../../utils/local-id';
import { CardStatus } from '../../../constants/Enums';
export function* createCard(listId, data, autoOpen) { export function* createCard(listId, data, autoOpen) {
const { boardId } = yield select(selectors.selectListById, listId); const { boardId } = yield select(selectors.selectListById, listId);
@ -63,7 +64,6 @@ export function* handleCardCreate({ id }) {
export function* updateCard(id, data) { export function* updateCard(id, data) {
yield put(actions.updateCard(id, data)); yield put(actions.updateCard(id, data));
let card; let card;
try { try {
({ item: card } = yield call(request, api.updateCard, id, data)); ({ item: card } = yield call(request, api.updateCard, id, data));
@ -72,6 +72,10 @@ export function* updateCard(id, data) {
return; return;
} }
if ('status' in data && data.status === CardStatus.ARCHIVED) {
yield put(actions.updateCard.archive_success(card));
return;
}
yield put(actions.updateCard.success(card)); yield put(actions.updateCard.success(card));
} }

@ -75,10 +75,10 @@ services:
dockerfile: ../config/development/Dockerfile.server dockerfile: ../config/development/Dockerfile.server
environment: environment:
- DATABASE_URL=postgresql://user:password@postgres:5432/planka_db - DATABASE_URL=postgresql://user:password@postgres:5432/planka_db
# - DEFAULT_ADMIN_EMAIL=demo@demo.demo # Do not remove if you want to prevent this user from being edited/deleted - DEFAULT_ADMIN_EMAIL=admin@robsonvnt.me # Do not remove if you want to prevent this user from being edited/deleted
# - DEFAULT_ADMIN_PASSWORD=demo - DEFAULT_ADMIN_PASSWORD=admin
# - DEFAULT_ADMIN_NAME=Demo Demo - DEFAULT_ADMIN_NAME=Admin
# - DEFAULT_ADMIN_USERNAME=demo - DEFAULT_ADMIN_USERNAME=admin
working_dir: /app working_dir: /app
command: ["sh", "-c", "npm run db:init"] command: ["sh", "-c", "npm run db:init"]

@ -44,6 +44,11 @@ module.exports = {
position: { position: {
type: 'number', type: 'number',
}, },
status: {
type: 'string',
isIn: ['active', 'archived'],
defaultsTo: 'active',
},
name: { name: {
type: 'string', type: 'string',
required: true, required: true,

@ -87,6 +87,10 @@ module.exports = {
isSubscribed: { isSubscribed: {
type: 'boolean', type: 'boolean',
}, },
status: {
type: 'string',
isIn: ['active', 'archived'],
},
}, },
exits: { exits: {
@ -173,6 +177,7 @@ module.exports = {
'dueDate', 'dueDate',
'stopwatch', 'stopwatch',
'isSubscribed', 'isSubscribed',
'status',
]); ]);
card = await sails.helpers.cards.updateOne card = await sails.helpers.cards.updateOne

@ -12,6 +12,7 @@ module.exports = {
async fn(inputs) { async fn(inputs) {
return sails.helpers.cards.getMany({ return sails.helpers.cards.getMany({
boardId: inputs.idOrIds, boardId: inputs.idOrIds,
status: inputs.status || 'active',
}); });
}, },
}; };

@ -28,6 +28,13 @@ module.exports = {
type: 'ref', type: 'ref',
columnName: 'due_date', columnName: 'due_date',
}, },
status: {
type: 'string',
isIn: ['active', 'archived'],
defaultsTo: 'active',
allowNull: false,
description: 'The current status of the card, which can be active or archived.',
},
stopwatch: { stopwatch: {
type: 'json', type: 'json',
}, },

@ -0,0 +1,11 @@
exports.up = async (knex) => {
await knex.schema.table('card', (table) => {
table.enum('status', ['active', 'archived']).defaultTo('active').notNullable();
});
};
exports.down = async (knex) => {
await knex.schema.table('card', (table) => {
table.dropColumn('status');
});
};

@ -7,6 +7,7 @@
"db:init": "node db/init.js", "db:init": "node db/init.js",
"db:migrate": "knex migrate:latest --cwd db", "db:migrate": "knex migrate:latest --cwd db",
"db:seed": "knex seed:run --cwd db", "db:seed": "knex seed:run --cwd db",
"db:create-migration": "knex migrate:make --cwd db",
"lint": "eslint . --max-warnings=0 --report-unused-disable-directives && echo '✔ Your .js files look good.'", "lint": "eslint . --max-warnings=0 --report-unused-disable-directives && echo '✔ Your .js files look good.'",
"start": "nodemon", "start": "nodemon",
"start:prod": "node app.js --prod", "start:prod": "node app.js --prod",

Loading…
Cancel
Save