From ffb96931843b141811cfabf65203537d18500de8 Mon Sep 17 00:00:00 2001 From: symonbaikov Date: Fri, 4 Jul 2025 21:37:11 +0300 Subject: [PATCH 1/5] feat(api): allow setting custom fields when creating a card via API (closes #1155) --- server/api/controllers/cards/create.js | 7 +++++++ server/api/helpers/cards/create-one.js | 27 ++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/server/api/controllers/cards/create.js b/server/api/controllers/cards/create.js index 7ff91013..9c542c6d 100755 --- a/server/api/controllers/cards/create.js +++ b/server/api/controllers/cards/create.js @@ -53,6 +53,9 @@ module.exports = { type: 'json', custom: isStopwatch, }, + customFields: { + type: 'ref', + }, }, exits: { @@ -96,6 +99,10 @@ module.exports = { 'stopwatch', ]); + if (inputs.customFields) { + values.customFields = inputs.customFields; + } + const card = await sails.helpers.cards.createOne .with({ project, diff --git a/server/api/helpers/cards/create-one.js b/server/api/helpers/cards/create-one.js index ae05a43e..602ce4db 100644 --- a/server/api/helpers/cards/create-one.js +++ b/server/api/helpers/cards/create-one.js @@ -75,6 +75,33 @@ module.exports = { listChangedAt: new Date().toISOString(), }); + if (values.customFields) { + const customFieldGroups = await CustomFieldGroup.qm.getByBoardId(values.board.id); + const customFieldGroupMap = _.keyBy(customFieldGroups, 'name'); + const customFieldGroupIds = customFieldGroups.map((g) => g.id); + const customFields = await CustomField.qm.getByCustomFieldGroupIds(customFieldGroupIds); + const customFieldMap = _.keyBy(customFields, (f) => `${f.customFieldGroupId}:${f.name}`); + + const createValuePromises = []; + Object.entries(values.customFields).forEach(([groupName, fields]) => { + const group = customFieldGroupMap[groupName]; + if (!group) return; + Object.entries(fields).forEach(([fieldName, content]) => { + const field = customFieldMap[`${group.id}:${fieldName}`]; + if (!field) return; + createValuePromises.push( + CustomFieldValue.create({ + cardId: card.id, + customFieldGroupId: group.id, + customFieldId: field.id, + content: String(content), + }), + ); + }); + }); + await Promise.all(createValuePromises); + } + sails.sockets.broadcast( `board:${card.boardId}`, 'cardCreate', From e1efe663a0799f870415999aee9b3ae650842104 Mon Sep 17 00:00:00 2001 From: symonbaikov Date: Sat, 5 Jul 2025 22:46:32 +0300 Subject: [PATCH 2/5] Add German (de-DE) translation and enable it in i18n config --- server/api/controllers/cards/create.js | 7 ------- server/api/helpers/cards/create-one.js | 27 -------------------------- server/config/i18n.js | 2 +- server/config/locales/de-DE.json | 16 +++++++++++++++ 4 files changed, 17 insertions(+), 35 deletions(-) create mode 100644 server/config/locales/de-DE.json diff --git a/server/api/controllers/cards/create.js b/server/api/controllers/cards/create.js index 9c542c6d..7ff91013 100755 --- a/server/api/controllers/cards/create.js +++ b/server/api/controllers/cards/create.js @@ -53,9 +53,6 @@ module.exports = { type: 'json', custom: isStopwatch, }, - customFields: { - type: 'ref', - }, }, exits: { @@ -99,10 +96,6 @@ module.exports = { 'stopwatch', ]); - if (inputs.customFields) { - values.customFields = inputs.customFields; - } - const card = await sails.helpers.cards.createOne .with({ project, diff --git a/server/api/helpers/cards/create-one.js b/server/api/helpers/cards/create-one.js index 602ce4db..ae05a43e 100644 --- a/server/api/helpers/cards/create-one.js +++ b/server/api/helpers/cards/create-one.js @@ -75,33 +75,6 @@ module.exports = { listChangedAt: new Date().toISOString(), }); - if (values.customFields) { - const customFieldGroups = await CustomFieldGroup.qm.getByBoardId(values.board.id); - const customFieldGroupMap = _.keyBy(customFieldGroups, 'name'); - const customFieldGroupIds = customFieldGroups.map((g) => g.id); - const customFields = await CustomField.qm.getByCustomFieldGroupIds(customFieldGroupIds); - const customFieldMap = _.keyBy(customFields, (f) => `${f.customFieldGroupId}:${f.name}`); - - const createValuePromises = []; - Object.entries(values.customFields).forEach(([groupName, fields]) => { - const group = customFieldGroupMap[groupName]; - if (!group) return; - Object.entries(fields).forEach(([fieldName, content]) => { - const field = customFieldMap[`${group.id}:${fieldName}`]; - if (!field) return; - createValuePromises.push( - CustomFieldValue.create({ - cardId: card.id, - customFieldGroupId: group.id, - customFieldId: field.id, - content: String(content), - }), - ); - }); - }); - await Promise.all(createValuePromises); - } - sails.sockets.broadcast( `board:${card.boardId}`, 'cardCreate', diff --git a/server/config/i18n.js b/server/config/i18n.js index dab3b812..574a6b55 100644 --- a/server/config/i18n.js +++ b/server/config/i18n.js @@ -19,7 +19,7 @@ module.exports.i18n = { * */ - locales: ['en-GB', 'en-US', 'es-ES', 'it-IT', 'ru-RU'], + locales: ['en-GB', 'en-US', 'es-ES', 'it-IT', 'ru-RU', 'de-DE'], /** * diff --git a/server/config/locales/de-DE.json b/server/config/locales/de-DE.json new file mode 100644 index 00000000..ceb546df --- /dev/null +++ b/server/config/locales/de-DE.json @@ -0,0 +1,16 @@ +{ + "Card Created": "Karte erstellt", + "Card Moved": "Karte verschoben", + "New Comment": "Neuer Kommentar", + "Test Title": "Testtitel", + "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", + "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", + "%s created %s in %s on %s": "%s hat %s in %s am %s erstellt", + "%s left a new comment to %s on %s": "%s hat einen neuen Kommentar zu %s am %s hinterlassen", + "%s mentioned you in %s on %s": "%s hat Sie in %s am %s erwähnt", + "%s moved %s from %s to %s on %s": "%s hat %s von %s nach %s am %s verschoben" +} From 334f7b2028ac31bd0b42dd886f1d274c465840b8 Mon Sep 17 00:00:00 2001 From: symonbaikov Date: Sat, 5 Jul 2025 23:07:22 +0300 Subject: [PATCH 3/5] feat: add 'No member' filter for board cards --- .../boards/BoardActions/Filters.jsx | 15 +++++++++++++++ client/src/constants/ActionTypes.js | 3 +++ client/src/constants/EntryActionTypes.js | 5 +++++ client/src/entry-actions/boards.js | 10 ++++++++++ client/src/locales/en-US/core.js | 1 + client/src/models/Board.js | 19 +++++++++++++++++++ client/src/models/List.js | 5 +++++ client/src/sagas/core/services/boards.js | 18 ++++++++++++++++++ client/src/sagas/core/watchers/boards.js | 8 ++++++++ 9 files changed, 84 insertions(+) diff --git a/client/src/components/boards/BoardActions/Filters.jsx b/client/src/components/boards/BoardActions/Filters.jsx index b193a7ed..3aaa71bb 100644 --- a/client/src/components/boards/BoardActions/Filters.jsx +++ b/client/src/components/boards/BoardActions/Filters.jsx @@ -147,6 +147,14 @@ const Filters = React.memo(() => { const isSearchActive = search || isSearchFocused; + const handleNoMemberClick = useCallback(() => { + if (board.filterNoMember) { + dispatch(entryActions.removeNoMemberFromFilterInCurrentBoard()); + } else { + dispatch(entryActions.setNoMemberToFilterInCurrentBoard()); + } + }, [dispatch, board.filterNoMember]); + return ( <> @@ -161,6 +169,13 @@ const Filters = React.memo(() => { {userIds.length === 0 && {t('common.all')}} + {userIds.length === 0 && withCurrentUserSelector && (