Compare commits

...
4 Commits
Author SHA1 Message Date
Maksim Eltyshev c8d732d936 chore: Update version 2024-05-03 12:44:51 +02:00
Maksim Eltyshev 5a32b6327c fix: Fix actions with members
Closes #737
2024-05-03 12:42:51 +02:00
Emmanuel Guyot 8488105810 feat: Search in card descriptions (#729) 2024-04-26 21:52:57 +02:00
Niccolò Pedrini 57ebfa51d8 fix: Update Italian translation (#727) 2024-04-24 18:49:27 +02:00
12 changed files with 118 additions and 59 deletions
+2 -2
View File
@@ -15,13 +15,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.28 version: 0.1.29
# This is the version number of the application being deployed. This version number should be # This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to # incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: "1.17.1" appVersion: "1.17.2"
dependencies: dependencies:
- alias: postgresql - alias: postgresql
+1 -1
View File
@@ -1 +1 @@
REACT_APP_VERSION=1.17.1 REACT_APP_VERSION=1.17.2
@@ -3,6 +3,7 @@ import React, { useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Button } from 'semantic-ui-react'; import { Button } from 'semantic-ui-react';
import { Popup } from '../../lib/custom-ui';
import { useSteps } from '../../hooks'; import { useSteps } from '../../hooks';
import User from '../User'; import User from '../User';
@@ -19,6 +20,7 @@ const ActionsStep = React.memo(
({ ({
membership, membership,
permissionsSelectStep, permissionsSelectStep,
title,
leaveButtonContent, leaveButtonContent,
leaveConfirmationTitle, leaveConfirmationTitle,
leaveConfirmationContent, leaveConfirmationContent,
@@ -31,6 +33,7 @@ const ActionsStep = React.memo(
canLeave, canLeave,
onUpdate, onUpdate,
onDelete, onDelete,
onBack,
onClose, onClose,
}) => { }) => {
const [t] = useTranslation(); const [t] = useTranslation();
@@ -53,6 +56,11 @@ const ActionsStep = React.memo(
[onUpdate], [onUpdate],
); );
const handleDeleteConfirm = useCallback(() => {
onDelete();
onClose();
}, [onDelete, onClose]);
if (step) { if (step) {
switch (step.type) { switch (step.type) {
case StepTypes.EDIT_PERMISSIONS: { case StepTypes.EDIT_PERMISSIONS: {
@@ -81,7 +89,7 @@ const ActionsStep = React.memo(
? leaveConfirmationButtonContent ? leaveConfirmationButtonContent
: deleteConfirmationButtonContent : deleteConfirmationButtonContent
} }
onConfirm={onDelete} onConfirm={handleDeleteConfirm}
onBack={handleBack} onBack={handleBack}
/> />
); );
@@ -89,7 +97,7 @@ const ActionsStep = React.memo(
} }
} }
return ( const contentNode = (
<> <>
<span className={styles.user}> <span className={styles.user}>
<User name={membership.user.name} avatarUrl={membership.user.avatarUrl} size="large" /> <User name={membership.user.name} avatarUrl={membership.user.avatarUrl} size="large" />
@@ -125,12 +133,26 @@ const ActionsStep = React.memo(
)} )}
</> </>
); );
return onBack ? (
<>
<Popup.Header onBack={onBack}>
{t(title, {
context: 'title',
})}
</Popup.Header>
<Popup.Content>{contentNode}</Popup.Content>
</>
) : (
contentNode
);
}, },
); );
ActionsStep.propTypes = { ActionsStep.propTypes = {
membership: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types membership: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
permissionsSelectStep: PropTypes.elementType, permissionsSelectStep: PropTypes.elementType,
title: PropTypes.string,
leaveButtonContent: PropTypes.string, leaveButtonContent: PropTypes.string,
leaveConfirmationTitle: PropTypes.string, leaveConfirmationTitle: PropTypes.string,
leaveConfirmationContent: PropTypes.string, leaveConfirmationContent: PropTypes.string,
@@ -143,11 +165,13 @@ ActionsStep.propTypes = {
canLeave: PropTypes.bool.isRequired, canLeave: PropTypes.bool.isRequired,
onUpdate: PropTypes.func, onUpdate: PropTypes.func,
onDelete: PropTypes.func.isRequired, onDelete: PropTypes.func.isRequired,
onBack: PropTypes.func,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
}; };
ActionsStep.defaultProps = { ActionsStep.defaultProps = {
permissionsSelectStep: undefined, permissionsSelectStep: undefined,
title: 'common.memberActions',
leaveButtonContent: 'action.leaveBoard', leaveButtonContent: 'action.leaveBoard',
leaveConfirmationTitle: 'common.leaveBoard', leaveConfirmationTitle: 'common.leaveBoard',
leaveConfirmationContent: 'common.areYouSureYouWantToLeaveBoard', leaveConfirmationContent: 'common.areYouSureYouWantToLeaveBoard',
@@ -157,6 +181,7 @@ ActionsStep.defaultProps = {
deleteConfirmationContent: 'common.areYouSureYouWantToRemoveThisMemberFromBoard', deleteConfirmationContent: 'common.areYouSureYouWantToRemoveThisMemberFromBoard',
deleteConfirmationButtonContent: 'action.removeMember', deleteConfirmationButtonContent: 'action.removeMember',
onUpdate: undefined, onUpdate: undefined,
onBack: undefined,
}; };
export default ActionsStep; export default ActionsStep;
@@ -5,10 +5,10 @@ import { usePopup } from '../../lib/popup';
import AddStep from './AddStep'; import AddStep from './AddStep';
import ActionsStep from './ActionsStep'; import ActionsStep from './ActionsStep';
import MembershipsStep from './MembershipsStep';
import User from '../User'; import User from '../User';
import styles from './Memberships.module.scss'; import styles from './Memberships.module.scss';
import MembershipsStep from './MembershipsStep';
const MAX_MEMBERS = 6; const MAX_MEMBERS = 6;
@@ -17,7 +17,9 @@ const Memberships = React.memo(
items, items,
allUsers, allUsers,
permissionsSelectStep, permissionsSelectStep,
title,
addTitle, addTitle,
actionsTitle,
leaveButtonContent, leaveButtonContent,
leaveConfirmationTitle, leaveConfirmationTitle,
leaveConfirmationContent, leaveConfirmationContent,
@@ -73,6 +75,8 @@ const Memberships = React.memo(
<MembershipsPopup <MembershipsPopup
items={items} items={items}
permissionsSelectStep={permissionsSelectStep} permissionsSelectStep={permissionsSelectStep}
title={title}
actionsTitle={actionsTitle}
leaveButtonContent={leaveButtonContent} leaveButtonContent={leaveButtonContent}
leaveConfirmationTitle={leaveConfirmationTitle} leaveConfirmationTitle={leaveConfirmationTitle}
leaveConfirmationContent={leaveConfirmationContent} leaveConfirmationContent={leaveConfirmationContent}
@@ -87,7 +91,7 @@ const Memberships = React.memo(
onDelete={onDelete} onDelete={onDelete}
> >
<Button icon className={styles.addUser}> <Button icon className={styles.addUser}>
+ {remainMembersCount < 99 ? remainMembersCount : 99} +{remainMembersCount < 99 ? remainMembersCount : 99}
</Button> </Button>
</MembershipsPopup> </MembershipsPopup>
)} )}
@@ -113,7 +117,9 @@ Memberships.propTypes = {
allUsers: PropTypes.array.isRequired, allUsers: PropTypes.array.isRequired,
/* eslint-enable react/forbid-prop-types */ /* eslint-enable react/forbid-prop-types */
permissionsSelectStep: PropTypes.elementType, permissionsSelectStep: PropTypes.elementType,
title: PropTypes.string,
addTitle: PropTypes.string, addTitle: PropTypes.string,
actionsTitle: PropTypes.string,
leaveButtonContent: PropTypes.string, leaveButtonContent: PropTypes.string,
leaveConfirmationTitle: PropTypes.string, leaveConfirmationTitle: PropTypes.string,
leaveConfirmationContent: PropTypes.string, leaveConfirmationContent: PropTypes.string,
@@ -131,7 +137,9 @@ Memberships.propTypes = {
Memberships.defaultProps = { Memberships.defaultProps = {
permissionsSelectStep: undefined, permissionsSelectStep: undefined,
title: undefined,
addTitle: undefined, addTitle: undefined,
actionsTitle: undefined,
leaveButtonContent: undefined, leaveButtonContent: undefined,
leaveConfirmationTitle: undefined, leaveConfirmationTitle: undefined,
leaveConfirmationContent: undefined, leaveConfirmationContent: undefined,
@@ -1,15 +1,20 @@
import React, { useCallback, useState } from 'react'; import React, { useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import BoardMembershipsStep from '../BoardMembershipsStep/BoardMembershipsStep'; import { useSteps } from '../../hooks';
import ActionsStep from './ActionsStep'; import ActionsStep from './ActionsStep';
import { Popup } from '../../lib/custom-ui'; import BoardMembershipsStep from '../BoardMembershipsStep';
const StepTypes = {
EDIT: 'EDIT',
};
const MembershipsStep = React.memo( const MembershipsStep = React.memo(
({ ({
items, items,
permissionsSelectStep, permissionsSelectStep,
title,
actionsTitle,
leaveButtonContent, leaveButtonContent,
leaveConfirmationTitle, leaveConfirmationTitle,
leaveConfirmationContent, leaveConfirmationContent,
@@ -24,49 +29,54 @@ const MembershipsStep = React.memo(
onDelete, onDelete,
onClose, onClose,
}) => { }) => {
const [t] = useTranslation(); const [step, openStep, handleBack] = useSteps();
const [editingItem, setEditingItem] = useState(); const handleUserSelect = useCallback(
(userId) => {
const handleUserClick = useCallback( openStep(StepTypes.EDIT, {
(id) => { userId,
setEditingItem(items.find((item) => item.user.id === id)); });
}, },
[setEditingItem, items], [openStep],
); );
if (editingItem) { if (step && step.type === StepTypes.EDIT) {
return ( const currentItem = items.find((item) => item.userId === step.params.userId);
<>
<Popup.Header onBack={() => setEditingItem(null)}>{t('common.memberInfo')}</Popup.Header> if (currentItem) {
<Popup.Content> return (
<ActionsStep <ActionsStep
membership={editingItem} membership={currentItem}
permissionsSelectStep={permissionsSelectStep} permissionsSelectStep={permissionsSelectStep}
leaveButtonContent={leaveButtonContent} title={actionsTitle}
leaveConfirmationTitle={leaveConfirmationTitle} leaveButtonContent={leaveButtonContent}
leaveConfirmationContent={leaveConfirmationContent} leaveConfirmationTitle={leaveConfirmationTitle}
leaveConfirmationButtonContent={leaveConfirmationButtonContent} leaveConfirmationContent={leaveConfirmationContent}
deleteButtonContent={deleteButtonContent} leaveConfirmationButtonContent={leaveConfirmationButtonContent}
deleteConfirmationTitle={deleteConfirmationTitle} deleteButtonContent={deleteButtonContent}
deleteConfirmationContent={deleteConfirmationContent} deleteConfirmationTitle={deleteConfirmationTitle}
deleteConfirmationButtonContent={deleteConfirmationButtonContent} deleteConfirmationContent={deleteConfirmationContent}
canEdit={canEdit} deleteConfirmationButtonContent={deleteConfirmationButtonContent}
canLeave={canLeave} canEdit={canEdit}
onUpdate={onUpdate} canLeave={canLeave}
onDelete={onDelete} onUpdate={(data) => onUpdate(currentItem.id, data)}
onClose={onClose} onDelete={() => onDelete(currentItem.id)}
/> onBack={handleBack}
</Popup.Content> onClose={onClose}
</> />
); );
}
openStep(null);
} }
return ( return (
// FIXME: hack
<BoardMembershipsStep <BoardMembershipsStep
items={items} items={items}
currentUserIds={[]} currentUserIds={[]}
onUserSelect={handleUserClick} title={title}
onUserSelect={handleUserSelect}
onUserDeselect={() => {}} onUserDeselect={() => {}}
/> />
); );
@@ -76,6 +86,8 @@ const MembershipsStep = React.memo(
MembershipsStep.propTypes = { MembershipsStep.propTypes = {
items: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types items: PropTypes.array.isRequired, // eslint-disable-line react/forbid-prop-types
permissionsSelectStep: PropTypes.elementType, permissionsSelectStep: PropTypes.elementType,
title: PropTypes.string,
actionsTitle: PropTypes.string,
leaveButtonContent: PropTypes.string, leaveButtonContent: PropTypes.string,
leaveConfirmationTitle: PropTypes.string, leaveConfirmationTitle: PropTypes.string,
leaveConfirmationContent: PropTypes.string, leaveConfirmationContent: PropTypes.string,
@@ -93,14 +105,16 @@ MembershipsStep.propTypes = {
MembershipsStep.defaultProps = { MembershipsStep.defaultProps = {
permissionsSelectStep: undefined, permissionsSelectStep: undefined,
leaveButtonContent: 'action.leaveBoard', title: undefined,
leaveConfirmationTitle: 'common.leaveBoard', actionsTitle: undefined,
leaveConfirmationContent: 'common.areYouSureYouWantToLeaveBoard', leaveButtonContent: undefined,
leaveConfirmationButtonContent: 'action.leaveBoard', leaveConfirmationTitle: undefined,
deleteButtonContent: 'action.removeFromBoard', leaveConfirmationContent: undefined,
deleteConfirmationTitle: 'common.removeMember', leaveConfirmationButtonContent: undefined,
deleteConfirmationContent: 'common.areYouSureYouWantToRemoveThisMemberFromBoard', deleteButtonContent: undefined,
deleteConfirmationButtonContent: 'action.removeMember', deleteConfirmationTitle: undefined,
deleteConfirmationContent: undefined,
deleteConfirmationButtonContent: undefined,
onUpdate: undefined, onUpdate: undefined,
}; };
@@ -12,7 +12,9 @@ const ManagersPane = React.memo(({ items, allUsers, onCreate, onDelete }) => {
<Memberships <Memberships
items={items} items={items}
allUsers={allUsers} allUsers={allUsers}
title="common.managers"
addTitle="common.addManager" addTitle="common.addManager"
actionsTitle="common.managerActions"
leaveButtonContent="action.leaveProject" leaveButtonContent="action.leaveProject"
leaveConfirmationTitle="common.leaveProject" leaveConfirmationTitle="common.leaveProject"
leaveConfirmationContent="common.areYouSureYouWantToLeaveProject" leaveConfirmationContent="common.areYouSureYouWantToLeaveProject"
+2 -1
View File
@@ -109,8 +109,9 @@ export default {
list: 'List', list: 'List',
listActions_title: 'List Actions', listActions_title: 'List Actions',
managers: 'Managers', managers: 'Managers',
memberInfo: 'Member Info', managerActions_title: 'Manager Actions',
members: 'Members', members: 'Members',
memberActions_title: 'Member Actions',
minutes: 'Minutes', minutes: 'Minutes',
moveCard_title: 'Move Card', moveCard_title: 'Move Card',
name: 'Name', name: 'Name',
+6
View File
@@ -59,6 +59,7 @@ export default {
currentPassword: 'Password corrente', currentPassword: 'Password corrente',
dangerZone_title: 'Zona pericolosa', dangerZone_title: 'Zona pericolosa',
date: 'Data', date: 'Data',
dueDate: 'Data di scadenza',
dueDate_title: 'Data di scadenza', dueDate_title: 'Data di scadenza',
deleteAttachment_title: 'Elimina Allegato', deleteAttachment_title: 'Elimina Allegato',
deleteBoard_title: 'Elimina Bacheca', deleteBoard_title: 'Elimina Bacheca',
@@ -111,6 +112,7 @@ export default {
minutes: 'Minuti', minutes: 'Minuti',
moveCard_title: 'Sposta card', moveCard_title: 'Sposta card',
name: 'Nome', name: 'Nome',
newestFirst: 'Dal più recente',
newEmail: 'Nuova e-mail', newEmail: 'Nuova e-mail',
newPassword: 'Nuova password', newPassword: 'Nuova password',
newUsername: 'Nuovo username', newUsername: 'Nuovo username',
@@ -120,6 +122,7 @@ export default {
noProjects: 'No progetti', noProjects: 'No progetti',
notifications: 'Notifiche', notifications: 'Notifiche',
noUnreadNotifications: 'Nessuna notifica non letta.', noUnreadNotifications: 'Nessuna notifica non letta.',
oldestFirst: 'Dal meno recente',
openBoard_title: 'Bacheca aperta', openBoard_title: 'Bacheca aperta',
optional_inline: 'opzionale', optional_inline: 'opzionale',
organization: 'Organizazzione', organization: 'Organizazzione',
@@ -134,12 +137,14 @@ export default {
searchLabels: 'Cerca etichette...', searchLabels: 'Cerca etichette...',
searchMembers: 'Cerca membri...', searchMembers: 'Cerca membri...',
searchUsers: 'Cerca utenti...', searchUsers: 'Cerca utenti...',
searchCards: 'Cerca cards...',
seconds: 'Secondi', seconds: 'Secondi',
selectBoard: 'Seleziona bacheca', selectBoard: 'Seleziona bacheca',
selectList: 'Seleziona lista', selectList: 'Seleziona lista',
selectPermissions_title: 'Seleziona Permessi', selectPermissions_title: 'Seleziona Permessi',
selectProject: 'Seleziona progetto', selectProject: 'Seleziona progetto',
settings: 'Impostazioni', settings: 'Impostazioni',
sortList_title: 'Ordina',
stopwatch: 'Timer', stopwatch: 'Timer',
subscribeToMyOwnCardsByDefault: 'Abbonati alle mie card per impostazione predefinita', subscribeToMyOwnCardsByDefault: 'Abbonati alle mie card per impostazione predefinita',
taskActions_title: 'Task Azioni', taskActions_title: 'Task Azioni',
@@ -227,6 +232,7 @@ export default {
showAllAttachments: 'Mostra tutti gli allegati ({{hidden}} hidden)', showAllAttachments: 'Mostra tutti gli allegati ({{hidden}} hidden)',
showDetails: 'Mostra dettagli', showDetails: 'Mostra dettagli',
showFewerAttachments: 'Mostra meno allegati', showFewerAttachments: 'Mostra meno allegati',
sortList_title: 'Ordina',
start: 'Inizio', start: 'Inizio',
stop: 'Ferma', stop: 'Ferma',
subscribe: 'Iscriviti', subscribe: 'Iscriviti',
-1
View File
@@ -111,7 +111,6 @@ export default {
list: 'Lista', list: 'Lista',
listActions_title: 'Ações da Lista', listActions_title: 'Ações da Lista',
managers: 'Gerentes', managers: 'Gerentes',
memberInfo: 'Informações do Membro',
members: 'Membros', members: 'Membros',
minutes: 'Minutos', minutes: 'Minutos',
moveCard_title: 'Mover Cartão', moveCard_title: 'Mover Cartão',
+6 -2
View File
@@ -101,7 +101,9 @@ export default class extends BaseModel {
} }
let doRegularSearch = true; let doRegularSearch = true;
if (re) { if (re) {
cardModels = cardModels.filter((cardModel) => re.test(cardModel.name)); cardModels = cardModels.filter(
(cardModel) => re.test(cardModel.name) || re.test(cardModel?.description),
);
doRegularSearch = false; doRegularSearch = false;
} else if (filterText.startsWith('!') && posSpace > 0) { } else if (filterText.startsWith('!') && posSpace > 0) {
const creatorUserId = User.findUsersFromText( const creatorUserId = User.findUsersFromText(
@@ -116,7 +118,9 @@ export default class extends BaseModel {
if (doRegularSearch) { if (doRegularSearch) {
const lowerCasedFilter = filterText.toLocaleLowerCase(); const lowerCasedFilter = filterText.toLocaleLowerCase();
cardModels = cardModels.filter( cardModels = cardModels.filter(
(cardModel) => cardModel.name.toLocaleLowerCase().indexOf(lowerCasedFilter) >= 0, (cardModel) =>
cardModel.name.toLocaleLowerCase().indexOf(lowerCasedFilter) >= 0 ||
cardModel.description?.toLocaleLowerCase().indexOf(lowerCasedFilter) >= 0,
); );
} }
} }
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "planka", "name": "planka",
"version": "1.17.1", "version": "1.17.2",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "planka", "name": "planka",
"version": "1.17.1", "version": "1.17.2",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "planka", "name": "planka",
"version": "1.17.1", "version": "1.17.2",
"private": true, "private": true,
"homepage": "https://plankanban.github.io/planka", "homepage": "https://plankanban.github.io/planka",
"repository": { "repository": {