-
Notifications
You must be signed in to change notification settings - Fork 124
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[JENKINS-73875] CSP compatibility for NewNodeConsoleNote
#477
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked some other plugins in jenkinsci
and found that the typical pattern is to iterate over all elements of a given class with e.g. document.querySelectorAll
and then add click handlers to just those elements. That seems a little cleaner than adding a click listener on the body element which is a no-op in the vast majority of cases. For example, from jenkins/core/src/main/resources/hudson/PluginManager/_installed.js
:
document.addEventListener("DOMContentLoaded", function () {
document
.querySelectorAll(".plugin-manager-toggle-switch")
.forEach(function (toggle) {
toggle.addEventListener("click", flip);
});
});
Hi @basil, I am running into an issue when trying to do it as you described above. The links to for the toggles do not appear directly after DOMContentLoaded is triggered. For example, in the below console logs, you can see that those elements don't actually appear in the html tree until all of the dependent resources are loaded. DOMContentLoaded: Number of .pipeline-toggle elements: 0 What do you think is the best approach in this situation? is it to use or perhaps continue to use the event delegation approach but narrow down the parent element to the one that contains the toggles instead of the entire Thank you |
Not sure offhand, but the event handler at the top of the file (the third argument to |
@basil https://www.loom.com/share/d8f0b84fca3f4b218f7d656f268394eb?sid=8b5e1d8e-5de0-43b3-a511-ba3c3737823e It is working correctly with the new change |
// TODO automatically hide second and subsequent branches: namely, in case a node has the same parent as an earlier one | ||
|
||
const toggle = e.querySelector('.pipeline-toggle'); | ||
if (toggle) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why would this element ever not be present if we just added it a few lines earlier? I cannot see the purpose of this if
statement.
// TODO automatically hide second and subsequent branches: namely, in case a node has the same parent as an earlier one | ||
|
||
const toggle = e.querySelector('.pipeline-toggle'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure this is always matching the <span class="pipeline-show-hide">
that we just added on line 17 above? That code is appending <span class="pipeline-show-hide">
elements as children of e
, so I am wondering if there might ever be two such children or if there is always one as in your test. Did you try testing nested parallel
blocks?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using the below script configuration
parallel first: {
stage('First Nested') {
parallel nestedA: {}, nestedB: {}
}
}, second: {
stage('"full" details') {
parallel nestedC: {}, nestedD: {}
}
}
I recorded the behavior of the toggle links:
https://www.loom.com/share/2acb8c6b041a449793132e3f4a433d70
Everything seems to be working okay. Can you confirm if this is the intended behavior?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I am glad the testing is passing. To make this bulletproof, I think we should select the last child with the pipeline-show-hide
class rather than the first. Since the /.+/
regular expression is always appending the new <span>
element to the end of the list of child nodes, selecting the last child should always match the node we just added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for explaining that detail. New commit addresses this
// TODO automatically hide second and subsequent branches: namely, in case a node has the same parent as an earlier one | ||
|
||
const toggle = e.querySelector('.pipeline-show-hide:last-child .pipeline-toggle'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer querySelectorAll
to reliably select the last .pipeline-toggle
element, as it works regardless of the DOM structure:
const toggle = e.querySelector('.pipeline-show-hide:last-child .pipeline-toggle'); | |
const toggles = e.querySelectorAll('.pipeline-show-hide .pipeline-toggle'); | |
const toggle = toggles[toggles.length - 1]; |
Picking the last item in the list ensures the correct element is always selected, even if e
contains multiple .pipeline-show-hide elements
. In contrast, querySelector('.pipeline-show-hide:last-child .pipeline-toggle')
only works if .pipeline-show-hide
is the last child of its parent, making it fragile if the DOM changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Understood, sorry for the back and forth with this change.
I appreciate your explanation and will note it moving forward.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @shlomomdahan! Approving pending one last piece of feedback. Can you please test this in ATH as in jenkinsci/acceptance-test-harness#1772 and then I will be ready to merge/release this.
const toggle = toggles[toggles.length - 1]; | ||
toggle.addEventListener('click', function(event) { | ||
event.preventDefault(); | ||
showHidePipelineSection(this); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As in jenkinsci/job-config-history-plugin#338 (comment), I think it would be more readable to use toggle
instead of button
here.
script.js
script.js
NewNodeConsoleNote
Created a ticket in JIRA to track this issue: JENKINS-73875
Removed inline onClick handler from script.js to comply with Content Security Policy and replaced with event delegation.
Testing done
STATUS QUO: No changes implemented. This is the intended functionality.
https://www.loom.com/share/da8a1ab0f1d8431e858da2ae3ac7215f?sid=2dedd5ac-eb73-472b-a0ae-11e39daff80c
NON RESTRICTIVE: This is the behavior after implementing the CSP changes. The code is working just as before and there is no regression in functionality.
https://www.loom.com/share/1f9479eeb2cf4829bdcf524d6f4d1a37?sid=cfd60732-705b-4874-9ae0-97ae1747b2d2
RESTRICTIVE: This is with CSP restrictive mode enabled. It is working correctly as intended without any issues.
https://www.loom.com/share/cad50c0d86af4e5d9ea467152a54ab08
Submitter checklist