Skip to content
Merged
Show file tree
Hide file tree
Changes from 45 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
38ca029
Add es6-slide-up-down dependency
myabc Jun 30, 2025
54eb1a0
Add Delegate dependency
myabc Oct 28, 2025
9c5c58c
[#65618] Remove jQuery from core
myabc Oct 28, 2025
2b731a5
Remove unused import in main-menu-toggle service
myabc Oct 29, 2025
184f042
Remove jQuery from spec support files
myabc Oct 29, 2025
5c7ccd2
Remove unnecessary closestWithContext helper function (#20844)
Copilot Oct 29, 2025
6ddd7d2
Merge branch 'bug/68679-session-ttl-not-toggleable' into code-mainten…
myabc Oct 31, 2025
cce4b40
Fix selectors in action-menu functions
myabc Nov 2, 2025
0e77814
Merge branch 'dev' into code-maintenance/rid-jquery
myabc Nov 2, 2025
d373a1b
Remove unused new message form on Forum show page
myabc Nov 2, 2025
293d93f
Remove unused inline edit form on News show page
myabc Nov 2, 2025
ca48d18
Rework WP Bulk Delete Danger Zone with Stimulus
myabc Nov 2, 2025
04f6449
Fix persistent-toggle handling no notifications
myabc Nov 2, 2025
9c0e223
[#68740] Fix Repository Revision compare radios
myabc Nov 2, 2025
bee6fd5
Remove jQuery from Wiki destroy form
myabc Nov 2, 2025
722f1d4
Remove jQuery from csp_onclick helper
myabc Nov 2, 2025
d05716a
Rework Repositories diff page with Stimulus
myabc Nov 2, 2025
207fbbe
Remove jQuery from Subversion settings form
myabc Nov 2, 2025
435268b
Merge branch 'dev' into code-maintenance/rid-jquery
myabc Nov 3, 2025
c9748dd
Fix event dispatch for Boards toolbar 'Rename view'
myabc Nov 3, 2025
27c6fb8
Teach modal wrapper service to handle missing link
myabc Nov 3, 2025
81493f9
Teach wp-timeline-cell tp handle null cellElement
myabc Nov 3, 2025
2e879e0
Ignore Rails/OutputSafety cop for csp_onclick
myabc Nov 3, 2025
9d60ac7
DRY up meta tag parsing with getMeta* helpers
myabc Nov 3, 2025
bd8154d
Fix invalid :first pseudo-class selector to use standard CSS
Copilot Nov 3, 2025
8284389
Fix calls to getPosition, argument typing
myabc Nov 3, 2025
189d43f
Fix timeline visibility
myabc Nov 3, 2025
43ea22d
Fix critical jQuery migration bugs in timeline and selection handling
Copilot Oct 29, 2025
53f3611
Fix timeline width calculation to use first child instead of sum
Copilot Oct 29, 2025
e2897d0
Fix TS2322 error in event-helpers.ts type handling
Copilot Oct 29, 2025
d2dcfd5
Add fallback to body width for timeline width calculation
Copilot Oct 29, 2025
d130257
Update getMetaElement to properly escape name
myabc Nov 3, 2025
7fcf2dc
Fix ESLint false positives for no-unused-vars
myabc Nov 3, 2025
c2594bd
Remove return true/false from event handlers and fix CustomEvent bubbles
myabc Nov 3, 2025
3a5a8bc
Fix width calculation to use offsetWidth instead of style.width
Copilot Nov 3, 2025
0c065cb
Fix getScrollParent to start from parentElement to match jQuery behavior
Copilot Nov 3, 2025
9a52cbc
Fix selector used in keyboard-shortcut service
myabc Nov 3, 2025
c901941
Make single-row-builder handle null row instances
myabc Nov 3, 2025
0143e7c
Merge branch 'dev' into code-maintenance/rid-jquery
myabc Nov 4, 2025
8309b32
Fix missing variable declaration in Backlogs
myabc Nov 4, 2025
b958b5b
Modernize Backlogs server variables: use const/let
myabc Nov 4, 2025
b9f04df
Fix Capybara locator type warnings in Backlogs
myabc Nov 4, 2025
829818d
Fix single-hierarchy-row-builder w/null subject cell
myabc Nov 4, 2025
7e63b60
Fix focusing on first context menu item
myabc Nov 3, 2025
93f508e
Ensure Work Package Export scenario awaits dialog
myabc Nov 4, 2025
dbb5534
Replace jQuery in work_package_full_view_tour.ts
myabc Nov 4, 2025
0aeeb3d
Remove unused js format from CategoriesController
myabc Nov 4, 2025
bfac4c2
Remove unused versions/create.js.erb view
myabc Nov 4, 2025
51d3486
Rework Wiki edit parent page form with Stimulus
myabc Nov 4, 2025
6d190e2
Remove unused session/_warn_logout.js.erb view
myabc Nov 4, 2025
37dcd13
Remove unused inline script from Cost Types list
myabc Nov 4, 2025
9e0b6f5
Remove unused jQuery typings
myabc Nov 4, 2025
91d2391
Add debounce to select-autosize controller
myabc Nov 5, 2025
7cad4d2
Ensure csp_onclick escapes selector
myabc Nov 5, 2025
e039c64
Merge branch 'dev' into code-maintenance/rid-jquery
myabc Nov 5, 2025
78834a5
Replace innerHTML approach with DOMParser for HTML text extraction
Copilot Nov 5, 2025
cdf1586
Remove unnecessary vendor prefixes from calendar gradient
Copilot Nov 5, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion app/helpers/removed_js_helpers_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ def link_to_function(content, function, html_options = {})
# Execute the callback on click
def csp_onclick(callback_str, selector, prevent_default: true)
content_for(:additional_js_dom_ready) do
"jQuery('#{selector}').click(function() { #{callback_str}; #{prevent_default ? 'return false;' : ''} });\n".html_safe
raw <<~JS # rubocop:disable Rails/OutputSafety
document.querySelector('#{selector}')?.addEventListener('click', function(event) {
#{callback_str&.delete_suffix(';')};#{"\n event.preventDefault();" if prevent_default}
});
JS
Comment on lines 48 to 52
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The csp_onclick method is vulnerable to XSS injection. The selector and callback_str parameters are directly interpolated into JavaScript without escaping. If user-controlled data reaches these parameters, malicious JavaScript could be executed. Consider using proper JavaScript escaping or a safer templating approach.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@oliverguenther I think we can live with this. User-generated data should never be passed to this method.

end
end
Comment on lines 46 to 54
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The csp_onclick helper interpolates user-provided strings directly into JavaScript without escaping (#{selector} and #{callback_str}). This creates a potential XSS vulnerability if the selector or callback contains malicious content. Use proper JavaScript escaping (e.g., j() or escape_javascript()) for both selector and callback_str.

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed escaping of selector arguments I think we can safely ignore warnings for callback_str - I can't see a way around this without full-on parsing the script. This method should never be used with user-generated content and is deprecated anyway!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Check

end
23 changes: 0 additions & 23 deletions app/views/forums/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,6 @@ See COPYRIGHT and LICENSE files for more details.

++#%>

<div id="add-message" style="display:none;">
<% if authorize_for('messages', 'new') %>
<h2><%= link_to h(@forum.name), project_forum_path(@project, @forum) %> &#187; <%= t(:label_message_new) %></h2>
<%= labelled_tabular_form_for Message.new(project: @project),
url: forum_topics_path(@forum),
html: {
multipart: true,
id: "message-form",
class: "form",
data: { turbo: false }
} do |f| %>
<%= render partial: "messages/form", locals: { f: f } %>

<hr class="form--separator">
<%= styled_button_tag t(:button_create), class: "-primary -with-icon icon-checkmark" %>
<%= link_to t(:button_cancel), "", class: "cancel-add-message-button button -with-icon icon-cancel" %>
<% csp_onclick('jQuery("#add-message").hide();', ".cancel-add-message-button") %>
<% end %>
<div id="preview"></div>
<% end %>
</div>
Comment on lines -30 to -50
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Check - I don't think we're displaying this form anywhere any more.


<%=
render(Primer::OpenProject::PageHeader.new) do |header|
header.with_title { @forum.name }
Expand All @@ -70,7 +48,6 @@ See COPYRIGHT and LICENSE files for more details.
leading_icon: :plus,
label: t(:label_message_new),
tag: :a,
class: "add-message-button",
href: url_for({ controller: "/messages", action: "new", forum_id: @forum })) do
t(:label_message)
end
Expand Down
10 changes: 3 additions & 7 deletions app/views/layouts/base.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,10 @@ See COPYRIGHT and LICENSE files for more details.
}

wrapper.style.display = '';
<% end %>

<%= nonced_javascript_tag do %>
(function($) {
// Wrapper for page-specific JS from deprecated inline functions
// no longer available with CSP.
<%= content_for :additional_js_dom_ready %>
}(jQuery));
// Wrapper for page-specific JS from deprecated inline functions
// no longer available with CSP.
<%= content_for :additional_js_dom_ready %>
<% end %>
<div class="op-wide-autocomplete-wrapper"></div>
<%= call_hook :view_layouts_base_body_bottom %>
Expand Down
11 changes: 0 additions & 11 deletions app/views/news/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ See COPYRIGHT and LICENSE files for more details.
aria: { label: I18n.t(:button_edit) },
title: I18n.t(:button_edit)
) do |button|
csp_onclick('jQuery("#edit-news").show()', ".edit-news-button")
button.with_leading_visual_icon(icon: :pencil)
t(:button_edit)
end
Expand All @@ -72,16 +71,6 @@ See COPYRIGHT and LICENSE files for more details.
end
%>

<% if authorize_for('news', 'edit') %>
<div id="edit-news" style="display:none;">
<%= labelled_tabular_form_for @news, html: { id: "news-form" } do |f| %>
<%= render partial: "form", locals: { f: f } %>
<%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %>
<%= link_to_function t(:button_cancel), 'jQuery("#edit-news").hide()',
class: "button -with-icon icon-cancel" %>
<% end %>
</div>
<% end %>
Comment on lines -75 to -84
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Check - I also don't think we're displaying this form.

<% if @news.summary.present? %>
<div class="summary">
<%= format_text(@news, :summary) %>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,16 @@ See COPYRIGHT and LICENSE files for more details.
) %>
<%=
content_for(:additional_js_dom_ready) do
"jQuery('#repository-password-placeholder')
.change(function() { this.name = 'repository[password]'; })
.focus(function() { this.value = ''; this.name = 'repository[password]'; });
".html_safe
raw <<~JS
const placeholder = document.getElementById('repository-password-placeholder');
placeholder?.addEventListener('input', function(event) {
placeholder.name = 'repository[password]';
});
placeholder?.addEventListener('focus', function(event) {
placeholder.value = '';
placeholder.name = 'repository[password]';
});
JS
Comment on lines +70 to +79
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ported this over, but don't really understand why we need to do this.

