Project

General

Profile

Defect #44639 » 0001-Fix-Gantt-project-collapse-when-an-intermediate-project-is-not-visible.patch

Katsuya HIDAKA, 2026-10-19 08:26

View differences:

lib/redmine/helpers/gantt.rb
228 228
        @columns[options[:column].name] = +'' if options[:only] == :selected_columns && @columns.has_key?(options[:column]) == false
229 229
        @number_of_rows = 0
230 230
        begin
231
          ancestors = []
231 232
          Project.project_tree(projects) do |project, level|
233
            # Keep the first `level` ancestors to identify the displayed parent for collapse/expand.
234
            ancestors.slice!(level..)
232 235
            options[:indent] = indent + level * options[:indent_increment]
233 236
            parent_row_key =
234
              if level > 0 && project.parent
235
                gantt_project_row_key(project.parent)
237
              if ancestors.any?
238
                gantt_project_row_key(ancestors.last)
236 239
              end
237 240
            render_project(project, options, parent_row_key: parent_row_key)
241
            ancestors << project
238 242
          end
239 243
        rescue MaxLinesLimitReached
240 244
          @truncated = true
test/unit/lib/redmine/helpers/gantt_test.rb
158 158
    assert_select 'div.gantt-row[data-gantt-row-type=version][style*="--gantt-row-indent:24px"]'
159 159
  end
160 160

  
161
  test "project rows should reference their nearest displayed ancestor across every pane" do
162
    # Project hierarchy (all projects are public unless marked private):
163
    # root
164
    # |-- hidden (private)
165
    # |   `-- hidden_child (private)
166
    # |       `-- descendant
167
    # |           `-- child
168
    # `-- sibling
169
    # hidden_root (private)
170
    # `-- other_root
171
    #     `-- other_child
172
    root = Project.generate!
173
    hidden = Project.generate!(:parent_id => root.id, :is_public => false)
174
    hidden_child = Project.generate!(:parent_id => hidden.id, :is_public => false)
175
    descendant = Project.generate!(:parent_id => hidden_child.id)
176
    child = Project.generate!(:parent_id => descendant.id)
177
    sibling = Project.generate!(:parent_id => root.id)
178
    hidden_root = Project.generate!(:is_public => false)
179
    other_root = Project.generate!(:parent_id => hidden_root.id)
180
    other_child = Project.generate!(:parent_id => other_root.id)
181

  
182
    # Expected parents in the displayed tree; nil means a root row.
183
    expected_parents = {
184
      root => nil,
185
      descendant => root,
186
      child => descendant,
187
      sibling => root,
188
      other_root => nil,
189
      other_child => other_root
190
    }
191

  
192
    # Give each expected project an issue so it is included in the Gantt chart.
193
    expected_parents.each_key {|project| Issue.generate!(:project => project)}
194

  
195
    # Use a non-admin user with no membership in the private projects.
196
    # Render a cross-project Gantt chart with a status column.
197
    User.current = User.find(2)
198
    create_gantt(nil)
199
    @gantt.query.column_names = [:status]
200

  
201
    [
202
      @gantt.subjects,
203
      @gantt.lines,
204
      @gantt.selected_column_content(:column => @gantt.query.columns.last)
205
    ].each do |html|
206
      # Private projects must not have rows in any pane.
207
      [hidden, hidden_child, hidden_root].each do |project|
208
        assert_select_in html, "[data-gantt-row-key=project-#{project.id}]", 0
209
      end
210

  
211
      expected_parents.each do |project, expected_parent|
212
        assert_select_in html, "[data-gantt-row-key=project-#{project.id}]", 1 do |rows|
213
          if expected_parent
214
            assert_equal "project-#{expected_parent.id}", rows.first['data-gantt-parent-row-key']
215
          else
216
            assert_nil rows.first['data-gantt-parent-row-key']
217
          end
218
        end
219
      end
220
    end
221
  end
222

  
161 223
  test "#subjects version without assigned issues should not be rendered" do
162 224
    setup_subjects
163 225
    @version = Version.generate!(:effective_date => (today + 14),
(3-3/3)