diff --git a/client/src/components/activities/BoardActivitiesModal/Item.jsx b/client/src/components/activities/BoardActivitiesModal/Item.jsx index 35cd0720..049a4253 100755 --- a/client/src/components/activities/BoardActivitiesModal/Item.jsx +++ b/client/src/components/activities/BoardActivitiesModal/Item.jsx @@ -11,8 +11,8 @@ import { Link } from 'react-router-dom'; import { Comment } from 'semantic-ui-react'; import selectors from '../../../selectors'; +import { isUserStatic } from '../../../utils/record-helpers'; import Paths from '../../../constants/Paths'; -import { StaticUserIds } from '../../../constants/StaticUsers'; import { ActivityTypes } from '../../../constants/Enums'; import TimeAgo from '../../common/TimeAgo'; import UserAvatar from '../../users/UserAvatar'; @@ -30,12 +30,11 @@ const Item = React.memo(({ id }) => { const [t] = useTranslation(); - const userName = - user.id === StaticUserIds.DELETED - ? t(`common.${user.name}`, { - context: 'title', - }) - : user.name; + const userName = isUserStatic(user) + ? t(`common.${user.name}`, { + context: 'title', + }) + : user.name; const cardName = card ? card.name : activity.data.card.name; diff --git a/client/src/components/activities/CardActivities/Item.jsx b/client/src/components/activities/CardActivities/Item.jsx index 4a644f2d..d154e055 100755 --- a/client/src/components/activities/CardActivities/Item.jsx +++ b/client/src/components/activities/CardActivities/Item.jsx @@ -10,7 +10,7 @@ import { useTranslation, Trans } from 'react-i18next'; import { Comment } from 'semantic-ui-react'; import selectors from '../../../selectors'; -import { StaticUserIds } from '../../../constants/StaticUsers'; +import { isUserStatic } from '../../../utils/record-helpers'; import { ActivityTypes } from '../../../constants/Enums'; import TimeAgo from '../../common/TimeAgo'; import UserAvatar from '../../users/UserAvatar'; @@ -26,12 +26,11 @@ const Item = React.memo(({ id }) => { const [t] = useTranslation(); - const userName = - user.id === StaticUserIds.DELETED - ? t(`common.${user.name}`, { - context: 'title', - }) - : user.name; + const userName = isUserStatic(user) + ? t(`common.${user.name}`, { + context: 'title', + }) + : user.name; let contentNode; switch (activity.type) { diff --git a/client/src/components/boards/Board/FiniteContent.jsx b/client/src/components/boards/Board/FiniteContent.jsx index 5a5751ec..6dabd0c2 100644 --- a/client/src/components/boards/Board/FiniteContent.jsx +++ b/client/src/components/boards/Board/FiniteContent.jsx @@ -15,13 +15,13 @@ import ListView from './ListView'; const FiniteContent = React.memo(() => { const board = useSelector(selectors.selectCurrentBoard); const cardIds = useSelector(selectors.selectFilteredCardIdsForCurrentBoard); - const hasAnyFiniteList = useSelector((state) => !!selectors.selectFirstFiniteListId(state)); + const canAddCard = useSelector((state) => !!selectors.selectFirstKanbanListId(state)); const dispatch = useDispatch(); const handleCardCreate = useCallback( (data, autoOpen) => { - dispatch(entryActions.createCardInFirstFiniteList(data, undefined, autoOpen)); + dispatch(entryActions.createCardInCurrentContext(data, undefined, autoOpen)); }, [dispatch], ); @@ -39,7 +39,7 @@ const FiniteContent = React.memo(() => { default: } - return ; + return ; }); export default FiniteContent; diff --git a/client/src/components/boards/Board/KanbanContent/KanbanContent.jsx b/client/src/components/boards/Board/KanbanContent/KanbanContent.jsx index bc6e38ef..94a285ed 100755 --- a/client/src/components/boards/Board/KanbanContent/KanbanContent.jsx +++ b/client/src/components/boards/Board/KanbanContent/KanbanContent.jsx @@ -23,7 +23,7 @@ import styles from './KanbanContent.module.scss'; import globalStyles from '../../../../styles.module.scss'; const KanbanContent = React.memo(() => { - const listIds = useSelector(selectors.selectFiniteListIdsForCurrentBoard); + const listIds = useSelector(selectors.selectKanbanListIdsForCurrentBoard); const canAddList = useSelector((state) => { const isEditModeEnabled = selectors.selectIsEditModeEnabled(state); // TODO: move out? diff --git a/client/src/components/cards/Card/Card.module.scss b/client/src/components/cards/Card/Card.module.scss index 4d71b897..a34a8b5e 100644 --- a/client/src/components/cards/Card/Card.module.scss +++ b/client/src/components/cards/Card/Card.module.scss @@ -21,6 +21,7 @@ top: 2px; transition: background 85ms ease; width: 20px; + z-index: 1000; &:hover { background: #ebeef0; @@ -52,6 +53,7 @@ background: #fff; border-radius: 3px; box-shadow: 0 1px 0 #ccc; + overflow: hidden; position: relative; &:hover { diff --git a/client/src/components/cards/CardModal/CreationDetailsStep.jsx b/client/src/components/cards/CardModal/CreationDetailsStep.jsx index 13ab85bd..46d4f869 100644 --- a/client/src/components/cards/CardModal/CreationDetailsStep.jsx +++ b/client/src/components/cards/CardModal/CreationDetailsStep.jsx @@ -10,7 +10,7 @@ import { useTranslation } from 'react-i18next'; import { Icon } from 'semantic-ui-react'; import selectors from '../../../selectors'; -import { StaticUserIds } from '../../../constants/StaticUsers'; +import { isUserStatic } from '../../../utils/record-helpers'; import TimeAgo from '../../common/TimeAgo'; import UserAvatar from '../../users/UserAvatar'; @@ -32,7 +32,7 @@ const CreationDetailsStep = React.memo(({ userId }) => {
- {user.id === StaticUserIds.DELETED + {isUserStatic(user) ? t(`common.${user.name}`, { context: 'title', }) diff --git a/client/src/components/cards/CardModal/StoryContent/StoryContent.jsx b/client/src/components/cards/CardModal/StoryContent.jsx similarity index 94% rename from client/src/components/cards/CardModal/StoryContent/StoryContent.jsx rename to client/src/components/cards/CardModal/StoryContent.jsx index 1665c588..52aa62b3 100644 --- a/client/src/components/cards/CardModal/StoryContent/StoryContent.jsx +++ b/client/src/components/cards/CardModal/StoryContent.jsx @@ -9,32 +9,32 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Gallery, Item as GalleryItem } from 'react-photoswipe-gallery'; import { Button, Grid, Icon } from 'semantic-ui-react'; -import { useDidUpdate } from '../../../../lib/hooks'; +import { useDidUpdate } from '../../../lib/hooks'; -import selectors from '../../../../selectors'; -import entryActions from '../../../../entry-actions'; -import { usePopupInClosableContext } from '../../../../hooks'; -import { isUsableMarkdownElement } from '../../../../utils/element-helpers'; -import { BoardMembershipRoles, CardTypes, ListTypes } from '../../../../constants/Enums'; -import { CardTypeIcons } from '../../../../constants/Icons'; -import { ClosableContext } from '../../../../contexts'; +import selectors from '../../../selectors'; +import entryActions from '../../../entry-actions'; +import { usePopupInClosableContext } from '../../../hooks'; +import { isUsableMarkdownElement } from '../../../utils/element-helpers'; +import { BoardMembershipRoles, CardTypes, ListTypes } from '../../../constants/Enums'; +import { CardTypeIcons } from '../../../constants/Icons'; +import { ClosableContext } from '../../../contexts'; +import NameField from './NameField'; import Thumbnail from './Thumbnail'; -import NameField from '../NameField'; -import CustomFieldGroups from '../CustomFieldGroups'; -import Communication from '../Communication'; -import CreationDetailsStep from '../CreationDetailsStep'; -import MoreActionsStep from '../MoreActionsStep'; -import Markdown from '../../../common/Markdown'; -import EditMarkdown from '../../../common/EditMarkdown'; -import ConfirmationStep from '../../../common/ConfirmationStep'; -import UserAvatar from '../../../users/UserAvatar'; -import BoardMembershipsStep from '../../../board-memberships/BoardMembershipsStep'; -import LabelChip from '../../../labels/LabelChip'; -import LabelsStep from '../../../labels/LabelsStep'; -import ListsStep from '../../../lists/ListsStep'; -import Attachments from '../../../attachments/Attachments'; -import AddAttachmentStep from '../../../attachments/AddAttachmentStep'; -import AddCustomFieldGroupStep from '../../../custom-field-groups/AddCustomFieldGroupStep'; +import CustomFieldGroups from './CustomFieldGroups'; +import Communication from './Communication'; +import CreationDetailsStep from './CreationDetailsStep'; +import MoreActionsStep from './MoreActionsStep'; +import Markdown from '../../common/Markdown'; +import EditMarkdown from '../../common/EditMarkdown'; +import ConfirmationStep from '../../common/ConfirmationStep'; +import UserAvatar from '../../users/UserAvatar'; +import BoardMembershipsStep from '../../board-memberships/BoardMembershipsStep'; +import LabelChip from '../../labels/LabelChip'; +import LabelsStep from '../../labels/LabelsStep'; +import ListsStep from '../../lists/ListsStep'; +import Attachments from '../../attachments/Attachments'; +import AddAttachmentStep from '../../attachments/AddAttachmentStep'; +import AddCustomFieldGroupStep from '../../custom-field-groups/AddCustomFieldGroupStep'; import styles from './StoryContent.module.scss'; diff --git a/client/src/components/cards/CardModal/StoryContent/StoryContent.module.scss b/client/src/components/cards/CardModal/StoryContent.module.scss similarity index 99% rename from client/src/components/cards/CardModal/StoryContent/StoryContent.module.scss rename to client/src/components/cards/CardModal/StoryContent.module.scss index 4aed88f1..a45a9f2a 100644 --- a/client/src/components/cards/CardModal/StoryContent/StoryContent.module.scss +++ b/client/src/components/cards/CardModal/StoryContent.module.scss @@ -99,7 +99,7 @@ } .coverWrapper { - padding-bottom: 20px; + padding-bottom: 10px; } .cursorPointer { @@ -283,7 +283,7 @@ } .moduleWrapperAttachments { - margin-bottom: 20px; + margin-bottom: 10px; } .moreActionsButton { diff --git a/client/src/components/cards/CardModal/StoryContent/index.js b/client/src/components/cards/CardModal/StoryContent/index.js deleted file mode 100644 index df81bba9..00000000 --- a/client/src/components/cards/CardModal/StoryContent/index.js +++ /dev/null @@ -1,8 +0,0 @@ -/*! - * Copyright (c) 2024 PLANKA Software GmbH - * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md - */ - -import StoryContent from './StoryContent'; - -export default StoryContent; diff --git a/client/src/components/cards/CardModal/StoryContent/Thumbnail.jsx b/client/src/components/cards/CardModal/Thumbnail.jsx similarity index 96% rename from client/src/components/cards/CardModal/StoryContent/Thumbnail.jsx rename to client/src/components/cards/CardModal/Thumbnail.jsx index 2c8eef3a..d2a8e3ea 100644 --- a/client/src/components/cards/CardModal/StoryContent/Thumbnail.jsx +++ b/client/src/components/cards/CardModal/Thumbnail.jsx @@ -8,7 +8,7 @@ import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import { Item as GalleryItem } from 'react-photoswipe-gallery'; -import selectors from '../../../../selectors'; +import selectors from '../../../selectors'; import styles from './Thumbnail.module.scss'; diff --git a/client/src/components/cards/CardModal/StoryContent/Thumbnail.module.scss b/client/src/components/cards/CardModal/Thumbnail.module.scss similarity index 100% rename from client/src/components/cards/CardModal/StoryContent/Thumbnail.module.scss rename to client/src/components/cards/CardModal/Thumbnail.module.scss diff --git a/client/src/components/comments/Comments/Item.jsx b/client/src/components/comments/Comments/Item.jsx index 031ba710..56f32139 100755 --- a/client/src/components/comments/Comments/Item.jsx +++ b/client/src/components/comments/Comments/Item.jsx @@ -14,8 +14,7 @@ import { useDidUpdate } from '../../../lib/hooks'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; import { usePopupInClosableContext } from '../../../hooks'; -import { isListArchiveOrTrash } from '../../../utils/record-helpers'; -import { StaticUserIds } from '../../../constants/StaticUsers'; +import { isListArchiveOrTrash, isUserStatic } from '../../../utils/record-helpers'; import { BoardMembershipRoles } from '../../../constants/Enums'; import { ClosableContext } from '../../../contexts'; import Edit from './Edit'; @@ -107,7 +106,7 @@ const Item = React.memo(({ id }) => { ) : (
- {user.id === StaticUserIds.DELETED + {isUserStatic(user) ? t(`common.${user.name}`, { context: 'title', }) diff --git a/client/src/components/common/AdministrationModal/UsersPane/UsersPane.jsx b/client/src/components/common/AdministrationModal/UsersPane/UsersPane.jsx index c9a67af9..5fc04858 100755 --- a/client/src/components/common/AdministrationModal/UsersPane/UsersPane.jsx +++ b/client/src/components/common/AdministrationModal/UsersPane/UsersPane.jsx @@ -17,9 +17,9 @@ import AddStep from './AddStep'; import styles from './UsersPane.module.scss'; const UsersPane = React.memo(() => { + const activeUsersTotal = useSelector(selectors.selectActiveUsersTotal); const activeUsersLimit = useSelector(selectors.selectActiveUsersLimit); const users = useSelector(selectors.selectUsers); - const activeUsersTotal = useSelector(selectors.selectActiveUsersTotal); const canAdd = useSelector((state) => { const oidcBootstrap = selectors.selectOidcBootstrap(state); diff --git a/client/src/components/common/Linkify/Link.jsx b/client/src/components/common/Linkify/Link.jsx index c083fe18..ff1d15c5 100644 --- a/client/src/components/common/Linkify/Link.jsx +++ b/client/src/components/common/Linkify/Link.jsx @@ -12,7 +12,7 @@ import selectors from '../../../selectors'; import matchPaths from '../../../utils/match-paths'; import Paths from '../../../constants/Paths'; -const Linkify = React.memo(({ href, content, stopPropagation, ...props }) => { +const Link = React.memo(({ href, content, stopPropagation, ...props }) => { const selectCardById = useMemo(() => selectors.makeSelectCardById(), []); const url = useMemo(() => { @@ -68,14 +68,14 @@ const Linkify = React.memo(({ href, content, stopPropagation, ...props }) => { ); }); -Linkify.propTypes = { +Link.propTypes = { href: PropTypes.string.isRequired, content: PropTypes.string.isRequired, stopPropagation: PropTypes.bool, }; -Linkify.defaultProps = { +Link.defaultProps = { stopPropagation: false, }; -export default Linkify; +export default Link; diff --git a/client/src/components/notifications/NotificationsStep/Item.jsx b/client/src/components/notifications/NotificationsStep/Item.jsx index 2b4fde7c..1ea0bade 100644 --- a/client/src/components/notifications/NotificationsStep/Item.jsx +++ b/client/src/components/notifications/NotificationsStep/Item.jsx @@ -14,8 +14,8 @@ import { Button } from 'semantic-ui-react'; import selectors from '../../../selectors'; import entryActions from '../../../entry-actions'; import { mentionMarkupToText } from '../../../utils/mentions'; +import { isUserStatic } from '../../../utils/record-helpers'; import Paths from '../../../constants/Paths'; -import { StaticUserIds } from '../../../constants/StaticUsers'; import { NotificationTypes } from '../../../constants/Enums'; import TimeAgo from '../../common/TimeAgo'; import UserAvatar from '../../users/UserAvatar'; @@ -42,12 +42,11 @@ const Item = React.memo(({ id, onClose }) => { dispatch(entryActions.deleteNotification(id)); }, [id, dispatch]); - const creatorUserName = - creatorUser.id === StaticUserIds.DELETED - ? t(`common.${creatorUser.name}`, { - context: 'title', - }) - : creatorUser.name; + const creatorUserName = isUserStatic(creatorUser) + ? t(`common.${creatorUser.name}`, { + context: 'title', + }) + : creatorUser.name; const cardName = card ? card.name : notification.data.card.name; diff --git a/client/src/components/users/UserAvatar/UserAvatar.jsx b/client/src/components/users/UserAvatar/UserAvatar.jsx index 7abd5226..c4881230 100755 --- a/client/src/components/users/UserAvatar/UserAvatar.jsx +++ b/client/src/components/users/UserAvatar/UserAvatar.jsx @@ -13,7 +13,7 @@ import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import selectors from '../../../selectors'; -import { StaticUserIds } from '../../../constants/StaticUsers'; +import { isUserStatic } from '../../../utils/record-helpers'; import styles from './UserAvatar.module.scss'; @@ -62,7 +62,7 @@ const UserAvatar = React.memo( const contentNode = ( ({ }, }); -const createCardInFirstFiniteList = (data, index = 0, autoOpen = false) => ({ - type: EntryActionTypes.CARD_IN_FIRST_FINITE_LIST_CREATE, +const createCardInCurrentContext = (data, index = 0, autoOpen = false) => ({ + type: EntryActionTypes.CARD_IN_CURRENT_CONTEXT_CREATE, payload: { data, index, @@ -180,7 +180,7 @@ export default { fetchCardsInCurrentList, handleCardsUpdate, createCard, - createCardInFirstFiniteList, + createCardInCurrentContext, createCardInCurrentList, handleCardCreate, updateCard, diff --git a/client/src/models/Board.js b/client/src/models/Board.js index 06a70c28..7b1241b4 100755 --- a/client/src/models/Board.js +++ b/client/src/models/Board.js @@ -7,7 +7,7 @@ import { attr, fk, many } from 'redux-orm'; import BaseModel from './BaseModel'; import buildSearchParts from '../utils/build-search-parts'; -import { isListFinite } from '../utils/record-helpers'; +import { isListKanban } from '../utils/record-helpers'; import ActionTypes from '../constants/ActionTypes'; import Config from '../constants/Config'; import { BoardContexts, BoardViews } from '../constants/Enums'; @@ -285,8 +285,8 @@ export default class extends BaseModel { return this.lists.orderBy(['position', 'id.length', 'id']); } - getFiniteListsQuerySet() { - return this.getListsQuerySet().filter((list) => isListFinite(list)); + getKanbanListsQuerySet() { + return this.getListsQuerySet().filter((list) => isListKanban(list)); } getCustomFieldGroupsQuerySet() { @@ -316,7 +316,7 @@ export default class extends BaseModel { } getCardsModelArray() { - return this.getFiniteListsQuerySet() + return this.getKanbanListsQuerySet() .toModelArray() .flatMap((listModel) => listModel.getCardsModelArray()); } diff --git a/client/src/models/List.js b/client/src/models/List.js index b7664347..b9c91db9 100755 --- a/client/src/models/List.js +++ b/client/src/models/List.js @@ -336,13 +336,11 @@ export default class extends BaseModel { return []; } - if (searchRegex) { - cardModels = cardModels.filter( - (cardModel) => - searchRegex.test(cardModel.name) || - (cardModel.description && searchRegex.test(cardModel.description)), - ); - } + cardModels = cardModels.filter( + (cardModel) => + searchRegex.test(cardModel.name) || + (cardModel.description && searchRegex.test(cardModel.description)), + ); } else { const searchParts = buildSearchParts(this.board.search); diff --git a/client/src/sagas/core/services/cards.js b/client/src/sagas/core/services/cards.js index 30553dd4..66d21eae 100644 --- a/client/src/sagas/core/services/cards.js +++ b/client/src/sagas/core/services/cards.js @@ -167,10 +167,10 @@ export function* createCard(listId, data, index, autoOpen) { } } -export function* createCardInFirstFiniteList(data, index, autoOpen) { - const firstFiniteListId = yield select(selectors.selectFirstFiniteListId); +export function* createCardInCurrentContext(data, index, autoOpen) { + const firstKanbanListId = yield select(selectors.selectFirstKanbanListId); - yield call(createCard, firstFiniteListId, data, index, autoOpen); + yield call(createCard, firstKanbanListId, data, index, autoOpen); } export function* createCardInCurrentList(data, autoOpen) { @@ -601,7 +601,7 @@ export default { fetchCardsInCurrentList, handleCardsUpdate, createCard, - createCardInFirstFiniteList, + createCardInCurrentContext, createCardInCurrentList, handleCardCreate, updateCard, diff --git a/client/src/sagas/core/watchers/cards.js b/client/src/sagas/core/watchers/cards.js index c89dfa5b..4cbc438c 100644 --- a/client/src/sagas/core/watchers/cards.js +++ b/client/src/sagas/core/watchers/cards.js @@ -20,9 +20,9 @@ export default function* cardsWatchers() { services.createCard(listId, data, index, autoOpen), ), takeEvery( - EntryActionTypes.CARD_IN_FIRST_FINITE_LIST_CREATE, + EntryActionTypes.CARD_IN_CURRENT_CONTEXT_CREATE, ({ payload: { data, index, autoOpen } }) => - services.createCardInFirstFiniteList(data, index, autoOpen), + services.createCardInCurrentContext(data, index, autoOpen), ), takeEvery(EntryActionTypes.CARD_IN_CURRENT_LIST_CREATE, ({ payload: { data, autoOpen } }) => services.createCardInCurrentList(data, autoOpen), diff --git a/client/src/selectors/boards.js b/client/src/selectors/boards.js index c2fb2bb6..4d038494 100644 --- a/client/src/selectors/boards.js +++ b/client/src/selectors/boards.js @@ -271,7 +271,7 @@ export const selectTrashListIdForCurrentBoard = createSelector( }, ); -export const selectFiniteListIdsForCurrentBoard = createSelector( +export const selectKanbanListIdsForCurrentBoard = createSelector( orm, (state) => selectPath(state).boardId, ({ Board }, id) => { @@ -286,7 +286,7 @@ export const selectFiniteListIdsForCurrentBoard = createSelector( } return boardModel - .getFiniteListsQuerySet() + .getKanbanListsQuerySet() .toRefArray() .map((list) => list.id); }, @@ -482,7 +482,7 @@ export default { selectLabelsForCurrentBoard, selectArchiveListIdForCurrentBoard, selectTrashListIdForCurrentBoard, - selectFiniteListIdsForCurrentBoard, + selectKanbanListIdsForCurrentBoard, selectAvailableListsForCurrentBoard, selectCardsExceptCurrentForCurrentBoard, selectFilteredCardIdsForCurrentBoard, diff --git a/client/src/selectors/lists.js b/client/src/selectors/lists.js index 633bfe03..098259bf 100644 --- a/client/src/selectors/lists.js +++ b/client/src/selectors/lists.js @@ -127,7 +127,7 @@ export const selectCurrentList = createSelector( }, ); -export const selectFirstFiniteListId = createSelector( +export const selectFirstKanbanListId = createSelector( orm, (state) => selectPath(state).boardId, ({ Board }, id) => { @@ -141,7 +141,7 @@ export const selectFirstFiniteListId = createSelector( return boardModel; } - const listModel = boardModel.getFiniteListsQuerySet().first(); + const listModel = boardModel.getKanbanListsQuerySet().first(); return listModel && listModel.id; }, ); @@ -174,6 +174,6 @@ export default { selectIsListWithIdAvailableForCurrentUser, selectCurrentListId, selectCurrentList, - selectFirstFiniteListId, + selectFirstKanbanListId, selectFilteredCardIdsForCurrentList, }; diff --git a/client/src/selectors/positioning.js b/client/src/selectors/positioning.js index 77c122d4..58e8f906 100755 --- a/client/src/selectors/positioning.js +++ b/client/src/selectors/positioning.js @@ -75,7 +75,7 @@ export const selectNextListPosition = createSelector( return boardModel; } - return nextPosition(boardModel.getFiniteListsQuerySet().toRefArray(), index, excludedId); + return nextPosition(boardModel.getKanbanListsQuerySet().toRefArray(), index, excludedId); }, ); diff --git a/client/src/utils/record-helpers.js b/client/src/utils/record-helpers.js index 843d7939..51454aee 100644 --- a/client/src/utils/record-helpers.js +++ b/client/src/utils/record-helpers.js @@ -3,8 +3,11 @@ * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md */ +import { StaticUserIds } from '../constants/StaticUsers'; import { ListTypes, UserRoles } from '../constants/Enums'; +export const isUserStatic = (user) => [StaticUserIds.DELETED].includes(user.id); + export const isUserAdminOrProjectOwner = (user) => [UserRoles.ADMIN, UserRoles.PROJECT_OWNER].includes(user.role); @@ -12,3 +15,5 @@ export const isListArchiveOrTrash = (list) => [ListTypes.ARCHIVE, ListTypes.TRASH].includes(list.type); export const isListFinite = (list) => [ListTypes.ACTIVE, ListTypes.CLOSED].includes(list.type); + +export const isListKanban = (list) => [ListTypes.ACTIVE, ListTypes.CLOSED].includes(list.type); diff --git a/client/src/utils/validator.js b/client/src/utils/validator.js index 787fd9a7..4e7c202c 100644 --- a/client/src/utils/validator.js +++ b/client/src/utils/validator.js @@ -11,6 +11,7 @@ const USERNAME_REGEX = /^[a-zA-Z0-9]+((_|\.)?[a-zA-Z0-9])*$/; export const isUrl = (string) => isURL(string, { protocols: ['http', 'https'], + require_tld: false, require_protocol: true, max_allowed_length: 2048, }); diff --git a/server/api/controllers/cards/index.js b/server/api/controllers/cards/index.js index ed46e7a4..51299bf5 100644 --- a/server/api/controllers/cards/index.js +++ b/server/api/controllers/cards/index.js @@ -23,10 +23,10 @@ * - name: before * in: query * required: false - * description: Pagination cursor (JSON object with id and listChangedAt) + * description: Pagination cursor (JSON object with listChangedAt and id) * schema: * type: string - * example: '{"id": "1357158568008091269", "listChangedAt": "2024-01-01T00:00:00.000Z"}' + * example: '{"listChangedAt": "2024-01-01T00:00:00.000Z", "id": "1357158568008091269"}' * - name: search * in: query * required: false diff --git a/server/api/controllers/lists/create.js b/server/api/controllers/lists/create.js index 63f656d4..0c76f466 100755 --- a/server/api/controllers/lists/create.js +++ b/server/api/controllers/lists/create.js @@ -87,7 +87,7 @@ module.exports = { }, type: { type: 'string', - isIn: List.FINITE_TYPES, + isIn: List.KANBAN_TYPES, required: true, }, position: { diff --git a/server/api/controllers/lists/delete.js b/server/api/controllers/lists/delete.js index e0e0f98a..25682288 100755 --- a/server/api/controllers/lists/delete.js +++ b/server/api/controllers/lists/delete.js @@ -100,7 +100,7 @@ module.exports = { throw Errors.LIST_NOT_FOUND; // Forbidden } - if (!sails.helpers.lists.isFinite(list)) { + if (!sails.helpers.lists.isKanban(list)) { throw Errors.NOT_ENOUGH_RIGHTS; } diff --git a/server/api/controllers/lists/update.js b/server/api/controllers/lists/update.js index c4dd7c37..756a8038 100755 --- a/server/api/controllers/lists/update.js +++ b/server/api/controllers/lists/update.js @@ -97,7 +97,7 @@ module.exports = { boardId: idInput, type: { type: 'string', - isIn: List.FINITE_TYPES, + isIn: List.KANBAN_TYPES, }, position: { type: 'number', @@ -146,7 +146,7 @@ module.exports = { throw Errors.LIST_NOT_FOUND; // Forbidden } - if (!sails.helpers.lists.isFinite(list)) { + if (!sails.helpers.lists.isKanban(list)) { throw Errors.NOT_ENOUGH_RIGHTS; } diff --git a/server/api/controllers/users/index.js b/server/api/controllers/users/index.js index dff38c51..a4359502 100755 --- a/server/api/controllers/users/index.js +++ b/server/api/controllers/users/index.js @@ -14,7 +14,7 @@ * operationId: getUsers * responses: * 200: - * description: List of users retrieved successfully + * description: Users retrieved successfully * content: * application/json: * schema: diff --git a/server/api/controllers/webhooks/index.js b/server/api/controllers/webhooks/index.js index 6f360cc9..e8fd8bc0 100644 --- a/server/api/controllers/webhooks/index.js +++ b/server/api/controllers/webhooks/index.js @@ -14,7 +14,7 @@ * operationId: getWebhooks * responses: * 200: - * description: List of webhooks retrieved successfully + * description: Webhooks retrieved successfully * content: * application/json: * schema: diff --git a/server/api/helpers/actions/create-one.js b/server/api/helpers/actions/create-one.js index bf7bff92..6b0b6705 100644 --- a/server/api/helpers/actions/create-one.js +++ b/server/api/helpers/actions/create-one.js @@ -23,7 +23,7 @@ const buildBodyByFormat = (board, card, action, actorUser, t) => { switch (action.type) { case Action.Types.CREATE_CARD: { - const listName = sails.helpers.lists.makeName(action.data.list); + const listName = sails.helpers.lists.resolveName(action.data.list, t); return { text: t('%s created %s in %s on %s', actorUser.name, card.name, listName, board.name), @@ -44,8 +44,8 @@ const buildBodyByFormat = (board, card, action, actorUser, t) => { }; } case Action.Types.MOVE_CARD: { - const fromListName = sails.helpers.lists.makeName(action.data.fromList); - const toListName = sails.helpers.lists.makeName(action.data.toList); + const fromListName = sails.helpers.lists.resolveName(action.data.fromList, t); + const toListName = sails.helpers.lists.resolveName(action.data.toList, t); return { text: t( diff --git a/server/api/helpers/boards/get-finite-lists-by-id.js b/server/api/helpers/boards/get-kanban-lists-by-id.js similarity index 91% rename from server/api/helpers/boards/get-finite-lists-by-id.js rename to server/api/helpers/boards/get-kanban-lists-by-id.js index 247a0034..3cda338c 100644 --- a/server/api/helpers/boards/get-finite-lists-by-id.js +++ b/server/api/helpers/boards/get-kanban-lists-by-id.js @@ -17,7 +17,7 @@ module.exports = { async fn(inputs) { return List.qm.getByBoardId(inputs.id, { exceptIdOrIds: inputs.exceptListIdOrIds, - typeOrTypes: List.FINITE_TYPES, + typeOrTypes: List.KANBAN_TYPES, }); }, }; diff --git a/server/api/helpers/cards/duplicate-one.js b/server/api/helpers/cards/duplicate-one.js index a6a4d7b2..1fe6bb9f 100644 --- a/server/api/helpers/cards/duplicate-one.js +++ b/server/api/helpers/cards/duplicate-one.js @@ -41,12 +41,26 @@ module.exports = { async fn(inputs) { const { values } = inputs; - if (sails.helpers.lists.isFinite(inputs.list)) { + if (values.list) { + const typeState = List.TYPE_STATE_BY_TYPE[values.list.type]; + + if (inputs.record.isClosed) { + if (typeState === List.TypeStates.OPENED) { + values.isClosed = false; + } + } else if (typeState === List.TypeStates.CLOSED) { + values.isClosed = true; + } + } + + const list = values.list || inputs.list; + + if (sails.helpers.lists.isFinite(list)) { if (_.isUndefined(values.position)) { throw 'positionMustBeInValues'; } - const cards = await Card.qm.getByListId(inputs.list.id); + const cards = await Card.qm.getByListId(list.id); const { position, repositions } = sails.helpers.utils.insertToPositionables( values.position, @@ -84,7 +98,6 @@ module.exports = { let card = await Card.qm.createOne({ ..._.pick(inputs.record, [ 'boardId', - 'listId', 'prevListId', 'type', 'name', @@ -95,6 +108,7 @@ module.exports = { 'isClosed', ]), ...values, + listId: list.id, creatorUserId: values.creatorUser.id, listChangedAt: new Date().toISOString(), }); @@ -240,7 +254,7 @@ module.exports = { included: { projects: [inputs.project], boards: [inputs.board], - lists: [inputs.list], + lists: [list], cardMemberships: nextCardMemberships, cardLabels: nextCardLabels, taskLists: nextTaskLists, @@ -277,19 +291,19 @@ module.exports = { } await sails.helpers.actions.createOne.with({ + list, webhooks, values: { card, type: Action.Types.CREATE_CARD, // TODO: introduce separate type? data: { card: _.pick(card, ['name']), - list: _.pick(inputs.list, ['id', 'type', 'name']), + list: _.pick(list, ['id', 'type', 'name']), }, user: values.creatorUser, }, project: inputs.project, board: inputs.board, - list: inputs.list, }); return { diff --git a/server/api/helpers/lists/create-one.js b/server/api/helpers/lists/create-one.js index 04913022..cf03b0cd 100644 --- a/server/api/helpers/lists/create-one.js +++ b/server/api/helpers/lists/create-one.js @@ -25,7 +25,7 @@ module.exports = { async fn(inputs) { const { values } = inputs; - const lists = await sails.helpers.boards.getFiniteListsById(values.board.id); + const lists = await sails.helpers.boards.getKanbanListsById(values.board.id); const { position, repositions } = sails.helpers.utils.insertToPositionables( values.position, diff --git a/server/api/helpers/lists/make-name.js b/server/api/helpers/lists/is-kanban.js similarity index 77% rename from server/api/helpers/lists/make-name.js rename to server/api/helpers/lists/is-kanban.js index 6a1efb3a..f90d07fc 100644 --- a/server/api/helpers/lists/make-name.js +++ b/server/api/helpers/lists/is-kanban.js @@ -3,7 +3,6 @@ * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md */ -// TODO: rename? module.exports = { sync: true, @@ -15,6 +14,6 @@ module.exports = { }, fn(inputs) { - return inputs.record.name || _.upperFirst(inputs.record.type); + return List.KANBAN_TYPES.includes(inputs.record.type); }, }; diff --git a/server/api/helpers/lists/resolve-name.js b/server/api/helpers/lists/resolve-name.js new file mode 100644 index 00000000..a292ec14 --- /dev/null +++ b/server/api/helpers/lists/resolve-name.js @@ -0,0 +1,27 @@ +/*! + * Copyright (c) 2024 PLANKA Software GmbH + * Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md + */ + +module.exports = { + sync: true, + + inputs: { + record: { + type: 'ref', + required: true, + }, + t: { + type: 'ref', + }, + }, + + fn(inputs) { + if (inputs.record.name) { + return inputs.record.name; + } + + const name = _.upperFirst(inputs.record.type); + return inputs.t ? inputs.t(name) : name; + }, +}; diff --git a/server/api/helpers/lists/update-one.js b/server/api/helpers/lists/update-one.js index 1f8a3f3e..4d75972d 100644 --- a/server/api/helpers/lists/update-one.js +++ b/server/api/helpers/lists/update-one.js @@ -58,7 +58,7 @@ module.exports = { const board = values.board || inputs.board; if (!_.isUndefined(values.position)) { - const lists = await sails.helpers.boards.getFiniteListsById(board.id, inputs.record.id); + const lists = await sails.helpers.boards.getKanbanListsById(board.id, inputs.record.id); const { position, repositions } = sails.helpers.utils.insertToPositionables( values.position, diff --git a/server/api/helpers/notifications/create-many.js b/server/api/helpers/notifications/create-many.js index 3af6dd16..42fca744 100644 --- a/server/api/helpers/notifications/create-many.js +++ b/server/api/helpers/notifications/create-many.js @@ -29,8 +29,8 @@ const buildBodyByFormat = (board, card, notification, actorUser, t) => { switch (notification.type) { case Notification.Types.MOVE_CARD: { - const fromListName = sails.helpers.lists.makeName(notification.data.fromList); - const toListName = sails.helpers.lists.makeName(notification.data.toList); + const fromListName = sails.helpers.lists.resolveName(notification.data.fromList, t); + const toListName = sails.helpers.lists.resolveName(notification.data.toList, t); return { text: t( @@ -144,8 +144,8 @@ const buildEmail = (board, card, notification, actorUser, notifiableUser, t) => let html; switch (notification.type) { case Notification.Types.MOVE_CARD: { - const fromListName = sails.helpers.lists.makeName(notification.data.fromList); - const toListName = sails.helpers.lists.makeName(notification.data.toList); + const fromListName = sails.helpers.lists.resolveName(notification.data.fromList, t); + const toListName = sails.helpers.lists.resolveName(notification.data.toList, t); html = `

${t( '%s moved %s from %s to %s on %s', @@ -243,10 +243,6 @@ module.exports = { arrayOfValues.map((values) => { const id = ids.shift(); - const isCommentRelated = - values.type === Notification.Types.COMMENT_CARD || - values.type === Notification.Types.MENTION_IN_COMMENT; - const nextValues = { ...values, id, @@ -254,10 +250,10 @@ module.exports = { boardId: values.card.boardId, cardId: values.card.id, }; - - if (isCommentRelated) { + if (values.comment) { nextValues.commentId = values.comment.id; - } else { + } + if (values.action) { nextValues.actionId = values.action.id; } diff --git a/server/api/helpers/notifications/create-one.js b/server/api/helpers/notifications/create-one.js index 25505492..f4b16c04 100644 --- a/server/api/helpers/notifications/create-one.js +++ b/server/api/helpers/notifications/create-one.js @@ -29,8 +29,8 @@ const buildBodyByFormat = (board, card, notification, actorUser, t) => { switch (notification.type) { case Notification.Types.MOVE_CARD: { - const fromListName = sails.helpers.lists.makeName(notification.data.fromList); - const toListName = sails.helpers.lists.makeName(notification.data.toList); + const fromListName = sails.helpers.lists.resolveName(notification.data.fromList, t); + const toListName = sails.helpers.lists.resolveName(notification.data.toList, t); return { text: t( @@ -152,8 +152,8 @@ const buildAndSendEmail = async ( let html; switch (notification.type) { case Notification.Types.MOVE_CARD: { - const fromListName = sails.helpers.lists.makeName(notification.data.fromList); - const toListName = sails.helpers.lists.makeName(notification.data.toList); + const fromListName = sails.helpers.lists.resolveName(notification.data.fromList, t); + const toListName = sails.helpers.lists.resolveName(notification.data.toList, t); html = `

${t( '%s moved %s from %s to %s on %s', @@ -234,13 +234,11 @@ module.exports = { async fn(inputs) { const { values } = inputs; - const isCommentRelated = - values.type === Notification.Types.COMMENT_CARD || - values.type === Notification.Types.MENTION_IN_COMMENT; - - if (isCommentRelated) { + if (values.comment) { values.commentId = values.comment.id; - } else { + } + + if (values.action) { values.actionId = values.action.id; } @@ -268,13 +266,12 @@ module.exports = { boards: [inputs.board], lists: [inputs.list], cards: [values.card], - ...(isCommentRelated - ? { - comments: [values.comment], - } - : { - actions: [values.action], - }), + ...(values.comment && { + comments: [values.comment], + }), + ...(values.action && { + actions: [values.action], + }), }, }), user: values.creatorUser, diff --git a/server/api/helpers/users/get-all-ids.js b/server/api/helpers/users/get-all-ids.js index 4ad65827..bcad7364 100644 --- a/server/api/helpers/users/get-all-ids.js +++ b/server/api/helpers/users/get-all-ids.js @@ -7,6 +7,7 @@ module.exports = { inputs: { roleOrRoles: { type: 'json', + required: true, }, }, diff --git a/server/api/hooks/query-methods/models/Card.js b/server/api/hooks/query-methods/models/Card.js index 09c1eb9c..e7f52948 100644 --- a/server/api/hooks/query-methods/models/Card.js +++ b/server/api/hooks/query-methods/models/Card.js @@ -56,19 +56,12 @@ const getIdsByEndlessListId = async ( const searchParts = buildSearchParts(search); if (searchParts.length > 0) { - let ilikeValues = searchParts.map((searchPart) => { + const ilikeValues = searchParts.map((searchPart) => { queryValues.push(searchPart); return `'%' || $${queryValues.length} || '%'`; }); - query += ` AND ((card.name ILIKE ALL(ARRAY[${ilikeValues.join(', ')}]))`; - - ilikeValues = searchParts.map((searchPart) => { - queryValues.push(searchPart); - return `'%' || $${queryValues.length} || '%'`; - }); - - query += ` OR (card.description ILIKE ALL(ARRAY[${ilikeValues.join(', ')}])))`; + query += ` AND ((card.name ILIKE ALL(ARRAY[${ilikeValues.join(', ')}])) OR (card.description ILIKE ALL(ARRAY[${ilikeValues.join(', ')}])))`; } } } diff --git a/server/api/models/List.js b/server/api/models/List.js index ca103dd7..a81d550a 100755 --- a/server/api/models/List.js +++ b/server/api/models/List.js @@ -95,6 +95,8 @@ const SortOrders = { const FINITE_TYPES = [Types.ACTIVE, Types.CLOSED]; +const KANBAN_TYPES = [Types.ACTIVE, Types.CLOSED]; + const TYPE_STATE_BY_TYPE = { [Types.ACTIVE]: TypeStates.OPENED, [Types.CLOSED]: Types.CLOSED, @@ -119,6 +121,7 @@ module.exports = { SortFieldNames, SortOrders, FINITE_TYPES, + KANBAN_TYPES, TYPE_STATE_BY_TYPE, COLORS, diff --git a/server/config/locales/ar-YE.json b/server/config/locales/ar-YE.json index d13d04a7..f20dd4df 100644 --- a/server/config/locales/ar-YE.json +++ b/server/config/locales/ar-YE.json @@ -1,4 +1,5 @@ { + "Archive": "أرشيف", "Card Created": "تم إنشاء البطاقة", "Card Moved": "تم نقل البطاقة", "New Comment": "تعليق جديد", @@ -6,6 +7,7 @@ "This is a test text message!": "هذه رسالة نصية تجريبية!", "This is a *test* **markdown** `message`!": "هذه *رسالة* **markdown** `تجريبية`!", "This is a test html message!": "هذه رسالة html تجريبية!", + "Trash": "سلة المهملات", "You Were Added to Card": "تمت إضافتك إلى البطاقة", "You Were Mentioned in Comment": "تم ذكرك في تعليق", "%s added you to %s on %s": "%s أضافك إلى %s في %s", diff --git a/server/config/locales/bg-BG.json b/server/config/locales/bg-BG.json index a6150f80..27f8ebe9 100644 --- a/server/config/locales/bg-BG.json +++ b/server/config/locales/bg-BG.json @@ -1,4 +1,5 @@ { + "Archive": "Архив", "Card Created": "Картата е създадена", "Card Moved": "Картата е преместена", "New Comment": "Нов коментар", @@ -6,6 +7,7 @@ "This is a test text message!": "Това е тестово текстово съобщение!", "This is a *test* **markdown** `message`!": "Това е *тестово* **markdown** `съобщение`!", "This is a test html message!": "Това е тестово html съобщение!", + "Trash": "Кошче", "You Were Added to Card": "Бяхте добавени към картата", "You Were Mentioned in Comment": "Бяхте споменати в коментар", "%s added you to %s on %s": "%s ви добави към %s на %s", diff --git a/server/config/locales/ca-ES.json b/server/config/locales/ca-ES.json index db59f100..5f17959d 100644 --- a/server/config/locales/ca-ES.json +++ b/server/config/locales/ca-ES.json @@ -1,4 +1,5 @@ { + "Archive": "Arxivar", "Card Created": "Targeta creada", "Card Moved": "Targeta moguda", "New Comment": "Comentari nou", @@ -6,6 +7,7 @@ "This is a test text message!": "Aquest és un missatge de text de prova!", "This is a *test* **markdown** `message`!": "Aquest és un *missatge* **markdown** `de prova`!", "This is a test html message!": "Aquest és un missatge html de prova!", + "Trash": "Paperera", "You Were Added to Card": "Has estat afegit a la targeta", "You Were Mentioned in Comment": "Has estat mencionat en un comentari", "%s added you to %s on %s": "%s t'ha afegit a %s el %s", diff --git a/server/config/locales/cs-CZ.json b/server/config/locales/cs-CZ.json index 1ae03041..b869dab4 100644 --- a/server/config/locales/cs-CZ.json +++ b/server/config/locales/cs-CZ.json @@ -1,4 +1,5 @@ { + "Archive": "Archiv", "Card Created": "Karta vytvořena", "Card Moved": "Karta přesunuta", "New Comment": "Nový komentář", @@ -6,6 +7,7 @@ "This is a test text message!": "Toto je testovací textová zpráva!", "This is a *test* **markdown** `message`!": "Toto je *testovací* **markdown** `zpráva`!", "This is a test html message!": "Toto je testovací html zpráva!", + "Trash": "Koš", "You Were Added to Card": "Byli jste přidáni ke kartě", "You Were Mentioned in Comment": "Byli jste zmíněni v komentáři", "%s added you to %s on %s": "%s vás přidal k %s dne %s", diff --git a/server/config/locales/da-DK.json b/server/config/locales/da-DK.json index 69b3fcbd..71dc0629 100644 --- a/server/config/locales/da-DK.json +++ b/server/config/locales/da-DK.json @@ -1,4 +1,5 @@ { + "Archive": "Arkiv", "Card Created": "Kort oprettet", "Card Moved": "Kort flyttet", "New Comment": "Ny kommentar", @@ -6,6 +7,7 @@ "This is a test text message!": "Dette er en test tekstbesked!", "This is a *test* **markdown** `message`!": "Dette er en *test* **markdown** `besked`!", "This is a test html message!": "Dette er en test html besked!", + "Trash": "Papirkurv", "You Were Added to Card": "Du blev tilføjet til kortet", "You Were Mentioned in Comment": "Du blev nævnt i en kommentar", "%s added you to %s on %s": "%s tilføjede dig til %s den %s", diff --git a/server/config/locales/de-DE.json b/server/config/locales/de-DE.json index d54252ef..82f120a5 100644 --- a/server/config/locales/de-DE.json +++ b/server/config/locales/de-DE.json @@ -1,4 +1,5 @@ { + "Archive": "Archiv", "Card Created": "Karte erstellt", "Card Moved": "Karte verschoben", "New Comment": "Neuer Kommentar", @@ -6,6 +7,7 @@ "This is a test text message!": "Dies ist eine Test-Textnachricht!", "This is a *test* **markdown** `message`!": "Dies ist eine *Test*-**Markdown**-`Nachricht`!", "This is a test html message!": "Dies ist eine Test-HTML-Nachricht!", + "Trash": "Papierkorb", "You Were Added to Card": "Sie wurden zur Karte hinzugefügt", "You Were Mentioned in Comment": "Sie wurden in einem Kommentar erwähnt", "%s added you to %s on %s": "%s hat Sie zu %s am %s hinzugefügt", diff --git a/server/config/locales/el-GR.json b/server/config/locales/el-GR.json index a47964a2..e81cc220 100644 --- a/server/config/locales/el-GR.json +++ b/server/config/locales/el-GR.json @@ -1,4 +1,5 @@ { + "Archive": "Αρχείο", "Card Created": "Η κάρτα δημιουργήθηκε", "Card Moved": "Η κάρτα μετακινήθηκε", "New Comment": "Νέο σχόλιο", @@ -6,6 +7,7 @@ "This is a test text message!": "Αυτό είναι ένα δοκιμαστικό μήνυμα!", "This is a *test* **markdown** `message`!": "Αυτό είναι ένα *δοκιμαστικό* **markdown** `μήνυμα`!", "This is a test html message!": "Αυτό είναι ένα δοκιμαστικό html μήνυμα!", + "Trash": "Κάδος απορριμμάτων", "You Were Added to Card": "Προστέθηκες στην κάρτα", "You Were Mentioned in Comment": "Αναφέρθηκες σε σχόλιο", "%s added you to %s on %s": "%s σε πρόσθεσε στο %s στο %s", diff --git a/server/config/locales/en-GB.json b/server/config/locales/en-GB.json index 935cf7a9..0434cc38 100644 --- a/server/config/locales/en-GB.json +++ b/server/config/locales/en-GB.json @@ -1,4 +1,5 @@ { + "Archive": "Archive", "Card Created": "Card Created", "Card Moved": "Card Moved", "New Comment": "New Comment", @@ -6,6 +7,7 @@ "This is a test text message!": "This is a test text message!", "This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!", "This is a test html message!": "This is a test html message!", + "Trash": "Trash", "You Were Added to Card": "You Were Added to Card", "You Were Mentioned in Comment": "You Were Mentioned in Comment", "%s added you to %s on %s": "%s added you to %s on %s", diff --git a/server/config/locales/en-US.json b/server/config/locales/en-US.json index 8c2e8d73..6b43f324 100644 --- a/server/config/locales/en-US.json +++ b/server/config/locales/en-US.json @@ -1,4 +1,5 @@ { + "Archive": "Archive", "Card Created": "Card Created", "Card Moved": "Card Moved", "New Comment": "New Comment", @@ -6,6 +7,7 @@ "This is a test text message!": "This is a test text message!", "This is a *test* **markdown** `message`!": "This is a *test* **markdown** `message`!", "This is a test html message!": "This is a test html message!", + "Trash": "Trash", "You Were Added to Card": "You Were Added to Card", "You Were Mentioned in Comment": "You Were Mentioned in Comment", "%s added you to %s on %s": "%s added you to %s on %s", diff --git a/server/config/locales/es-ES.json b/server/config/locales/es-ES.json index f3bfc152..16417dc4 100644 --- a/server/config/locales/es-ES.json +++ b/server/config/locales/es-ES.json @@ -1,4 +1,5 @@ { + "Archive": "Archivo", "Card Created": "Tarjeta creada", "Card Moved": "Tarjeta movida", "New Comment": "Nuevo comentario", @@ -6,6 +7,7 @@ "This is a test text message!": "¡Este es un mensaje de texto de prueba!", "This is a *test* **markdown** `message`!": "¡Este es un *mensaje* **markdown** `de prueba`!", "This is a test html message!": "¡Este es un mensaje html de prueba!", + "Trash": "Papelera", "You Were Added to Card": "Fuiste añadido a la tarjeta", "You Were Mentioned in Comment": "Fuiste mencionado en un comentario", "%s added you to %s on %s": "%s te añadió a %s en %s", diff --git a/server/config/locales/et-EE.json b/server/config/locales/et-EE.json index c4021a83..7f3060f4 100644 --- a/server/config/locales/et-EE.json +++ b/server/config/locales/et-EE.json @@ -1,4 +1,5 @@ { + "Archive": "Arhiiv", "Card Created": "Kaart loodud", "Card Moved": "Kaart liigutatud", "New Comment": "Uus kommentaar", @@ -6,6 +7,7 @@ "This is a test text message!": "See on testi tekstisõnum!", "This is a *test* **markdown** `message`!": "See on *testi* **markdown** `sõnum`!", "This is a test html message!": "See on testi html sõnum!", + "Trash": "Prügikast", "You Were Added to Card": "Teid lisati kaardile", "You Were Mentioned in Comment": "Teid mainiti kommentaaris", "%s added you to %s on %s": "%s lisas teid %s-le %s", diff --git a/server/config/locales/fa-IR.json b/server/config/locales/fa-IR.json index b94fa66c..484837d9 100644 --- a/server/config/locales/fa-IR.json +++ b/server/config/locales/fa-IR.json @@ -1,4 +1,5 @@ { + "Archive": "بایگانی", "Card Created": "کارت ایجاد شد", "Card Moved": "کارت منتقل شد", "New Comment": "نظر جدید", @@ -6,6 +7,7 @@ "This is a test text message!": "این یک پیام متنی آزمایشی است!", "This is a *test* **markdown** `message`!": "این یک *پیام* **markdown** `آزمایشی` است!", "This is a test html message!": "این یک پیام html آزمایشی است!", + "Trash": "سطل زباله", "You Were Added to Card": "شما به کارت اضافه شدید", "You Were Mentioned in Comment": "در نظری از شما نام برده شد", "%s added you to %s on %s": "%s شما را به %s در %s اضافه کرد", diff --git a/server/config/locales/fi-FI.json b/server/config/locales/fi-FI.json index 0f3be176..62cbecb5 100644 --- a/server/config/locales/fi-FI.json +++ b/server/config/locales/fi-FI.json @@ -1,4 +1,5 @@ { + "Archive": "Arkisto", "Card Created": "Kortti luotu", "Card Moved": "Kortti siirretty", "New Comment": "Uusi kommentti", @@ -6,6 +7,7 @@ "This is a test text message!": "Tämä on testiviesti!", "This is a *test* **markdown** `message`!": "Tämä on *testi* **markdown** `viesti`!", "This is a test html message!": "Tämä on testi html viesti!", + "Trash": "Roskakori", "You Were Added to Card": "Sinut lisättiin korttiin", "You Were Mentioned in Comment": "Sinut mainittiin kommentissa", "%s added you to %s on %s": "%s lisäsi sinut kohteeseen %s kohteessa %s", diff --git a/server/config/locales/fr-FR.json b/server/config/locales/fr-FR.json index 0c4cb9e2..d9996530 100644 --- a/server/config/locales/fr-FR.json +++ b/server/config/locales/fr-FR.json @@ -1,4 +1,5 @@ { + "Archive": "Archive", "Card Created": "Carte créée", "Card Moved": "Carte déplacée", "New Comment": "Nouveau commentaire", @@ -6,6 +7,7 @@ "This is a test text message!": "Ceci est un message texte de test !", "This is a *test* **markdown** `message`!": "Ceci est un *message* **markdown** `de test` !", "This is a test html message!": "Ceci est un test html message!", + "Trash": "Corbeille", "You Were Added to Card": "Vous avez été ajouté à la carte", "You Were Mentioned in Comment": "Vous avez été mentionné dans un commentaire", "%s added you to %s on %s": "%s vous a ajouté à %s le %s", diff --git a/server/config/locales/hu-HU.json b/server/config/locales/hu-HU.json index b84700cb..25e7c784 100644 --- a/server/config/locales/hu-HU.json +++ b/server/config/locales/hu-HU.json @@ -1,4 +1,5 @@ { + "Archive": "Archívum", "Card Created": "Kártya létrehozva", "Card Moved": "Kártya áthelyezve", "New Comment": "Új hozzászólás", @@ -6,6 +7,7 @@ "This is a test text message!": "Ez itt egy szöveges teszt üzenet!", "This is a *test* **markdown** `message`!": "Ez itt egy **markdown** formátumú *teszt* `üzenet`!", "This is a test html message!": "Ez egy html formátumú teszt üzenet!", + "Trash": "Kuka", "You Were Added to Card": "Hozzádrendeltek egy kártyát", "You Were Mentioned in Comment": "Megemlítettek egy kártyán", "%s added you to %s on %s": "%s hozzárendelt téged a(z) %s kártyához a(z) %s projektben", diff --git a/server/config/locales/id-ID.json b/server/config/locales/id-ID.json index bbffd8a9..ec719a42 100644 --- a/server/config/locales/id-ID.json +++ b/server/config/locales/id-ID.json @@ -1,4 +1,5 @@ { + "Archive": "Arsip", "Card Created": "Kartu dibuat", "Card Moved": "Kartu dipindahkan", "New Comment": "Komentar baru", @@ -6,6 +7,7 @@ "This is a test text message!": "Ini adalah pesan teks tes!", "This is a *test* **markdown** `message`!": "Ini adalah *pesan* **markdown** `tes`!", "This is a test html message!": "Ini adalah pesan html tes!", + "Trash": "Sampah", "You Were Added to Card": "Anda ditambahkan ke kartu", "You Were Mentioned in Comment": "Anda disebutkan dalam komentar", "%s added you to %s on %s": "%s menambahkan Anda ke %s pada %s", diff --git a/server/config/locales/it-IT.json b/server/config/locales/it-IT.json index 2e82564c..113c3ea9 100644 --- a/server/config/locales/it-IT.json +++ b/server/config/locales/it-IT.json @@ -1,4 +1,5 @@ { + "Archive": "Archivio", "Card Created": "Nuova task creata", "Card Moved": "Task spostata", "New Comment": "Nuovo commento", @@ -6,6 +7,7 @@ "This is a test text message!": "Questo è un messaggio di testo di test!", "This is a *test* **markdown** `message`!": "Questo è un *test* **markdown** `messaggio`!", "This is a test html message!": "Questo è un test html messaggio!", + "Trash": "Cestino", "You Were Added to Card": "Sei stato aggiunto alla task", "You Were Mentioned in Comment": "Sei stato menzionato nel commento", "%s created %s in %s on %s": "%s ha creato %s in %s in %s", diff --git a/server/config/locales/ja-JP.json b/server/config/locales/ja-JP.json index f0172f47..810ca4e3 100644 --- a/server/config/locales/ja-JP.json +++ b/server/config/locales/ja-JP.json @@ -1,4 +1,5 @@ { + "Archive": "アーカイブ", "Card Created": "カードが作成されました", "Card Moved": "カードが移動されました", "New Comment": "新しいコメント", @@ -6,6 +7,7 @@ "This is a test text message!": "これはテストテキストメッセージです!", "This is a *test* **markdown** `message`!": "これは*テスト***markdown**`メッセージ`です!", "This is a test html message!": "これはテストhtmlメッセージです!", + "Trash": "ゴミ箱", "You Were Added to Card": "カードに追加されました", "You Were Mentioned in Comment": "コメントでメンションされました", "%s added you to %s on %s": "%sが%sの%sにあなたを追加しました", diff --git a/server/config/locales/ko-KR.json b/server/config/locales/ko-KR.json index 53962ea8..144be51d 100644 --- a/server/config/locales/ko-KR.json +++ b/server/config/locales/ko-KR.json @@ -1,4 +1,5 @@ { + "Archive": "보관함", "Card Created": "카드가 생성됨", "Card Moved": "카드가 이동됨", "New Comment": "새 댓글", @@ -6,6 +7,7 @@ "This is a test text message!": "이것은 테스트 텍스트 메시지입니다!", "This is a *test* **markdown** `message`!": "이것은 *테스트* **markdown** `메시지`입니다!", "This is a test html message!": "이것은 테스트 html 메시지입니다!", + "Trash": "휴지통", "You Were Added to Card": "카드에 추가되었습니다", "You Were Mentioned in Comment": "댓글에서 언급되었습니다", "%s added you to %s on %s": "%s님이 %s의 %s에 당신을 추가했습니다", diff --git a/server/config/locales/nl-NL.json b/server/config/locales/nl-NL.json index f74bcf6b..70753dda 100644 --- a/server/config/locales/nl-NL.json +++ b/server/config/locales/nl-NL.json @@ -1,4 +1,5 @@ { + "Archive": "Archief", "Card Created": "Kaart aangemaakt", "Card Moved": "Kaart verplaatst", "New Comment": "Nieuwe reactie", @@ -6,6 +7,7 @@ "This is a test text message!": "Dit is een test tekstbericht!", "This is a *test* **markdown** `message`!": "Dit is een *test* **markdown** `bericht`!", "This is a test html message!": "Dit is een test html bericht!", + "Trash": "Prullenbak", "You Were Added to Card": "Je bent toegevoegd aan kaart", "You Were Mentioned in Comment": "Je bent genoemd in reactie", "%s added you to %s on %s": "%s heeft je toegevoegd aan %s op %s", diff --git a/server/config/locales/pl-PL.json b/server/config/locales/pl-PL.json index 46838af1..6eaff471 100644 --- a/server/config/locales/pl-PL.json +++ b/server/config/locales/pl-PL.json @@ -1,4 +1,5 @@ { + "Archive": "Archiwum", "Card Created": "Karta utworzona", "Card Moved": "Karta przeniesiona", "New Comment": "Nowy komentarz", @@ -6,6 +7,7 @@ "This is a test text message!": "To jest testowa wiadomość tekstowa!", "This is a *test* **markdown** `message`!": "To jest *testowa* **markdown** `wiadomość`!", "This is a test html message!": "To jest testowa html wiadomość!", + "Trash": "Kosz", "You Were Added to Card": "Zostałeś dodany do karty", "You Were Mentioned in Comment": "Zostałeś wspomniany w komentarzu", "%s added you to %s on %s": "%s dodał cię do %s w dniu %s", diff --git a/server/config/locales/pt-BR.json b/server/config/locales/pt-BR.json index 3f45e3eb..49745515 100644 --- a/server/config/locales/pt-BR.json +++ b/server/config/locales/pt-BR.json @@ -1,4 +1,5 @@ { + "Archive": "Arquivo", "Card Created": "Cartão criado", "Card Moved": "Cartão movido", "New Comment": "Novo comentário", @@ -6,6 +7,7 @@ "This is a test text message!": "Esta é uma mensagem de texto de teste!", "This is a *test* **markdown** `message`!": "Esta é uma *mensagem* **markdown** `de teste`!", "This is a test html message!": "Esta é uma mensagem html de teste!", + "Trash": "Lixeira", "You Were Added to Card": "Você foi adicionado ao cartão", "You Were Mentioned in Comment": "Você foi mencionado em comentário", "%s added you to %s on %s": "%s adicionou você a %s em %s", diff --git a/server/config/locales/pt-PT.json b/server/config/locales/pt-PT.json index 1005c8f4..7379cf5a 100644 --- a/server/config/locales/pt-PT.json +++ b/server/config/locales/pt-PT.json @@ -1,4 +1,5 @@ { + "Archive": "Arquivo", "Card Created": "Cartão criado", "Card Moved": "Cartão movido", "New Comment": "Novo comentário", @@ -6,6 +7,7 @@ "This is a test text message!": "Esta é uma mensagem de texto de teste!", "This is a *test* **markdown** `message`!": "Esta é uma *mensagem* **markdown** `de teste`!", "This is a test html message!": "Esta é uma mensagem html de teste!", + "Trash": "Lixo", "You Were Added to Card": "Foi adicionado ao cartão", "You Were Mentioned in Comment": "Foi mencionado num comentário", "%s added you to %s on %s": "%s adicionou-o a %s em %s", diff --git a/server/config/locales/ro-RO.json b/server/config/locales/ro-RO.json index b35764ee..d6885dd8 100644 --- a/server/config/locales/ro-RO.json +++ b/server/config/locales/ro-RO.json @@ -1,4 +1,5 @@ { + "Archive": "Arhivă", "Card Created": "Card creat", "Card Moved": "Card mutat", "New Comment": "Comentariu nou", @@ -6,6 +7,7 @@ "This is a test text message!": "Acesta este un mesaj text de test!", "This is a *test* **markdown** `message`!": "Acesta este un *mesaj* **markdown** `de test`!", "This is a test html message!": "Acesta este un mesaj html de test!", + "Trash": "Coș de gunoi", "You Were Added to Card": "Ați fost adăugat la card", "You Were Mentioned in Comment": "Ați fost menționat într-un comentariu", "%s added you to %s on %s": "%s v-a adăugat la %s pe %s", diff --git a/server/config/locales/ru-RU.json b/server/config/locales/ru-RU.json index 0467f4f0..c94db4d8 100644 --- a/server/config/locales/ru-RU.json +++ b/server/config/locales/ru-RU.json @@ -1,4 +1,5 @@ { + "Archive": "Архив", "Card Created": "Карточка создана", "Card Moved": "Карточка перемещена", "New Comment": "Новый комментарий", @@ -6,6 +7,7 @@ "This is a test text message!": "Это тестовое сообщение!", "This is a *test* **markdown** `message`!": "Это *тестовое* **markdown** `сообщение`!", "This is a test html message!": "Это тестовое html сообщение!", + "Trash": "Корзина", "You Were Added to Card": "Вы были добавлены к карточке", "You Were Mentioned in Comment": "Вы были упомянуты в комментарии", "%s added you to %s on %s": "%s добавил(а) вас к %s на %s", diff --git a/server/config/locales/sk-SK.json b/server/config/locales/sk-SK.json index 79ab3283..a0bc5c7f 100644 --- a/server/config/locales/sk-SK.json +++ b/server/config/locales/sk-SK.json @@ -1,4 +1,5 @@ { + "Archive": "Archív", "Card Created": "Karta vytvorená", "Card Moved": "Karta presunutá", "New Comment": "Nový komentár", @@ -6,6 +7,7 @@ "This is a test text message!": "Toto je testovacia textová správa!", "This is a *test* **markdown** `message`!": "Toto je *testovacia* **markdown** `správa`!", "This is a test html message!": "Toto je testovacia html správa!", + "Trash": "Kôš", "You Were Added to Card": "Boli ste pridaní ku karte", "You Were Mentioned in Comment": "Boli ste spomenutí v komentári", "%s added you to %s on %s": "%s vás pridal k %s dňa %s", diff --git a/server/config/locales/sr-Cyrl-RS.json b/server/config/locales/sr-Cyrl-RS.json index 430a6203..e09cc2d5 100644 --- a/server/config/locales/sr-Cyrl-RS.json +++ b/server/config/locales/sr-Cyrl-RS.json @@ -1,4 +1,5 @@ { + "Archive": "Архива", "Card Created": "Картица креирана", "Card Moved": "Картица премештена", "New Comment": "Нови коментар", @@ -6,6 +7,7 @@ "This is a test text message!": "Ово је тест текстуална порука!", "This is a *test* **markdown** `message`!": "Ово је *тест* **markdown** `порука`!", "This is a test html message!": "Ово је тест html порука!", + "Trash": "Корпа за отпатке", "You Were Added to Card": "Додати сте на картицу", "You Were Mentioned in Comment": "Поменути сте у коментару", "%s added you to %s on %s": "%s вас је додао на %s дана %s", diff --git a/server/config/locales/sr-Latn-RS.json b/server/config/locales/sr-Latn-RS.json index fb218171..b9ea7368 100644 --- a/server/config/locales/sr-Latn-RS.json +++ b/server/config/locales/sr-Latn-RS.json @@ -1,4 +1,5 @@ { + "Archive": "Arhiva", "Card Created": "Kartica kreirana", "Card Moved": "Kartica premeštena", "New Comment": "Novi komentar", @@ -6,6 +7,7 @@ "This is a test text message!": "Ovo je test tekstualna poruka!", "This is a *test* **markdown** `message`!": "Ovo je *test* **markdown** `poruka`!", "This is a test html message!": "Ovo je test html poruka!", + "Trash": "Korpa za otpatke", "You Were Added to Card": "Dodati ste na karticu", "You Were Mentioned in Comment": "Pomenuti ste u komentaru", "%s added you to %s on %s": "%s vas je dodao na %s dana %s", diff --git a/server/config/locales/sv-SE.json b/server/config/locales/sv-SE.json index c42bd5c9..568d57d9 100644 --- a/server/config/locales/sv-SE.json +++ b/server/config/locales/sv-SE.json @@ -1,4 +1,5 @@ { + "Archive": "Arkiv", "Card Created": "Kort skapat", "Card Moved": "Kort flyttat", "New Comment": "Ny kommentar", @@ -6,6 +7,7 @@ "This is a test text message!": "Detta är ett test textmeddelande!", "This is a *test* **markdown** `message`!": "Detta är ett *test* **markdown** `meddelande`!", "This is a test html message!": "Detta är ett test html meddelande!", + "Trash": "Papperskorg", "You Were Added to Card": "Du lades till på kort", "You Were Mentioned in Comment": "Du nämndes i kommentar", "%s added you to %s on %s": "%s lade till dig på %s den %s", diff --git a/server/config/locales/tr-TR.json b/server/config/locales/tr-TR.json index 2ee799d3..9045bfee 100644 --- a/server/config/locales/tr-TR.json +++ b/server/config/locales/tr-TR.json @@ -1,4 +1,5 @@ { + "Archive": "Arşiv", "Card Created": "Kart oluşturuldu", "Card Moved": "Kart taşındı", "New Comment": "Yeni yorum", @@ -6,6 +7,7 @@ "This is a test text message!": "Bu bir test metin mesajıdır!", "This is a *test* **markdown** `message`!": "Bu bir *test* **markdown** `mesajı`!", "This is a test html message!": "Bu bir test html mesajı!", + "Trash": "Çöp kutusu", "You Were Added to Card": "Karta eklendiniz", "You Were Mentioned in Comment": "Bir yorumda bahsedildiniz", "%s added you to %s on %s": "%s sizi %s'ye %s tarihinde ekledi", diff --git a/server/config/locales/uk-UA.json b/server/config/locales/uk-UA.json index 3f30267c..919806c9 100644 --- a/server/config/locales/uk-UA.json +++ b/server/config/locales/uk-UA.json @@ -1,4 +1,5 @@ { + "Archive": "Архів", "Card Created": "Картку створено", "Card Moved": "Картку переміщено", "New Comment": "Новий коментар", @@ -6,6 +7,7 @@ "This is a test text message!": "Це нове повідомлення!", "This is a *test* **markdown** `message`!": "Це *тестове* **markdown** `повідомлення`!", "This is a test html message!": "Це тестове html повідомлення!", + "Trash": "Кошик", "You Were Added to Card": "Вас було додано до картки", "You Were Mentioned in Comment": "Вас було згадано у коментарі", "%s added you to %s on %s": "%s додав(ла) вас до %s на %s", diff --git a/server/config/locales/uz-UZ.json b/server/config/locales/uz-UZ.json index 57458a76..8c5ccbf8 100644 --- a/server/config/locales/uz-UZ.json +++ b/server/config/locales/uz-UZ.json @@ -1,4 +1,5 @@ { + "Archive": "Arxiv", "Card Created": "Karta yaratildi", "Card Moved": "Karta ko'chirildi", "New Comment": "Yangi izoh", @@ -6,6 +7,7 @@ "This is a test text message!": "Bu test matn xabari!", "This is a *test* **markdown** `message`!": "Bu *test* **markdown** `xabar`!", "This is a test html message!": "Bu test html xabar!", + "Trash": "Chiqindi quti", "You Were Added to Card": "Siz kartaga qo'shildingiz", "You Were Mentioned in Comment": "Siz izohda eslatildingiz", "%s added you to %s on %s": "%s sizni %s ga %s da qo'shdi", diff --git a/server/config/locales/zh-CN.json b/server/config/locales/zh-CN.json index 0a36e4e9..87ca06c3 100644 --- a/server/config/locales/zh-CN.json +++ b/server/config/locales/zh-CN.json @@ -1,4 +1,5 @@ { + "Archive": "归档", "Card Created": "卡片已创建", "Card Moved": "卡片已移动", "New Comment": "新评论", @@ -6,6 +7,7 @@ "This is a test text message!": "这是一条测试文本消息!", "This is a *test* **markdown** `message`!": "这是一条*测试***markdown**`消息`!", "This is a test html message!": "这是一条测试html消息!", + "Trash": "回收站", "You Were Added to Card": "您已被添加到卡片", "You Were Mentioned in Comment": "您在评论中被提及", "%s added you to %s on %s": "%s 在 %s 将您添加到 %s", diff --git a/server/config/locales/zh-TW.json b/server/config/locales/zh-TW.json index 71042dd8..c93f150f 100644 --- a/server/config/locales/zh-TW.json +++ b/server/config/locales/zh-TW.json @@ -1,4 +1,5 @@ { + "Archive": "封存", "Card Created": "卡片已建立", "Card Moved": "卡片已移動", "New Comment": "新留言", @@ -6,6 +7,7 @@ "This is a test text message!": "這是一則測試文字訊息!", "This is a *test* **markdown** `message`!": "這是一則*測試***markdown**`訊息`!", "This is a test html message!": "這是一則測試html訊息!", + "Trash": "垃圾桶", "You Were Added to Card": "您已被加入卡片", "You Were Mentioned in Comment": "您在留言中被提及", "%s added you to %s on %s": "%s 在 %s 將您加入 %s", diff --git a/server/utils/validators.js b/server/utils/validators.js index 767027d4..695b80a6 100644 --- a/server/utils/validators.js +++ b/server/utils/validators.js @@ -16,6 +16,7 @@ const USERNAME_REGEX = /^[a-zA-Z0-9]+((_|\.)?[a-zA-Z0-9])*$/; const isUrl = (value) => validator.isURL(value, { protocols: ['http', 'https'], + require_tld: false, require_protocol: true, });