tree_helper.rb 6.23 KB
Newer Older
1
module TreeHelper
2 3 4 5
  # 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
6
  def render_tree(tree)
7
    # Render Folders before Files/Submodules
8
    folders, files, submodules = tree.trees, tree.blobs, tree.submodules
9 10 11 12

    tree = ""

    # Render folders if we have any
13 14
    tree << render(partial: 'projects/tree/tree_item', collection: folders,
                   locals: { type: 'folder' }) if folders.present?
15

16
    # Render files if we have any
17 18
    tree << render(partial: 'projects/tree/blob_item', collection: files,
                   locals: { type: 'file' }) if files.present?
19 20

    # Render submodules if we have any
21 22
    tree << render(partial: 'projects/tree/submodule_item',
                   collection: submodules) if submodules.present?
23 24

    tree.html_safe
25 26
  end

27
  def render_readme(readme)
28
    render_markup(readme.name, readme.data)
29 30
  end

31
  # Return an image icon depending on the file type and mode
32 33
  #
  # type - String type of the tree item; either 'folder' or 'file'
34 35 36 37
  # mode - File unix mode
  # name - File name
  def tree_icon(type, mode, name)
    icon("#{file_type_icon_class(type, mode, name)} fw")
38 39
  end

40 41
  def tree_hex_class(content)
    "file_#{hexdigest(content.name)}"
42
  end
43

44 45 46 47
  # Simple shortcut to File.join
  def tree_join(*args)
    File.join(*args)
  end
48

49 50 51 52
  def on_top_of_branch?(project = @project, ref = @ref)
    project.repository.branch_names.include?(ref)
  end

53
  def can_edit_tree?(project = nil, ref = nil)
54
    project ||= @project
55
    ref ||= @ref
56

57 58
    return false unless on_top_of_branch?(project, ref)

59
    can_collaborate_with_project?(project)
60
  end
61

62
  def tree_edit_branch(project = @project, ref = @ref)
63 64 65 66 67 68
    return unless can_edit_tree?(project, ref)

    if can_push_branch?(project, ref)
      ref
    else
      project = tree_edit_project(project)
69
      project.repository.next_branch('patch')
70 71 72 73 74 75 76 77
    end
  end

  def tree_edit_project(project = @project)
    if can?(current_user, :push_code, project)
      project
    elsif current_user && current_user.already_forked?(project)
      current_user.fork_of(project)
78
    end
79 80
  end

81 82 83 84 85 86 87 88 89 90 91 92 93 94
  def edit_in_new_fork_notice_now
    "You're not allowed to make changes to this project directly." +
      " A fork of this project is being created that you can make changes in, so you can submit a merge request."
  end

  def edit_in_new_fork_notice
    "You're not allowed to make changes to this project directly." +
      " A fork of this project has been created that you can make changes in, so you can submit a merge request."
  end

  def commit_in_fork_help
    "A new branch will be created in your fork and a new merge request will be started."
  end

95
  def tree_breadcrumbs(tree, max_links = 2)
96
    if @path.present?
97
      part_path = ""
98
      parts = @path.split('/')
99 100

      yield('..', nil) if parts.count > max_links
101

102 103 104
      parts.each do |part|
        part_path = File.join(part_path, part) unless part_path.empty?
        part_path = part if part_path.empty?
105

Gabriel Mazetto's avatar
Gabriel Mazetto committed
106
        next if parts.count > max_links && !parts.last(2).include?(part)
107
        yield(part, tree_join(@ref, part_path), part_path)
108 109
      end
    end
110
  end
111

112
  def up_dir_path
113 114
    file = File.join(@path, "..")
    tree_join(@ref, file)
115
  end
116

Steven Burgart's avatar
Steven Burgart committed
117
  # returns the relative path of the first subdir that doesn't have only one directory descendant
118 119 120 121 122 123 124 125
  def flatten_tree(tree)
    subtree = Gitlab::Git::Tree.where(@repository, @commit.id, tree.path)
    if subtree.count == 1 && subtree.first.dir?
      return tree_join(tree.name, flatten_tree(subtree.first))
    else
      return tree.name
    end
  end
Valery Sizov's avatar
Valery Sizov committed
126 127 128 129 130

  def lock_file_link(project = @project, path = @path, html_options: {})
    return unless license_allows_file_locks?
    return if path.blank?

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
    path_lock = project.find_path_lock(path, downstream: true)

    if path_lock
      locker = path_lock.user.name

      if path_lock.exact?(path)
        if can_unlock?(path_lock)
          html_options[:data] = { state: :unlock }
          tooltip = path_lock.user == current_user ? '' : "Locked by #{locker}"
          enabled_lock_link("Unlock", tooltip, html_options)
        else
          disabled_lock_link("Unlock", "Locked by #{locker}. You do not have permission to unlock this", html_options)
        end
      elsif path_lock.upstream?(path)
        if can_unlock?(path_lock)
          disabled_lock_link("Unlock", "#{locker} has a lock on \"#{path_lock.path}\". Unlock that directory in order to unlock this", html_options)
        else
          disabled_lock_link("Unlock", "#{locker} has a lock on \"#{path_lock.path}\". You do not have permission to unlock it", html_options)
        end
      elsif path_lock.downstream?(path)
        if can_unlock?(path_lock)
          disabled_lock_link("Lock", "This directory cannot be locked while #{locker} has a lock on \"#{path_lock.path}\". Unlock this in order to proceed", html_options)
        else
          disabled_lock_link("Lock", "This directory cannot be locked while #{locker} has a lock on \"#{path_lock.path}\". You do not have permission to unlock it", html_options)
        end
      end
    else
      if can?(current_user, :push_code, project)
        html_options[:data] = { state: :lock }
        enabled_lock_link("Lock", '', html_options)
      else
        disabled_lock_link("Lock", "You do not have permission to lock this", html_options)
      end
    end
  end

  def disabled_lock_link(label, title, html_options)
    html_options['data-toggle'] = 'tooltip'
    html_options[:title] = title
    html_options[:class] = "#{html_options[:class].to_s} disabled has-tooltip"
Valery Sizov's avatar
Valery Sizov committed
171

172 173 174 175 176 177 178
    content_tag :span, label, html_options
  end

  def enabled_lock_link(label, title, html_options)
    html_options['data-toggle'] = 'tooltip'
    html_options[:title] = title
    html_options[:class] = "#{html_options[:class].to_s} has-tooltip"
Valery Sizov's avatar
Valery Sizov committed
179 180 181

    link_to label, '#', html_options
  end
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

  def render_lock_icon(path)
    return unless license_allows_file_locks?
    return unless @project.root_ref?(@ref)

    if file_lock = @project.find_path_lock(path, exact_match: true)
      content_tag(
        :i,
        nil,
        class: "fa fa-lock prepend-left-5 append-right-5",
        title: text_label_for_lock(file_lock, path),
        'data-toggle' => 'tooltip'
      )
    end
  end
197
end