end
%>
</div>
10 changes: 6 additions & 4 deletions app/views/repositories/_revisions.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,9 @@ See COPYRIGHT and LICENSE files for more details.
(line_num == 1),
id: "cb-#{line_num}" %>
<% csp_onclick(
"jQuery('#cbto-#{line_num + 1}').attr('checked', true);",
"cb-#{line_num}"
"document.getElementById('cbto-#{line_num + 1}').checked = true;",
"#cb-#{line_num}",
prevent_default: false
) %>
<% end %>
</td>
Expand All @@ -134,8 +135,9 @@ See COPYRIGHT and LICENSE files for more details.
(line_num == 2),
id: "cbto-#{line_num}" %>
<% csp_onclick(
"if (jQuery('#cb-#{line_num}').attr('checked')) {jQuery('#cb-#{line_num - 1}').attr('checked', true)}",
"cbto-#{line_num}"
"if (document.getElementById('cb-#{line_num}')?.checked) {document.getElementById('cb-#{line_num - 1}').checked = true;}",
"#cbto-#{line_num}",
prevent_default: false
) %>
<% end %>
</td>
Expand Down
20 changes: 9 additions & 11 deletions app/views/repositories/diff.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,16 @@ See COPYRIGHT and LICENSE files for more details.
end
%>
<div class="repository-input-group">
<%= form_tag({repo_path: to_path_param(@path)}, method: :get) do %>
<%= hidden_field_tag('rev', params[:rev]) if params[:rev] %>
<%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %>
<%= styled_select_tag 'type', options_for_select([[t(:label_diff_inline), "inline"], [t(:label_diff_side_by_side), "sbs"]], @diff_type), id: "repository-diff-type-select" %>
<%= form_tag({ repo_path: to_path_param(@path) }, method: :get, data: { controller: "auto-submit" }) do %>
<%= hidden_field_tag("rev", params[:rev]) if params[:rev] %>
<%= hidden_field_tag("rev_to", params[:rev_to]) if params[:rev_to] %>
<%= styled_select_tag "type",
options_for_select(
[[t(:label_diff_inline), "inline"],
[t(:label_diff_side_by_side), "sbs"]], @diff_type
),
data: { action: "auto-submit#submit" } %>
<% end %>
<%=
content_for(:additional_js_dom_ready) do
"jQuery('#repository-diff-type-select').change(function() {
if (this.value != '') { this.form.submit() }
});".html_safe
end
%>
</div>
<% cache(@cache_key) do -%>
<%= render partial: 'common/diff', locals: { diff: @diff, diff_type: @diff_type } %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/wiki/destroy.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ See COPYRIGHT and LICENSE files for more details.
<%= styled_select_tag "reassign_to_id",
options_for_select(wiki_page_options_for_select(@reassignable_to)),
{ container_class: "-wide" } %>
<% csp_onclick("jQuery('#todo_reassign').attr('checked', true)", "#reassign_to_id") %>
<% csp_onclick("document.getElementById('todo_reassign').checked = true", "#reassign_to_id") %>
</div>
<% end %>

