From 71d0815891b40ff1857312fa9ea39b4b31e284ff Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sat, 16 Nov 2024 18:13:13 +0100 Subject: [PATCH 01/20] fix: Consider language specifics when parsing time Closes #946 --- .../DueDateEditStep/DueDateEditStep.jsx | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/client/src/components/DueDateEditStep/DueDateEditStep.jsx b/client/src/components/DueDateEditStep/DueDateEditStep.jsx index 9c9c1f3b..530e85db 100755 --- a/client/src/components/DueDateEditStep/DueDateEditStep.jsx +++ b/client/src/components/DueDateEditStep/DueDateEditStep.jsx @@ -67,11 +67,18 @@ const DueDateEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) return; } - const value = parseTime(data.time, nullableDate); + let value = t('format:dateTime', { + postProcess: 'parseDate', + value: `${data.date} ${data.time}`, + }); if (Number.isNaN(value.getTime())) { - timeField.current.select(); - return; + value = parseTime(data.time, nullableDate); + + if (Number.isNaN(value.getTime())) { + timeField.current.select(); + return; + } } if (!defaultValue || value.getTime() !== defaultValue.getTime()) { @@ -79,7 +86,7 @@ const DueDateEditStep = React.memo(({ defaultValue, onUpdate, onBack, onClose }) } onClose(); - }, [defaultValue, onUpdate, onClose, data, nullableDate]); + }, [defaultValue, onUpdate, onClose, data, nullableDate, t]); const handleClearClick = useCallback(() => { if (defaultValue) { From 1a70b2b7e6f67cb81336cf539794643ea28098bb Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sun, 17 Nov 2024 23:37:43 +0100 Subject: [PATCH 02/20] fix: Prevent list with multiline title from overflowing board view Closes #377 --- client/src/components/List/List.jsx | 12 +++--------- client/src/components/List/List.module.scss | 8 +++----- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/client/src/components/List/List.jsx b/client/src/components/List/List.jsx index 25c85e58..e09a7a14 100755 --- a/client/src/components/List/List.jsx +++ b/client/src/components/List/List.jsx @@ -32,7 +32,7 @@ const List = React.memo( const [isAddCardOpened, setIsAddCardOpened] = useState(false); const nameEdit = useRef(null); - const listWrapper = useRef(null); + const cardsWrapper = useRef(null); const handleHeaderClick = useCallback(() => { if (isPersisted && canEdit) { @@ -67,7 +67,7 @@ const List = React.memo( useEffect(() => { if (isAddCardOpened) { - listWrapper.current.scrollTop = listWrapper.current.scrollHeight; + cardsWrapper.current.scrollTop = cardsWrapper.current.scrollHeight; } }, [cardIds, isAddCardOpened]); @@ -133,13 +133,7 @@ const List = React.memo( )} -
+
{cardsNode}
{!isAddCardOpened && canEdit && ( diff --git a/client/src/components/List/List.module.scss b/client/src/components/List/List.module.scss index 4e579d66..6de525cf 100644 --- a/client/src/components/List/List.module.scss +++ b/client/src/components/List/List.module.scss @@ -40,7 +40,6 @@ } .cardsInnerWrapper { - max-height: calc(100vh - 268px); overflow-x: hidden; overflow-y: auto; width: 290px; @@ -62,10 +61,6 @@ } } - .cardsInnerWrapperFull { - max-height: calc(100vh - 232px); - } - .cardsOuterWrapper { padding: 0 8px; white-space: normal; @@ -140,6 +135,9 @@ .outerWrapper { background: #dfe3e6; border-radius: 3px; + display: flex; + flex-direction: column; + max-height: calc(100vh - 198px); overflow: hidden; } } From 5a3c3bb39bc9feb899abd34b33f122cbcd6eb154 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Sun, 17 Nov 2024 23:45:29 +0100 Subject: [PATCH 03/20] fix: Disable pointer events when dragging --- client/src/components/Board/Board.jsx | 4 ++++ client/src/components/Boards/Boards.jsx | 4 ++++ client/src/components/CardModal/Tasks/Tasks.jsx | 4 ++++ client/src/components/LabelsStep/LabelsStep.jsx | 9 ++++++++- client/src/styles.module.scss | 4 ++++ 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/client/src/components/Board/Board.jsx b/client/src/components/Board/Board.jsx index 481eaedf..b3b8acd3 100755 --- a/client/src/components/Board/Board.jsx +++ b/client/src/components/Board/Board.jsx @@ -11,6 +11,7 @@ import ListAdd from './ListAdd'; import { ReactComponent as PlusMathIcon } from '../../assets/images/plus-math-icon.svg'; import styles from './Board.module.scss'; +import globalStyles from '../../styles.module.scss'; const parseDndId = (dndId) => dndId.split(':')[1]; @@ -31,11 +32,14 @@ const Board = React.memo( }, []); const handleDragStart = useCallback(() => { + document.body.classList.add(globalStyles.dragging); closePopup(); }, []); const handleDragEnd = useCallback( ({ draggableId, type, source, destination }) => { + document.body.classList.remove(globalStyles.dragging); + if ( !destination || (source.droppableId === destination.droppableId && source.index === destination.index) diff --git a/client/src/components/Boards/Boards.jsx b/client/src/components/Boards/Boards.jsx index fad20475..b2453856 100755 --- a/client/src/components/Boards/Boards.jsx +++ b/client/src/components/Boards/Boards.jsx @@ -13,6 +13,7 @@ import AddStep from './AddStep'; import EditStep from './EditStep'; import styles from './Boards.module.scss'; +import globalStyles from '../../styles.module.scss'; const Boards = React.memo(({ items, currentId, canEdit, onCreate, onUpdate, onMove, onDelete }) => { const tabsWrapper = useRef(null); @@ -24,11 +25,14 @@ const Boards = React.memo(({ items, currentId, canEdit, onCreate, onUpdate, onMo }, []); const handleDragStart = useCallback(() => { + document.body.classList.add(globalStyles.dragging); closePopup(); }, []); const handleDragEnd = useCallback( ({ draggableId, source, destination }) => { + document.body.classList.remove(globalStyles.dragging); + if (!destination || source.index === destination.index) { return; } diff --git a/client/src/components/CardModal/Tasks/Tasks.jsx b/client/src/components/CardModal/Tasks/Tasks.jsx index 1f947e07..0d6ef5f3 100755 --- a/client/src/components/CardModal/Tasks/Tasks.jsx +++ b/client/src/components/CardModal/Tasks/Tasks.jsx @@ -10,16 +10,20 @@ import Item from './Item'; import Add from './Add'; import styles from './Tasks.module.scss'; +import globalStyles from '../../../styles.module.scss'; const Tasks = React.memo(({ items, canEdit, onCreate, onUpdate, onMove, onDelete }) => { const [t] = useTranslation(); const handleDragStart = useCallback(() => { + document.body.classList.add(globalStyles.dragging); closePopup(); }, []); const handleDragEnd = useCallback( ({ draggableId, source, destination }) => { + document.body.classList.remove(globalStyles.dragging); + if (!destination || source.index === destination.index) { return; } diff --git a/client/src/components/LabelsStep/LabelsStep.jsx b/client/src/components/LabelsStep/LabelsStep.jsx index aeabc4d6..3d09fa3f 100755 --- a/client/src/components/LabelsStep/LabelsStep.jsx +++ b/client/src/components/LabelsStep/LabelsStep.jsx @@ -13,6 +13,7 @@ import EditStep from './EditStep'; import Item from './Item'; import styles from './LabelsStep.module.scss'; +import globalStyles from '../../styles.module.scss'; const StepTypes = { ADD: 'ADD', @@ -77,8 +78,14 @@ const LabelsStep = React.memo( [onDeselect], ); + const handleDragStart = useCallback(() => { + document.body.classList.add(globalStyles.dragging); + }, []); + const handleDragEnd = useCallback( ({ draggableId, source, destination }) => { + document.body.classList.remove(globalStyles.dragging); + if (!destination || source.index === destination.index) { return; } @@ -159,7 +166,7 @@ const LabelsStep = React.memo( onChange={handleSearchChange} /> {filteredItems.length > 0 && ( - + {({ innerRef, droppableProps, placeholder }) => (
* { + pointer-events: none; + } + /* Backgrounds */ .backgroundBerryRed { From 96956e126882fd73c87ecf0b0ebb4e7491ed2d66 Mon Sep 17 00:00:00 2001 From: Maksim Eltyshev Date: Mon, 18 Nov 2024 00:00:32 +0100 Subject: [PATCH 04/20] chore: Update version --- charts/planka/Chart.yaml | 4 ++-- client/src/version.js | 2 +- package-lock.json | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/planka/Chart.yaml b/charts/planka/Chart.yaml index 75f624d6..8c01cfcf 100644 --- a/charts/planka/Chart.yaml +++ b/charts/planka/Chart.yaml @@ -15,13 +15,13 @@ type: application # 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. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.15 +version: 0.2.16 # 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 # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "1.24.0" +appVersion: "1.24.1" dependencies: - alias: postgresql diff --git a/client/src/version.js b/client/src/version.js index 21792097..bd34845a 100644 --- a/client/src/version.js +++ b/client/src/version.js @@ -1 +1 @@ -export default '1.24.0'; +export default '1.24.1'; diff --git a/package-lock.json b/package-lock.json index 39260dd0..05817c1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "planka", - "version": "1.24.0", + "version": "1.24.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "planka", - "version": "1.24.0", + "version": "1.24.1", "hasInstallScript": true, "license": "AGPL-3.0", "dependencies": { diff --git a/package.json b/package.json index 4454c614..c4d2e419 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "planka", - "version": "1.24.0", + "version": "1.24.1", "private": true, "homepage": "https://plankanban.github.io/planka", "repository": { From 2632edb44c7c5d74d9d3fc09122fd3d91a204339 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Derzsi=20D=C3=A1niel?= Date: Mon, 18 Nov 2024 23:38:52 +0200 Subject: [PATCH 05/20] fix: Lazy initialize OIDC client (#947) --- .../access-tokens/exchange-using-oidc.js | 7 +++ server/api/controllers/show-config.js | 22 +++++++++- .../users/get-or-create-one-using-oidc.js | 9 +++- server/api/hooks/oidc/index.js | 43 ++++++++++--------- 4 files changed, 58 insertions(+), 23 deletions(-) diff --git a/server/api/controllers/access-tokens/exchange-using-oidc.js b/server/api/controllers/access-tokens/exchange-using-oidc.js index 1fcf06e0..f8607688 100644 --- a/server/api/controllers/access-tokens/exchange-using-oidc.js +++ b/server/api/controllers/access-tokens/exchange-using-oidc.js @@ -3,6 +3,9 @@ const { v4: uuid } = require('uuid'); const { getRemoteAddress } = require('../../../utils/remoteAddress'); const Errors = { + INVALID_OIDC_CONFIGURATION: { + invalidOIDCConfiguration: 'Invalid OIDC configuration', + }, INVALID_CODE_OR_NONCE: { invalidCodeOrNonce: 'Invalid code or nonce', }, @@ -37,6 +40,9 @@ module.exports = { }, exits: { + invalidOIDCConfiguration: { + responseType: 'serverError', + }, invalidCodeOrNonce: { responseType: 'unauthorized', }, @@ -63,6 +69,7 @@ module.exports = { sails.log.warn(`Invalid code or nonce! (IP: ${remoteAddress})`); return Errors.INVALID_CODE_OR_NONCE; }) + .intercept('invalidOIDCConfiguration', () => Errors.INVALID_OIDC_CONFIGURATION) .intercept('invalidUserinfoConfiguration', () => Errors.INVALID_USERINFO_CONFIGURATION) .intercept('emailAlreadyInUse', () => Errors.EMAIL_ALREADY_IN_USE) .intercept('usernameAlreadyInUse', () => Errors.USERNAME_ALREADY_IN_USE) diff --git a/server/api/controllers/show-config.js b/server/api/controllers/show-config.js index 1a8207ec..1180d517 100644 --- a/server/api/controllers/show-config.js +++ b/server/api/controllers/show-config.js @@ -1,8 +1,26 @@ +const Errors = { + INVALID_OIDC_CONFIGURATION: { + invalidOidcConfiguration: 'Invalid OIDC configuration', + }, +}; + module.exports = { - fn() { + exits: { + invalidOidcConfiguration: { + responseType: 'serverError', + }, + }, + + async fn() { let oidc = null; if (sails.hooks.oidc.isActive()) { - const oidcClient = sails.hooks.oidc.getClient(); + let oidcClient; + try { + oidcClient = await sails.hooks.oidc.getClient(); + } catch (error) { + sails.log.warn(`Error while initializing OIDC client: ${error}`); + throw Errors.INVALID_OIDC_CONFIGURATION; + } const authorizationUrlParams = { scope: sails.config.custom.oidcScopes, diff --git a/server/api/helpers/users/get-or-create-one-using-oidc.js b/server/api/helpers/users/get-or-create-one-using-oidc.js index 2c3cb65f..2808fb83 100644 --- a/server/api/helpers/users/get-or-create-one-using-oidc.js +++ b/server/api/helpers/users/get-or-create-one-using-oidc.js @@ -11,6 +11,7 @@ module.exports = { }, exits: { + invalidOIDCConfiguration: {}, invalidCodeOrNonce: {}, invalidUserinfoConfiguration: {}, missingValues: {}, @@ -19,7 +20,13 @@ module.exports = { }, async fn(inputs) { - const client = sails.hooks.oidc.getClient(); + let client; + try { + client = await sails.hooks.oidc.getClient(); + } catch (error) { + sails.log.warn(`Error while initializing OIDC client: ${error}`); + throw 'invalidOIDCConfiguration'; + } let tokenSet; try { diff --git a/server/api/hooks/oidc/index.js b/server/api/hooks/oidc/index.js index 47c2bf7a..73a670f4 100644 --- a/server/api/hooks/oidc/index.js +++ b/server/api/hooks/oidc/index.js @@ -15,37 +15,40 @@ module.exports = function defineOidcHook(sails) { /** * Runs when this Sails app loads/lifts. */ - async initialize() { - if (!sails.config.custom.oidcIssuer) { + if (!this.isActive()) { return; } sails.log.info('Initializing custom hook (`oidc`)'); - - const issuer = await openidClient.Issuer.discover(sails.config.custom.oidcIssuer); - - const metadata = { - client_id: sails.config.custom.oidcClientId, - client_secret: sails.config.custom.oidcClientSecret, - redirect_uris: [sails.config.custom.oidcRedirectUri], - response_types: ['code'], - userinfo_signed_response_alg: sails.config.custom.oidcUserinfoSignedResponseAlg, - }; - - if (sails.config.custom.oidcIdTokenSignedResponseAlg) { - metadata.id_token_signed_response_alg = sails.config.custom.oidcIdTokenSignedResponseAlg; - } - - client = new issuer.Client(metadata); }, - getClient() { + async getClient() { + if (client === null && this.isActive()) { + sails.log.info('Initializing OIDC client'); + + const issuer = await openidClient.Issuer.discover(sails.config.custom.oidcIssuer); + + const metadata = { + client_id: sails.config.custom.oidcClientId, + client_secret: sails.config.custom.oidcClientSecret, + redirect_uris: [sails.config.custom.oidcRedirectUri], + response_types: ['code'], + userinfo_signed_response_alg: sails.config.custom.oidcUserinfoSignedResponseAlg, + }; + + if (sails.config.custom.oidcIdTokenSignedResponseAlg) { + metadata.id_token_signed_response_alg = sails.config.custom.oidcIdTokenSignedResponseAlg; + } + + client = new issuer.Client(metadata); + } + return client; }, isActive() { - return client !== null; + return sails.config.custom.oidcIssuer !== undefined; }, }; }; From 1d11d9e35c1ca53f762ab8cfd6d8177e52284c11 Mon Sep 17 00:00:00 2001 From: knif3 Date: Mon, 18 Nov 2024 22:43:28 +0100 Subject: [PATCH 06/20] fix: Fix path to apple-touch-icon (#948) --- client/public/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/public/index.html b/client/public/index.html index 8319461c..ae366e97 100755 --- a/client/public/index.html +++ b/client/public/index.html @@ -9,7 +9,7 @@ name="description" content="Planka is an open source project management software" /> - +