debian-mirror-gitlab/app/presenters/project_presenter.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

514 lines
15 KiB
Ruby
Raw Normal View History

2018-11-18 11:00:15 +05:30
# frozen_string_literal: true
2018-03-27 19:54:05 +05:30
class ProjectPresenter < Gitlab::View::Presenter::Delegated
include ActionView::Helpers::NumberHelper
include GitlabRoutingHelper
include StorageHelper
include TreeHelper
2023-03-17 16:20:25 +05:30
include Ci::PipelineEditorHelper
2019-02-15 15:39:39 +05:30
include IconsHelper
2020-11-24 15:15:51 +05:30
include BlobHelper
2018-05-09 12:01:36 +05:30
include ChecksCollaboration
2018-03-27 19:54:05 +05:30
include Gitlab::Utils::StrongMemoize
2021-04-17 20:07:23 +05:30
include Gitlab::Experiment::Dsl
2018-03-27 19:54:05 +05:30
2021-11-18 22:05:49 +05:30
delegator_override_with GitlabRoutingHelper # TODO: Remove `GitlabRoutingHelper` inclusion as it's duplicate
2022-04-04 11:22:00 +05:30
delegator_override_with Gitlab::Utils::StrongMemoize # This module inclusion is expected. See https://gitlab.com/gitlab-org/gitlab/-/issues/352884.
2021-11-18 22:05:49 +05:30
presents ::Project, as: :project
2018-03-27 19:54:05 +05:30
2021-04-17 20:07:23 +05:30
AnchorData = Struct.new(:is_link, :label, :link, :class_modifier, :icon, :itemprop, :data)
2019-03-02 22:35:43 +05:30
MAX_TOPICS_TO_SHOW = 3
2018-11-20 20:47:30 +05:30
2019-02-15 15:39:39 +05:30
def statistic_icon(icon_name = 'plus-square-o')
2021-03-11 19:13:27 +05:30
sprite_icon(icon_name, css_class: 'icon gl-mr-2 gl-text-gray-500')
2019-02-15 15:39:39 +05:30
end
2018-03-27 19:54:05 +05:30
def statistics_anchors(show_auto_devops_callout:)
[
commits_anchor_data,
branches_anchor_data,
tags_anchor_data,
2020-04-22 19:07:51 +05:30
storage_anchor_data,
2023-04-23 21:23:45 +05:30
releases_anchor_data,
environments_anchor_data
2019-02-15 15:39:39 +05:30
].compact.select(&:is_link)
2018-03-27 19:54:05 +05:30
end
def statistics_buttons(show_auto_devops_callout:)
[
2018-11-08 19:23:39 +05:30
readme_anchor_data,
2019-12-26 22:10:19 +05:30
license_anchor_data,
2018-03-27 19:54:05 +05:30
changelog_anchor_data,
contribution_guide_anchor_data,
autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
kubernetes_cluster_anchor_data,
2021-04-17 20:07:23 +05:30
gitlab_ci_anchor_data,
2023-04-23 21:23:45 +05:30
wiki_anchor_data,
2021-04-17 20:07:23 +05:30
integrations_anchor_data
2019-07-31 22:56:46 +05:30
].compact.reject(&:is_link).sort_by.with_index { |item, idx| [item.class_modifier ? 0 : 1, idx] }
2018-03-27 19:54:05 +05:30
end
def empty_repo_statistics_anchors
2019-12-26 22:10:19 +05:30
[]
2018-03-27 19:54:05 +05:30
end
def empty_repo_statistics_buttons
[
2021-04-17 20:07:23 +05:30
upload_anchor_data,
2018-03-27 19:54:05 +05:30
new_file_anchor_data,
readme_anchor_data,
2019-12-26 22:10:19 +05:30
license_anchor_data,
2019-02-15 15:39:39 +05:30
changelog_anchor_data,
2019-12-21 20:55:43 +05:30
contribution_guide_anchor_data,
2021-04-17 20:07:23 +05:30
gitlab_ci_anchor_data,
2023-04-23 21:23:45 +05:30
wiki_anchor_data,
2021-04-17 20:07:23 +05:30
integrations_anchor_data
2019-02-15 15:39:39 +05:30
].compact.reject { |item| item.is_link }
2018-03-27 19:54:05 +05:30
end
def default_view
return anonymous_project_view unless current_user
user_view = current_user.project_view
2023-03-04 22:38:38 +05:30
if can?(current_user, :read_code, project)
2018-03-27 19:54:05 +05:30
user_view
2021-01-03 14:25:43 +05:30
elsif user_view == 'activity'
'activity'
elsif project.wiki_repository_exists? && can?(current_user, :read_wiki, project)
'wiki'
elsif can?(current_user, :read_issue, project)
'projects/issues/issues'
2018-03-27 19:54:05 +05:30
else
2021-01-03 14:25:43 +05:30
'activity'
2018-03-27 19:54:05 +05:30
end
end
def readme_path
2021-02-22 17:27:13 +05:30
filename_path(repository.readme_path)
2018-03-27 19:54:05 +05:30
end
def changelog_path
2021-02-22 17:27:13 +05:30
filename_path(repository.changelog&.name)
2018-03-27 19:54:05 +05:30
end
def license_path
2021-02-22 17:27:13 +05:30
filename_path(repository.license_blob&.name)
2018-03-27 19:54:05 +05:30
end
def contribution_guide_path
if project && contribution_guide = repository.contribution_guide
2023-05-27 22:25:52 +05:30
project_blob_path(project, tree_join(project.default_branch, contribution_guide.name))
2018-03-27 19:54:05 +05:30
end
end
def add_license_path
add_special_file_path(file_name: 'LICENSE')
end
2021-01-03 14:25:43 +05:30
def add_license_ide_path
2021-06-08 01:23:25 +05:30
ide_edit_path(project, default_branch_or_main, 'LICENSE')
2021-01-03 14:25:43 +05:30
end
2018-03-27 19:54:05 +05:30
def add_changelog_path
add_special_file_path(file_name: 'CHANGELOG')
end
2021-01-03 14:25:43 +05:30
def add_changelog_ide_path
2021-06-08 01:23:25 +05:30
ide_edit_path(project, default_branch_or_main, 'CHANGELOG')
2021-01-03 14:25:43 +05:30
end
2018-03-27 19:54:05 +05:30
def add_contribution_guide_path
2019-02-15 15:39:39 +05:30
add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add CONTRIBUTING')
2018-03-27 19:54:05 +05:30
end
2021-01-03 14:25:43 +05:30
def add_contribution_guide_ide_path
2021-06-08 01:23:25 +05:30
ide_edit_path(project, default_branch_or_main, 'CONTRIBUTING.md')
2020-11-24 15:15:51 +05:30
end
2018-03-27 19:54:05 +05:30
def add_readme_path
add_special_file_path(file_name: 'README.md')
end
2021-01-03 14:25:43 +05:30
def add_readme_ide_path
2021-06-08 01:23:25 +05:30
ide_edit_path(project, default_branch_or_main, 'README.md')
2021-01-03 14:25:43 +05:30
end
2018-03-27 19:54:05 +05:30
def license_short_name
license = repository.license
license&.nickname || license&.name || 'LICENSE'
end
def can_current_user_push_code?
strong_memoize(:can_current_user_push_code) do
if empty_repo?
can?(current_user, :push_code, project)
else
can_current_user_push_to_branch?(default_branch)
end
end
end
def can_current_user_push_to_branch?(branch)
2021-04-17 20:07:23 +05:30
return false unless current_user
2018-05-09 12:01:36 +05:30
user_access(project).can_push_to_branch?(branch)
end
2018-03-27 19:54:05 +05:30
2018-05-09 12:01:36 +05:30
def can_current_user_push_to_default_branch?
can_current_user_push_to_branch?(default_branch)
2018-03-27 19:54:05 +05:30
end
2020-04-22 19:07:51 +05:30
def storage_anchor_data
2022-07-23 23:45:48 +05:30
can_show_quota = can?(current_user, :admin_project, project) && !empty_repo?
2023-05-27 22:25:52 +05:30
AnchorData.new(
true,
statistic_icon('disk') +
_('%{strong_start}%{human_size}%{strong_end} Project Storage').html_safe % {
human_size: storage_counter(statistics.storage_size),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
can_show_quota ? project_usage_quotas_path(project) : nil
)
2020-04-22 19:07:51 +05:30
end
2020-03-13 15:44:24 +05:30
def releases_anchor_data
return unless can?(current_user, :read_release, project)
releases_count = project.releases.count
return if releases_count < 1
2023-05-27 22:25:52 +05:30
AnchorData.new(
true,
statistic_icon('deployments') +
n_('%{strong_start}%{release_count}%{strong_end} Release', '%{strong_start}%{release_count}%{strong_end} Releases', releases_count).html_safe % {
release_count: number_with_delimiter(releases_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
project_releases_path(project)
)
2020-03-13 15:44:24 +05:30
end
2023-04-23 21:23:45 +05:30
def environments_anchor_data
return unless can?(current_user, :read_environment, project)
environments_count = project.environments.available.count
return if environments_count == 0
2023-05-27 22:25:52 +05:30
AnchorData.new(
true,
statistic_icon('environment') +
n_('%{strong_start}%{count}%{strong_end} Environment', '%{strong_start}%{count}%{strong_end} Environments', environments_count).html_safe % {
count: number_with_delimiter(environments_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
project_environments_path(project)
)
2023-04-23 21:23:45 +05:30
end
2018-03-27 19:54:05 +05:30
def commits_anchor_data
2023-05-27 22:25:52 +05:30
AnchorData.new(
true,
statistic_icon('commit') +
n_('%{strong_start}%{commit_count}%{strong_end} Commit', '%{strong_start}%{commit_count}%{strong_end} Commits', statistics.commit_count).html_safe % {
commit_count: number_with_delimiter(statistics.commit_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
empty_repo? ? nil : project_commits_path(project, default_branch_or_main)
)
2018-03-27 19:54:05 +05:30
end
def branches_anchor_data
2023-05-27 22:25:52 +05:30
AnchorData.new(
true,
statistic_icon('branch') +
n_('%{strong_start}%{branch_count}%{strong_end} Branch', '%{strong_start}%{branch_count}%{strong_end} Branches', repository.branch_count).html_safe % {
branch_count: number_with_delimiter(repository.branch_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
empty_repo? ? nil : project_branches_path(project)
)
2018-03-27 19:54:05 +05:30
end
def tags_anchor_data
2023-05-27 22:25:52 +05:30
AnchorData.new(
true,
statistic_icon('label') +
n_('%{strong_start}%{tag_count}%{strong_end} Tag', '%{strong_start}%{tag_count}%{strong_end} Tags', repository.tag_count).html_safe % {
tag_count: number_with_delimiter(repository.tag_count),
strong_start: '<strong class="project-stat-value">'.html_safe,
strong_end: '</strong>'.html_safe
},
empty_repo? ? nil : project_tags_path(project)
)
2018-03-27 19:54:05 +05:30
end
2021-04-17 20:07:23 +05:30
def upload_anchor_data
strong_memoize(:upload_anchor_data) do
next unless can_current_user_push_to_default_branch?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon('upload') + _('Upload file'),
'#modal-upload-blob',
'js-upload-file-trigger',
nil,
nil,
{
'target_branch' => default_branch_or_main,
'original_branch' => default_branch_or_main,
'can_push_code' => 'true',
'path' => project_create_blob_path(project, default_branch_or_main),
'project_path' => project.full_path
}
)
2021-04-17 20:07:23 +05:30
end
end
2018-03-27 19:54:05 +05:30
def new_file_anchor_data
2021-04-17 20:07:23 +05:30
if can_current_user_push_to_default_branch?
2021-06-08 01:23:25 +05:30
new_file_path = empty_repo? ? ide_edit_path(project, default_branch_or_main) : project_new_blob_path(project, default_branch_or_main)
2021-01-03 14:25:43 +05:30
2023-05-27 22:25:52 +05:30
AnchorData.new(false, statistic_icon + _('New file'), new_file_path, 'btn-dashed')
2018-03-27 19:54:05 +05:30
end
end
def readme_anchor_data
2021-04-17 20:07:23 +05:30
if can_current_user_push_to_default_branch? && readme_path.nil?
2023-05-27 22:25:52 +05:30
AnchorData.new(false, statistic_icon + _('Add README'), empty_repo? ? add_readme_ide_path : add_readme_path)
2021-02-22 17:27:13 +05:30
elsif readme_path
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon('doc-text') + _('README'),
default_view != 'readme' ? readme_path : '#readme',
'btn-default',
'doc-text'
)
2018-03-27 19:54:05 +05:30
end
end
def changelog_anchor_data
2021-04-17 20:07:23 +05:30
if can_current_user_push_to_default_branch? && repository.changelog.blank?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon + _('Add CHANGELOG'),
empty_repo? ? add_changelog_ide_path : add_changelog_path
)
2018-03-27 19:54:05 +05:30
elsif repository.changelog.present?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon('doc-text') + _('CHANGELOG'),
changelog_path,
'btn-default'
)
2018-03-27 19:54:05 +05:30
end
end
def license_anchor_data
2019-02-15 15:39:39 +05:30
icon = statistic_icon('scale')
2018-11-20 20:47:30 +05:30
if repository.license_blob.present?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
icon + content_tag(:span, license_short_name, class: 'project-stat-value'),
license_path,
'btn-default',
nil,
'license'
)
2023-03-04 22:38:38 +05:30
elsif can_current_user_push_to_default_branch?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
content_tag(:span, statistic_icon + _('Add LICENSE'), class: 'add-license-link d-flex'),
empty_repo? ? add_license_ide_path : add_license_path
)
2018-03-27 19:54:05 +05:30
end
end
def contribution_guide_anchor_data
2021-04-17 20:07:23 +05:30
if can_current_user_push_to_default_branch? && repository.contribution_guide.blank?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon + _('Add CONTRIBUTING'),
empty_repo? ? add_contribution_guide_ide_path : add_contribution_guide_path
)
2018-03-27 19:54:05 +05:30
elsif repository.contribution_guide.present?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon('doc-text') + _('CONTRIBUTING'),
contribution_guide_path,
'btn-default'
)
2018-03-27 19:54:05 +05:30
end
end
def autodevops_anchor_data(show_auto_devops_callout: false)
2022-10-11 01:57:18 +05:30
return unless project.feature_available?(:builds, current_user)
2018-03-27 19:54:05 +05:30
if current_user && can?(current_user, :admin_pipeline, project) && repository.gitlab_ci_yml.blank? && !show_auto_devops_callout
2019-02-15 15:39:39 +05:30
if auto_devops_enabled?
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon('settings') + _('Auto DevOps enabled'),
project_settings_ci_cd_path(project, anchor: 'autodevops-settings'),
'btn-default'
)
2019-02-15 15:39:39 +05:30
else
2023-05-27 22:25:52 +05:30
AnchorData.new(
false,
statistic_icon + _('Enable Auto DevOps'),
project_settings_ci_cd_path(project, anchor: 'autodevops-settings')
)
2019-02-15 15:39:39 +05:30
end
2018-03-27 19:54:05 +05:30
elsif auto_devops_enabled?
2023-05-27 22:25:52 +05:30
AnchorData.new(false, _('Auto DevOps enabled'), nil)
2018-03-27 19:54:05 +05:30
end
end
def kubernetes_cluster_anchor_data
2020-03-13 15:44:24 +05:30
if can_instantiate_cluster?
2018-03-27 19:54:05 +05:30
if clusters.empty?
2023-05-27 22:25:52 +05:30
AnchorData.new(false, statistic_icon + _('Add Kubernetes cluster'), project_clusters_path(project))
2019-02-15 15:39:39 +05:30
else
cluster_link = clusters.count == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)
2019-01-03 12:48:30 +05:30
2023-05-27 22:25:52 +05:30
AnchorData.new(false, _('Kubernetes'), cluster_link, 'btn-default')
2019-02-15 15:39:39 +05:30
end
2018-03-27 19:54:05 +05:30
end
end
def gitlab_ci_anchor_data
2023-03-17 16:20:25 +05:30
return unless can_view_pipeline_editor?(project)
2020-03-13 15:44:24 +05:30
if cicd_missing?
2023-05-27 22:25:52 +05:30
AnchorData.new(false, statistic_icon + _('Set up CI/CD'), project_ci_pipeline_editor_path(project))
2018-03-27 19:54:05 +05:30
elsif repository.gitlab_ci_yml.present?
2023-05-27 22:25:52 +05:30
AnchorData.new(false, statistic_icon('doc-text') + _('CI/CD configuration'), project_ci_pipeline_editor_path(project), 'btn-default')
2018-03-27 19:54:05 +05:30
end
end
2023-04-23 21:23:45 +05:30
def wiki_anchor_data
return unless project.wiki_enabled? && can_read_wiki?
if project.wiki.has_home_page?
AnchorData.new(false, statistic_icon('book') + _('Wiki'), project_wiki_path, 'btn-default', nil, nil)
elsif can_create_wiki?
AnchorData.new(false, statistic_icon + _('Add Wiki'), project_create_wiki_path, nil, nil, nil)
end
end
2019-03-02 22:35:43 +05:30
def topics_to_show
2021-10-27 15:23:28 +05:30
project_topic_list.take(MAX_TOPICS_TO_SHOW) # rubocop: disable CodeReuse/ActiveRecord
2018-11-20 20:47:30 +05:30
end
2019-07-07 11:18:12 +05:30
def topics_not_shown
2021-10-27 15:23:28 +05:30
project_topic_list - topics_to_show
2019-07-07 11:18:12 +05:30
end
2019-03-02 22:35:43 +05:30
def count_of_extra_topics_not_shown
2021-10-27 15:23:28 +05:30
if project_topic_list.count > MAX_TOPICS_TO_SHOW
project_topic_list.count - MAX_TOPICS_TO_SHOW
2018-11-20 20:47:30 +05:30
else
0
end
end
2019-03-02 22:35:43 +05:30
def has_extra_topics?
count_of_extra_topics_not_shown > 0
2018-11-20 20:47:30 +05:30
end
2020-03-13 15:44:24 +05:30
def can_setup_review_app?
strong_memoize(:can_setup_review_app) do
(can_instantiate_cluster? && all_clusters_empty?) || cicd_missing?
end
end
def all_clusters_empty?
strong_memoize(:all_clusters_empty) do
project.all_clusters.empty?
end
end
2018-03-27 19:54:05 +05:30
private
2021-04-17 20:07:23 +05:30
def integrations_anchor_data
2021-11-11 11:23:49 +05:30
return unless can?(current_user, :admin_project, project)
2021-04-17 20:07:23 +05:30
2021-11-11 11:23:49 +05:30
label = statistic_icon('settings') + _('Configure Integrations')
AnchorData.new(false, label, project_settings_integrations_path(project), nil, nil, nil)
2021-04-17 20:07:23 +05:30
end
2020-03-13 15:44:24 +05:30
def cicd_missing?
current_user && can_current_user_push_code? && repository.gitlab_ci_yml.blank? && !auto_devops_enabled?
end
def can_instantiate_cluster?
current_user && can?(current_user, :create_cluster, project)
end
2021-02-22 17:27:13 +05:30
def filename_path(filepath)
return if filepath.blank?
project_blob_path(project, tree_join(default_branch, filepath))
2018-03-27 19:54:05 +05:30
end
def anonymous_project_view
2023-03-04 22:38:38 +05:30
if !project.empty_repo? && can?(current_user, :read_code, project)
2018-03-27 19:54:05 +05:30
'files'
2021-01-03 14:25:43 +05:30
elsif project.wiki_repository_exists? && can?(current_user, :read_wiki, project)
'wiki'
elsif can?(current_user, :read_issue, project)
'projects/issues/issues'
2018-03-27 19:54:05 +05:30
else
'activity'
end
end
2021-06-08 01:23:25 +05:30
def add_special_file_path(file_name:, commit_message: nil, branch_name: nil, additional_params: {})
2018-03-27 19:54:05 +05:30
commit_message ||= s_("CommitMessage|Add %{file_name}") % { file_name: file_name }
project_new_blob_path(
project,
2021-06-08 01:23:25 +05:30
default_branch_or_main,
2022-08-27 11:52:29 +05:30
file_name: file_name,
2018-03-27 19:54:05 +05:30
commit_message: commit_message,
2022-08-27 11:52:29 +05:30
branch_name: branch_name,
2021-06-08 01:23:25 +05:30
**additional_params
2018-03-27 19:54:05 +05:30
)
end
2021-10-27 15:23:28 +05:30
def project_topic_list
strong_memoize(:project_topic_list) do
2022-07-16 23:28:13 +05:30
project.topics.map { |topic| { name: topic.name, title: topic.title_or_name } }
2021-10-27 15:23:28 +05:30
end
end
2022-05-07 20:08:51 +05:30
# Avoid including ActionView::Helpers::UrlHelper
2023-04-23 21:23:45 +05:30
def content_tag(...)
ActionController::Base.helpers.content_tag(...)
end
def can_create_wiki?
current_user && can?(current_user, :create_wiki, project)
end
def can_read_wiki?
current_user && can?(current_user, :read_wiki, project)
end
def project_wiki_path
wiki_path(project.wiki)
end
def project_create_wiki_path
"#{wiki_path(project.wiki)}?view=create"
2022-05-07 20:08:51 +05:30
end
2018-03-27 19:54:05 +05:30
end
2019-12-04 20:38:33 +05:30
2021-06-08 01:23:25 +05:30
ProjectPresenter.prepend_mod_with('ProjectPresenter')