1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-08-10 16:05:35 +02:00

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.
This commit is contained in:
Robson Ventura Rodrigues 2024-04-22 13:57:12 -03:00
parent 03825c3bed
commit 60c514b63f
49 changed files with 174 additions and 37 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -4,9 +4,9 @@ import { useTranslation } from 'react-i18next';
import { Button } from 'semantic-ui-react';
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();
return (
@ -24,7 +24,7 @@ const DeleteStep = React.memo(({ title, content, buttonContent, onConfirm, onBac
);
});
DeleteStep.propTypes = {
ConfirmStep.propTypes = {
title: PropTypes.string.isRequired,
content: PropTypes.string.isRequired,
buttonContent: PropTypes.string.isRequired,
@ -32,8 +32,8 @@ DeleteStep.propTypes = {
onBack: PropTypes.func,
};
DeleteStep.defaultProps = {
ConfirmStep.defaultProps = {
onBack: undefined,
};
export default DeleteStep;
export default ConfirmStep;

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -75,10 +75,10 @@ services:
dockerfile: ../config/development/Dockerfile.server
environment:
- 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_PASSWORD=demo
# - DEFAULT_ADMIN_NAME=Demo Demo
# - DEFAULT_ADMIN_USERNAME=demo
- DEFAULT_ADMIN_EMAIL=admin@robsonvnt.me # Do not remove if you want to prevent this user from being edited/deleted
- DEFAULT_ADMIN_PASSWORD=admin
- DEFAULT_ADMIN_NAME=Admin
- DEFAULT_ADMIN_USERNAME=admin
working_dir: /app
command: ["sh", "-c", "npm run db:init"]

View file

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

View file

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

View file

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

View file

@ -28,6 +28,13 @@ module.exports = {
type: 'ref',
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: {
type: 'json',
},

View file

@ -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');
});
};

View file

@ -7,6 +7,7 @@
"db:init": "node db/init.js",
"db:migrate": "knex migrate:latest --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.'",
"start": "nodemon",
"start:prod": "node app.js --prod",