Skip to content

Commit 9b06dcf

Browse files
committed
Gate Select All on unlocked projects and harden select-all JS
- Only render the Select All checkbox when the project is unlocked, matching Add a Story and the bulk-delete control (addresses the review question about the unlocked check). Add a spec that it is hidden on a locked project. - Make updateSelectAllStatus null-safe so toggling a row checkbox on a locked project (where Select All is absent) no longer throws. - Clean up the extracted updateBulkDeleteStatus indentation and file newline. - De-flake the madmin projects spec via CGI.escapeHTML (same fix as PR #333).
1 parent a2f408a commit 9b06dcf

3 files changed

Lines changed: 45 additions & 29 deletions

File tree

app/assets/javascripts/project.js

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@ document.addEventListener("turbolinks:load", function () {
44
updateSelectAllStatus();
55
});
66

7-
87
$(".import-export-header").click(function () {
98
$(this).children(".rotate").toggleClass("left");
109
});
1110

12-
1311
$("#select_all").click((event) => {
1412
let checked = event.target.checked;
1513

@@ -117,37 +115,44 @@ function toggleCloneSubProjects(value) {
117115

118116
function updateBulkDeleteStatus() {
119117
const selected = $("input[name='stories[]']:checked");
120-
const is_unlocked = $("#stories").data("unlocked");
121-
if (!is_unlocked) {
122-
return;
123-
}
118+
const is_unlocked = $("#stories").data("unlocked");
119+
if (!is_unlocked) {
120+
return;
121+
}
124122

125-
if (selected.length > 0) {
126-
const ending = selected.length == 1 ? "y" : "ies";
127-
$("#bulk_delete")
128-
.text(`Bulk Delete (${selected.length} Stor${ending})`)
129-
.attr("aria-disabled", "false")
130-
.prop("disabled", false);
131-
} else {
132-
$("#bulk_delete")
133-
.text("Bulk Delete")
134-
.attr("aria-disabled", "true")
135-
.prop("disabled", true);
136-
}
123+
if (selected.length > 0) {
124+
const ending = selected.length == 1 ? "y" : "ies";
125+
$("#bulk_delete")
126+
.text(`Bulk Delete (${selected.length} Stor${ending})`)
127+
.attr("aria-disabled", "false")
128+
.prop("disabled", false);
129+
} else {
130+
$("#bulk_delete")
131+
.text("Bulk Delete")
132+
.attr("aria-disabled", "true")
133+
.prop("disabled", true);
134+
}
137135
}
138136

139137
function updateSelectAllStatus() {
138+
const selectAll = $("#select_all")[0];
139+
// Select All is only rendered for unlocked projects, so there is nothing to
140+
// sync when it is absent.
141+
if (!selectAll) {
142+
return;
143+
}
144+
140145
const selected = $("input[name='stories[]']:checked");
141146
const checkboxes = $("input[name='stories[]']");
142147

143148
if (selected.length == 0) {
144-
$("#select_all")[0].checked = false;
145-
$("#select_all")[0].indeterminate = false;
149+
selectAll.checked = false;
150+
selectAll.indeterminate = false;
146151
} else if (selected.length == checkboxes.length) {
147-
$("#select_all")[0].checked = true;
148-
$("#select_all")[0].indeterminate = false;
152+
selectAll.checked = true;
153+
selectAll.indeterminate = false;
149154
} else {
150-
$("#select_all")[0].checked = false;
151-
$("#select_all")[0].indeterminate = true;
155+
selectAll.checked = false;
156+
selectAll.indeterminate = true;
152157
}
153-
}
158+
}

app/views/projects/show.html.erb

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
<th class="project-table__cell">Best<br />Estimate</th>
1919
<th class="project-table__cell">Worst<br />Estimate</th>
2020
<th class="project-table__cell story_actions">
21-
<div>
22-
<input type="checkbox" name="select_all" id="select_all">
23-
<label for="select_all">Select All</label>
24-
</div>
21+
<% if is_unlocked?(@project) %>
22+
<div>
23+
<input type="checkbox" name="select_all" id="select_all">
24+
<label for="select_all">Select All</label>
25+
</div>
26+
<% end %>
2527
<%= link_unless_archived(@project, "Add a Story", new_project_story_path(@project), classes: "green") if is_unlocked?(@project) %>
2628
<button id="bulk_delete" class="button magenta" aria-disabled="true" disabled>Bulk Delete</button>
2729
</th>

spec/features/stories_manage_spec.rb

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@
123123
expect(page).to have_unchecked_field(name: "stories[]")
124124
end
125125

126+
it "does not show Select All on a locked project" do
127+
locked_project = FactoryBot.create(:project, :locked)
128+
FactoryBot.create(:story, project: locked_project)
129+
130+
visit project_path(id: locked_project.id)
131+
132+
expect(page).to have_no_field("Select All")
133+
end
134+
126135
it "allows me to delete a story" do
127136
visit project_path(id: project.id)
128137

0 commit comments

Comments
 (0)