Expand Down
43 changes: 34 additions & 9 deletions app/views/work_packages/bulk/destroy.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@ See COPYRIGHT and LICENSE files for more details.
++#%>
<%= error_messages_for work_packages.first %>

<%= styled_form_tag work_packages_bulk_path, method: :delete, class: "form danger-zone" do %>
<%=
styled_form_tag(
work_packages_bulk_path,
method: :delete,
class: "form danger-zone",
data: {
controller: "show-when-value-selected"
}
) do
%>
<%= back_url_hidden_field_tag unless back_url_is_wp_show? %>
<% work_packages.each do |work_package| %>
<%= hidden_field_tag "ids[]", work_package.id %>
Expand All @@ -49,33 +58,49 @@ See COPYRIGHT and LICENSE files for more details.
<div class="form--field -trailing-label">
<%= styled_label_tag :to_do_action_destroy, t(:text_destroy) %>
<div class="form--field-container">
<%= styled_radio_button_tag "to_do[action]", "destroy" %>
<%= styled_radio_button_tag "to_do[action]", "destroy", nil,
data: {
show_when_value_selected_target: "cause",
target_name: "action"
} %>
</div>
</div>
<div class="form--field -trailing-label">
<%= styled_label_tag "to_do_action_nullify", t(:text_assign_to_project) %>
<div class="form--field-container">
<%= styled_radio_button_tag "to_do[action]", "nullify" %>
<%= styled_radio_button_tag "to_do[action]", "nullify", nil,
data: {
show_when_value_selected_target: "cause",
target_name: "action"
} %>
</div>
</div>
<div class="grid-block">
<div class="grid-block small-3">
<div class="form--field -trailing-label">
<%= styled_label_tag "to_do_action_reassign", t(:text_reassign) %>
<div class="form--field-container">
<%= styled_radio_button_tag "to_do[action]", "reassign" %>
<% csp_onclick(
'if(jQuery("#to_do_action_reassign").prop("checked")) { jQuery("#to_do_reassign_to_id").focus(); }',
"#reassign"
) %>
<%= styled_radio_button_tag "to_do[action]", "reassign", nil,
data: {
show_when_value_selected_target: "cause",
target_name: "action"
} %>
</div>
</div>
</div>
<div class="grid-block">
<div class="form--field">
<div class="form--text-field-container -xslim">
<%= styled_label_tag "to_do_reassign_to_id", t(:text_reassign), class: "form--label sr-only" %>
<%= f.text_field "reassign_to_id", placeholder: WorkPackage.human_attribute_name(:id), value: params[:reassign_to_id], size: 6, onfocus: 'jQuery("#to_do_action_reassign").prop("checked", true);' %>
<%= f.text_field "reassign_to_id",
placeholder: WorkPackage.human_attribute_name(:id), value: params[:reassign_to_id],
size: 6,
hidden: true,
data: {
show_when_value_selected_target: "effect",
target_name: "action",
value: "reassign"
} %>
</div>
</div>
</div>
Expand Down
10 changes: 1 addition & 9 deletions frontend/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,7 @@ export default defineConfig([
},
],

