pull/724/merge
Robson Ventura 2 years ago committed by GitHub
commit fbf04da80a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -1 +1,3 @@
# Planka client # Frontend
The Planka frontend uses a combination of React, Redux, and Saga for state management and side effects, providing a rich and responsive user experience.

@ -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',
@ -182,12 +184,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',
@ -186,12 +188,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"]

@ -1 +1,53 @@
# Planka server # Planka Server Documentation
The backend was developed using the SailsJS framework, which facilitates complex operations in web applications, especially when combined with the Knex database migration manager.
## Modifying the Database Structure
### Creating a Migration
**Step 1:** Navigate to the corresponding folder within the project:
```bash
cd ROOT_PATH/server/db
```
**Step 2:** Execute the following command to create a new migration file:
```bash
npm run db:create-migration add_change_in_the_database_structure
```
This command creates a file in the migration folder named based on the provided argument. The generated file will have the following initial structure:
```Javascript
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.up = function(knex) {
// Add the changes that will be applied to the database
};
/**
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function(knex) {
// Add the changes that will revert the operations done in up
};
```
#### Adapting to Asynchronous Functions:
In the project, asynchronous functions are used by default. Modify the migration file to adhere to this standard:
```Javascript
exports.up = async (knex) => {
// Migration logic to apply changes
};
exports.down = async (knex) => {
// Migration logic to revert changes
};
```
#### Implementation
Implement the necessary logic in the up and down methods to apply or revert changes in the database. To understand how migrations work and explore detailed examples, refer to the [official Knex documentation on migrations](https://knexjs.org/guide/migrations.html#migration-api).

@ -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