Commit 03b1bcbb authored by Drew Blessing's avatar Drew Blessing

Truncate tree to max 1,000 items and display notice to users

Rendering ten thousands of tree items consumes a lot of server
time and can cause timeouts in extreme cases. Realistically,
displaying more than 1,000 files is probably not useful so
truncate and show the user a notice instead. 'Find files' can be
used to locate specific files beyond the 1,000 limit.
parent a4072db0
......@@ -125,7 +125,7 @@
color: $white-normal;
}
&:hover {
&:hover:not(.tree-truncated-warning) {
td {
background-color: $row-hover;
border-top: 1px solid $row-hover-border;
......@@ -198,6 +198,11 @@
}
}
.tree-truncated-warning {
color: $orange-600;
background-color: $orange-100;
}
.tree-time-ago {
min-width: 135px;
color: $gl-text-color-secondary;
......
module TreeHelper
FILE_LIMIT = 1_000
# Sorts a repository's tree so that folders are before files and renders
# their corresponding partials
#
# contents - A Grit::Tree object for the current tree
# tree - A `Tree` object for the current tree
def render_tree(tree)
# Sort submodules and folders together by name ahead of files
folders, files, submodules = tree.trees, tree.blobs, tree.submodules
tree = ""
tree = ''
items = (folders + submodules).sort_by(&:name) + files
tree << render(partial: "projects/tree/tree_row", collection: items) if items.present?
if items.size > FILE_LIMIT
tree << render(partial: 'projects/tree/truncated_notice_tree_row',
locals: { limit: FILE_LIMIT, total: items.size })
items = items.take(FILE_LIMIT)
end
tree << render(partial: 'projects/tree/tree_row', collection: items) if items.present?
tree.html_safe
end
......
%tr.tree-truncated-warning
%td{ colspan: '3' }
= icon('exclamation-triangle fw')
%span
Too many items to show. To preserve performance only
%strong #{number_with_delimiter(limit)} of #{number_with_delimiter(total)}
items are displayed.
---
title: Truncate tree to max 1,000 items and display notice to users
merge_request:
author:
type: performance
require 'spec_helper'
describe TreeHelper do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:sha) { 'ce369011c189f62c815f5971d096b26759bab0d1' }
describe '.render_tree' do
before do
@id = sha
@project = project
end
it 'displays all entries without a warning' do
tree = repository.tree(sha, 'files')
html = render_tree(tree)
expect(html).not_to have_selector('.tree-truncated-warning')
end
it 'truncates entries and adds a warning' do
stub_const('TreeHelper::FILE_LIMIT', 1)
tree = repository.tree(sha, 'files')
html = render_tree(tree)
expect(html).to have_selector('.tree-truncated-warning', count: 1)
expect(html).to have_selector('.tree-item-file-name', count: 1)
end
end
describe 'flatten_tree' do
let(:project) { create(:project, :repository) }
let(:repository) { project.repository }
let(:sha) { 'ce369011c189f62c815f5971d096b26759bab0d1' }
let(:tree) { repository.tree(sha, 'files') }
let(:root_path) { 'files' }
let(:tree_item) { tree.entries.find { |entry| entry.path == path } }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment