From b7a00948ddd28b6d7fbaca186fb74d7187504b69 Mon Sep 17 00:00:00 2001 From: Maciej Barelkowski Date: Fri, 22 Sep 2023 14:51:59 +0200 Subject: [PATCH 1/2] feat: workaround `isEdited` race condition Related to https://github.com/camunda/camunda-modeler/issues/3815 Co-authored-by: Beatriz Mendes --- src/components/Group.js | 30 +++++++++++++++++------------- test/spec/components/Group.spec.js | 5 +++++ 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/src/components/Group.js b/src/components/Group.js index 4364acc9..a175473a 100644 --- a/src/components/Group.js +++ b/src/components/Group.js @@ -58,25 +58,29 @@ export default function Group(props) { // set edited state depending on all entries useEffect(() => { - const hasOneEditedEntry = entries.find(entry => { - const { - id, - isEdited - } = entry; + const scheduled = requestAnimationFrame(() => { + const hasOneEditedEntry = entries.find(entry => { + const { + id, + isEdited + } = entry; - const entryNode = domQuery(`[data-entry-id="${id}"]`); + const entryNode = domQuery(`[data-entry-id="${id}"]`); - if (!isFunction(isEdited) || !entryNode) { - return false; - } + if (!isFunction(isEdited) || !entryNode) { + return false; + } + + const inputNode = domQuery('.bio-properties-panel-input', entryNode); - const inputNode = domQuery('.bio-properties-panel-input', entryNode); + return isEdited(inputNode); + }); - return isEdited(inputNode); + setEdited(hasOneEditedEntry); }); - setEdited(hasOneEditedEntry); - }, [ entries ]); + return () => cancelAnimationFrame(scheduled); + }, [ entries, setEdited ]); // set error state depending on all entries const allErrors = useErrors(); diff --git a/test/spec/components/Group.spec.js b/test/spec/components/Group.spec.js index 40a90286..850baaca 100644 --- a/test/spec/components/Group.spec.js +++ b/test/spec/components/Group.spec.js @@ -43,6 +43,11 @@ describe('', function() { container = TestContainer.get(this); }); + beforeEach(() => { + const requestAnimationFrameSpy = sinon.fake.returns(cb => cb()); + global.window.requestAnimationFrame = requestAnimationFrameSpy(); + }); + it('should render', function() { From 7c9d25afcf94f26b7204da2a27411531e5582ed5 Mon Sep 17 00:00:00 2001 From: Maciej Barelkowski Date: Mon, 25 Sep 2023 15:38:27 +0200 Subject: [PATCH 2/2] chore: apply suggestions from code review --- package-lock.json | 3 +++ src/components/Group.js | 2 ++ test/spec/components/Group.spec.js | 7 +++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index d4ad3856..da3c6b04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,6 +62,9 @@ "sinon-chai": "^3.7.0", "sirv-cli": "^1.0.12", "webpack": "^5.74.0" + }, + "engines": { + "node": "*" } }, "node_modules/@aashutoshrathi/word-wrap": { diff --git a/src/components/Group.js b/src/components/Group.js index a175473a..b959c147 100644 --- a/src/components/Group.js +++ b/src/components/Group.js @@ -58,6 +58,8 @@ export default function Group(props) { // set edited state depending on all entries useEffect(() => { + + // TODO(@barmac): replace with CSS when `:has()` is supported in all major browsers, or rewrite as in https://github.com/camunda/camunda-modeler/issues/3815#issuecomment-1733038161 const scheduled = requestAnimationFrame(() => { const hasOneEditedEntry = entries.find(entry => { const { diff --git a/test/spec/components/Group.spec.js b/test/spec/components/Group.spec.js index 850baaca..02393c5f 100644 --- a/test/spec/components/Group.spec.js +++ b/test/spec/components/Group.spec.js @@ -44,8 +44,11 @@ describe('', function() { }); beforeEach(() => { - const requestAnimationFrameSpy = sinon.fake.returns(cb => cb()); - global.window.requestAnimationFrame = requestAnimationFrameSpy(); + sinon.replace(window, 'requestAnimationFrame', cb => cb()); + }); + + afterEach(() => { + sinon.restore(); });