// Sometimes we need to shush the TypeScript compiler
'no-unused-vars': ['error', { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }],
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error', { varsIgnorePattern: '^_', argsIgnorePattern: '^_' }],

// Allow short circuit evaluations
Expand Down Expand Up @@ -154,13 +153,6 @@ export default defineConfig([
'@angular-eslint/template/prefer-control-flow': 'error'
}
},
{
files: ['**/*.d.ts'],
rules: {
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': 'off',
},
},
{
files: ['**/*.spec.ts'],
plugins: { jasmine },
Expand Down
24 changes: 24 additions & 0 deletions frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"@hotwired/stimulus": "^3.2.2",
"@hotwired/turbo": "^8.0.20",
"@hotwired/turbo-rails": "^8.0.20",
"@knowledgecode/delegate": "^0.8.5",
"@kolkov/ngx-gallery": "^2.0.1",
"@mantine/core": "^8.3.6",
"@mantine/hooks": "^8.3.5",
Expand Down Expand Up @@ -137,6 +138,7 @@
"dom-autoscroller": "^2.2.8",
"dom-plane": "^1.0.2",
"dragula": "^3.7.3",
"es6-slide-up-down": "^1.0.0",
"flatpickr": "^4.6.13",
"glob": "^11.0.3",
"hammerjs": "^2.0.8",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { PathHelperService } from 'core-app/core/path-helper/path-helper.service
import { CurrentProjectService } from './current-project.service';

describe('currentProject service', () => {
let element:JQuery;
let element:HTMLMetaElement;
let currentProject:CurrentProjectService;

const apiV3Stub:any = {
Expand All @@ -55,12 +55,12 @@ describe('currentProject service', () => {

describe('with a meta value present', () => {
beforeEach(() => {
const html = `
<meta name="current_project" data-project-name="Foo 1234" data-project-id="1" data-project-identifier="foobar"/>
`;

element = jQuery(html);
jQuery(document.body).append(element);
element = document.createElement('meta');
element.setAttribute('name', 'current_project');
element.dataset.projectName = 'Foo 1234';
element.dataset.projectId = '1';
element.dataset.projectIdentifier = 'foobar';
document.head.appendChild(element);
currentProject.detect();
});

Expand Down
Loading
Loading