gitlab-org--gitlab-foss/app/helpers/projects_helper.rb

739 lines
25 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
2012-09-07 12:57:13 -04:00
module ProjectsHelper
def project_incident_management_setting
@project_incident_management_setting ||= @project.incident_management_setting ||
@project.build_incident_management_setting
end
def link_to_project(project)
link_to namespace_project_path(namespace_id: project.namespace, id: project), title: h(project.name), class: 'gl-link' do
2014-04-11 18:00:58 -04:00
title = content_tag(:span, project.name, class: 'project-name')
2012-12-09 03:56:15 -05:00
if project.namespace
2013-10-10 03:53:49 -04:00
namespace = content_tag(:span, "#{project.namespace.human_name} / ", class: 'namespace-name')
2012-12-09 03:56:15 -05:00
title = namespace + title
end
title
end
end
2012-10-29 17:45:11 -04:00
2016-01-28 20:36:48 -05:00
def link_to_member_avatar(author, opts = {})
default_opts = { size: 16 }
2016-01-28 20:36:48 -05:00
opts = default_opts.merge(opts)
classes = %W[avatar avatar-inline s#{opts[:size]}]
2017-09-05 16:17:53 -04:00
classes << opts[:avatar_class] if opts[:avatar_class]
avatar = avatar_icon_for_user(author, opts[:size])
image_tag(avatar, width: opts[:size], class: classes, alt: '')
2016-01-28 20:36:48 -05:00
end
def author_content_tag(author, opts = {})
default_opts = { author_class: 'author', tooltip: false, by_username: false }
opts = default_opts.merge(opts)
has_tooltip = !opts[:by_username] && opts[:tooltip]
username = opts[:by_username] ? author.to_reference : author.name
name_tag_options = { class: [opts[:author_class]] }
if has_tooltip
name_tag_options[:title] = author.to_reference
name_tag_options[:data] = { placement: 'top' }
name_tag_options[:class] << 'has-tooltip'
end
# NOTE: ActionView::Helpers::TagHelper#content_tag HTML escapes username
content_tag(:span, username, name_tag_options)
end
def link_to_member(project, author, opts = {}, &block)
default_opts = { avatar: true, name: true, title: ":name" }
opts = default_opts.merge(opts)
return "(deleted)" unless author
data_attrs = {
user_id: author.id,
username: author.username,
name: author.name
}
inject_classes = ["author-link", opts[:extra_class]]
if opts[:name]
inject_classes.concat(["js-user-link", opts[:mobile_classes]])
else
inject_classes.append( "has-tooltip" )
end
inject_classes = inject_classes.compact.join(" ")
author_html = []
# Build avatar image tag
author_html << link_to_member_avatar(author, opts) if opts[:avatar]
# Build name span tag
author_html << author_content_tag(author, opts) if opts[:name]
author_html << capture(&block) if block
author_html = author_html.join.html_safe
if opts[:name]
link_to(author_html, user_path(author), class: inject_classes, data: data_attrs).html_safe
else
title = opts[:title].sub(":name", sanitize(author.name))
link_to(author_html, user_path(author), class: inject_classes, title: title, data: { container: 'body', qa_selector: 'assignee_link' }).html_safe
end
2012-10-29 17:45:11 -04:00
end
2012-12-12 05:02:29 -05:00
def project_title(project)
namespace_link = build_namespace_breadcrumb_link(project)
project_link = build_project_breadcrumb_link(project)
2017-09-06 07:19:03 -04:00
namespace_link = breadcrumb_list_item(namespace_link) unless project.group
project_link = breadcrumb_list_item project_link
2017-09-06 07:19:03 -04:00
"#{namespace_link} #{project_link}".html_safe
2012-12-12 05:02:29 -05:00
end
2013-05-20 07:22:18 -04:00
def remove_project_message(project)
_("You are going to delete %{project_full_name}. Deleted projects CANNOT be restored! Are you ABSOLUTELY sure?") %
{ project_full_name: project.full_name }
2013-05-20 07:22:18 -04:00
end
2013-06-13 15:58:27 -04:00
def transfer_project_message(project)
_("You are going to transfer %{project_full_name} to another namespace. Are you ABSOLUTELY sure?") %
{ project_full_name: project.full_name }
end
def remove_fork_project_description_message(project)
source = visible_fork_source(project)
if source
msg = _('This will remove the fork relationship between this project and %{fork_source}.') %
{ fork_source: link_to(source.full_name, project_path(source)) }
msg.html_safe
else
_('This will remove the fork relationship between this project and other projects in the fork network.')
end
end
def remove_fork_project_warning_message(project)
_("You are going to remove the fork relationship from %{project_full_name}. Are you ABSOLUTELY sure?") %
{ project_full_name: project.full_name }
end
def remove_fork_project_confirm_json(project, remove_form_id)
{
remove_form_id: remove_form_id,
button_text: _('Remove fork relationship'),
confirm_danger_message: remove_fork_project_warning_message(project),
phrase: @project.path
}
end
def visible_fork_source(project)
project.fork_source if project.fork_source && can?(current_user, :read_project, project.fork_source)
end
def project_search_tabs?(tab)
abilities = Array(search_tab_ability_map[tab])
abilities.any? { |ability| can?(current_user, ability, @project) }
end
2015-07-06 08:38:43 -04:00
def can_change_visibility_level?(project, current_user)
can?(current_user, :change_visibility_level, project)
2015-07-06 08:38:43 -04:00
end
def can_disable_emails?(project, current_user)
return false if project.group&.emails_disabled?
can?(current_user, :set_emails_disabled, project)
end
def last_push_event
Rework how recent push events are retrieved Whenever you push to a branch GitLab will show a button to create a merge request (should one not exist already). The underlying code to display this data was quite inefficient. For example, it involved multiple slow queries just to figure out what the most recent push event was. This commit changes the way this data is retrieved so it's much faster. This is achieved by caching the ID of the last push event on every push, which is then retrieved when loading certain pages. Database queries are only executed if necessary and the cached data is removed automatically once a merge request has been created, or 2 hours after being stored. A trade-off of this approach is that we _only_ track the last event. Previously if you were to push to branch A and B then create a merge request for branch B we'd still show the widget for branch A. As of this commit this is no longer the case, instead we will only show the widget for the branch you pushed to most recently. Once a merge request exists the widget is no longer displayed. Alternative solutions are either too complex and/or too slow, hence the decision was made to settle for this trade-off. Performance Impact ------------------ In the best case scenario (= a user didn't push anything for more than 2 hours) we perform a single Redis GET per page. Should there be cached data we will run a single (and lightweight) SQL query to get the event data from the database. If a merge request already exists we will run an additional DEL to remove the cache key. The difference in response timings can vary a bit per project. On GitLab.com the 99th percentile of time spent in User#recent_push hovers between 100 milliseconds and 1 second, while the mean hovers around 50 milliseconds. With the changes in this MR the expected time spent in User#recent_push is expected to be reduced down to just a few milliseconds. Fixes https://gitlab.com/gitlab-org/gitlab-ce/issues/35990
2017-09-01 06:50:14 -04:00
current_user&.recent_push(@project)
end
def link_to_autodeploy_doc
link_to _('About auto deploy'), help_page_path('topics/autodevops/stages.md', anchor: 'auto-deploy'), target: '_blank', rel: 'noopener'
end
2017-02-07 10:59:38 -05:00
def autodeploy_flash_notice(branch_name)
html_escape(_("Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}")) %
{ branch_name: tag.strong(truncate(sanitize(branch_name))), link_to_autodeploy_doc: link_to_autodeploy_doc }
2017-02-07 10:59:38 -05:00
end
def project_list_cache_key(project, pipeline_status: true)
key = [
project.route.cache_key,
project.cache_key,
project.last_activity_date,
controller.controller_name,
controller.action_name,
Gitlab::CurrentSettings.cache_key,
"cross-project:#{can?(current_user, :read_cross_project)}",
max_project_member_access_cache_key(project),
pipeline_status,
Gitlab::I18n.locale,
'v2.6'
]
key << pipeline_status_cache_key(project.pipeline_status) if pipeline_status && project.pipeline_status.has_status?
2017-03-16 05:53:48 -04:00
key
end
def load_pipeline_status(projects)
2017-06-21 09:48:12 -04:00
Gitlab::Cache::Ci::ProjectPipelineStatus
.load_in_batch_for_projects(projects)
end
def show_no_ssh_key_message?
Gitlab::CurrentSettings.user_show_add_ssh_key_message? &&
cookies[:hide_no_ssh_message].blank? &&
!current_user.hide_no_ssh_key &&
current_user.require_ssh_key?
end
def show_no_password_message?
cookies[:hide_no_password_message].blank? && !current_user.hide_no_password &&
current_user.require_extra_setup_for_git_auth?
end
def show_auto_devops_implicitly_enabled_banner?(project, user)
return false unless user_can_see_auto_devops_implicitly_enabled_banner?(project, user)
cookies["hide_auto_devops_implicitly_enabled_banner_#{project.id}".to_sym].blank?
end
def no_password_message
push_pull_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('gitlab-basics/start-using-git', anchor: 'pull-and-push') }
clone_with_https_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_page_path('gitlab-basics/start-using-git', anchor: 'clone-with-https') }
set_password_link_start = '<a href="%{url}">'.html_safe % { url: edit_profile_password_path }
set_up_pat_link_start = '<a href="%{url}">'.html_safe % { url: profile_personal_access_tokens_path }
message = if current_user.require_password_creation_for_git?
_('Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_password_link_start}set a password%{link_end} or %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}.')
else
_('Your account is authenticated with SSO or SAML. To %{push_pull_link_start}push and pull%{link_end} over %{protocol} with Git using this account, you must %{set_up_pat_link_start}set up a Personal Access Token%{link_end} to use instead of a password. For more information, see %{clone_with_https_link_start}Clone with HTTPS%{link_end}.')
end
html_escape(message) % {
push_pull_link_start: push_pull_link_start,
protocol: gitlab_config.protocol.upcase,
clone_with_https_link_start: clone_with_https_link_start,
set_password_link_start: set_password_link_start,
set_up_pat_link_start: set_up_pat_link_start,
link_end: '</a>'.html_safe
}
end
# Returns true if any projects are present.
#
# If the relation has a LIMIT applied we'll cast the relation to an Array
# since repeated any? checks would otherwise result in multiple COUNT queries
# being executed.
#
# If no limit is applied we'll just issue a COUNT since the result set could
# be too large to load into memory.
def any_projects?(projects)
return projects.any? if projects.is_a?(Array)
if projects.limit_value
projects.to_a.any?
else
projects.except(:offset).any?
end
end
# TODO: Remove this method when removing the feature flag
# https://gitlab.com/gitlab-org/gitlab/merge_requests/11209#note_162234863
# make sure to remove from the EE specific controller as well: ee/app/controllers/ee/dashboard/projects_controller.rb
def show_projects?(projects, params)
Feature.enabled?(:project_list_filter_bar) || !!(params[:personal] || params[:name] || any_projects?(projects))
end
def push_to_create_project_command(user = current_user)
repository_url =
if Gitlab::CurrentSettings.current_application_settings.enabled_git_access_protocol == 'http'
user_url(user)
else
Gitlab.config.gitlab_shell.ssh_path_prefix + user.username
end
"git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)"
end
2018-06-05 06:10:34 -04:00
def show_xcode_link?(project = @project)
browser.platform.mac? && project.repository.xcode_project?
end
def xcode_uri_to_repo(project = @project)
"xcode://clone?repo=#{CGI.escape(default_url_to_repo(project))}"
end
def explore_projects_tab?
current_page?(explore_projects_path) ||
current_page?(trending_explore_projects_path) ||
current_page?(starred_explore_projects_path)
end
def show_merge_request_count?(disabled: false, compact_mode: false)
!disabled && !compact_mode
end
def show_issue_count?(disabled: false, compact_mode: false)
!disabled && !compact_mode
end
def error_tracking_setting_project_json
setting = @project.error_tracking_setting
return if setting.blank? || setting.project_slug.blank? ||
setting.organization_slug.blank?
{
name: setting.project_name,
organization_name: setting.organization_name,
organization_slug: setting.organization_slug,
slug: setting.project_slug
}.to_json
end
def directory?
@path.present?
end
def external_classification_label_help_message
default_label = ::Gitlab::CurrentSettings.current_application_settings
.external_authorization_service_default_label
s_(
"ExternalAuthorizationService|When no classification label is set the "\
"default label `%{default_label}` will be used."
) % { default_label: default_label }
end
def can_admin_project_member?(project)
Ability.allowed?(current_user, :admin_project_member, project) && !membership_locked?
end
def project_can_be_shared?
!membership_locked? || @project.allowed_to_share_with_group?
end
def membership_locked?
false
end
def share_project_description(project)
share_with_group = project.allowed_to_share_with_group?
share_with_members = !membership_locked?
description =
if share_with_group && share_with_members
_("You can invite a new member to %{project_name} or invite another group.")
elsif share_with_group
_("You can invite another group to %{project_name}.")
elsif share_with_members
_("You can invite a new member to %{project_name}.")
end
html_escape(description) % { project_name: tag.strong(project.name) }
end
def metrics_external_dashboard_url
@project.metrics_setting_external_dashboard_url
end
def metrics_dashboard_timezone
@project.metrics_setting_dashboard_timezone
end
def grafana_integration_url
@project.grafana_integration&.grafana_url
end
def grafana_integration_masked_token
@project.grafana_integration&.masked_token
end
def grafana_integration_enabled?
@project.grafana_integration&.enabled?
end
def project_license_name(project)
key = "project:#{project.id}:license_name"
Gitlab::SafeRequestStore.fetch(key) { project.repository.license&.name }
rescue GRPC::Unavailable, GRPC::DeadlineExceeded, Gitlab::Git::CommandError => e
Gitlab::ErrorTracking.track_exception(e)
Gitlab::SafeRequestStore[key] = nil
nil
end
def show_terraform_banner?(project)
Feature.enabled?(:show_terraform_banner, type: :ops, default_enabled: true) && project.repository_languages.with_programming_language('HCL').exists? && project.terraform_states.empty?
end
def project_permissions_panel_data(project)
{
packagesAvailable: ::Gitlab.config.packages.enabled,
packagesHelpPath: help_page_path('user/packages/index'),
currentSettings: project_permissions_settings(project),
canDisableEmails: can_disable_emails?(project, current_user),
canChangeVisibilityLevel: can_change_visibility_level?(project, current_user),
allowedVisibilityOptions: project_allowed_visibility_levels(project),
visibilityHelpPath: help_page_path('public_access/public_access'),
registryAvailable: Gitlab.config.registry.enabled,
registryHelpPath: help_page_path('user/packages/container_registry/index'),
lfsAvailable: Gitlab.config.lfs.enabled,
lfsHelpPath: help_page_path('topics/git/lfs/index'),
lfsObjectsExist: project.lfs_objects.exists?,
lfsObjectsRemovalHelpPath: help_page_path('topics/git/lfs/index', anchor: 'removing-objects-from-lfs'),
pagesAvailable: Gitlab.config.pages.enabled,
pagesAccessControlEnabled: Gitlab.config.pages.access_control,
pagesAccessControlForced: ::Gitlab::Pages.access_control_is_forced?,
pagesHelpPath: help_page_path('user/project/pages/introduction', anchor: 'gitlab-pages-access-control'),
issuesHelpPath: help_page_path('user/project/issues/index')
}
end
def project_classes(project)
return "project-highlight-puc" if project.warn_about_potentially_unwanted_characters?
""
end
# Returns the confirm phrase the user needs to type in order to delete the project
#
# Thus the phrase should include the namespace to make it very clear to the
# user which project is subject to deletion.
# Relevant issue: https://gitlab.com/gitlab-org/gitlab/-/issues/343591
def delete_confirm_phrase(project)
project.path_with_namespace
end
def fork_button_disabled_tooltip(project)
return unless current_user
if !current_user.can?(:fork_project, project)
s_("ProjectOverview|You don't have permission to fork this project")
elsif !current_user.can?(:create_fork)
s_('ProjectOverview|You have reached your project limit')
end
end
def import_from_bitbucket_message
configure_oauth_import_message('Bitbucket', help_page_path("integration/bitbucket"))
end
def import_from_gitlab_message
configure_oauth_import_message('GitLab.com', help_page_path("integration/gitlab"))
end
private
def configure_oauth_import_message(provider, help_url)
str = if current_user.admin?
'ImportProjects|To enable importing projects from %{provider}, as administrator you need to configure %{link_start}OAuth integration%{link_end}'
else
'ImportProjects|To enable importing projects from %{provider}, ask your GitLab administrator to configure %{link_start}OAuth integration%{link_end}'
end
link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: help_url }
s_(str).html_safe % { provider: provider, link_start: link_start, link_end: '</a>'.html_safe }
end
def tab_ability_map
{
cycle_analytics: :read_cycle_analytics,
environments: :read_environment,
metrics_dashboards: :metrics_dashboard,
milestones: :read_milestone,
snippets: :read_snippet,
settings: :admin_project,
builds: :read_build,
clusters: :read_cluster,
serverless: :read_cluster,
terraform: :read_terraform_state,
error_tracking: :read_sentry_issue,
alert_management: :read_alert_management_alert,
incidents: :read_issue,
labels: :read_label,
issues: :read_issue,
project_members: :read_project_member,
wiki: :read_wiki,
feature_flags: :read_feature_flag,
analytics: :read_analytics
}
end
def search_tab_ability_map
@search_tab_ability_map ||= tab_ability_map.merge(
blobs: :download_code,
commits: :download_code,
merge_requests: :read_merge_request,
notes: [:read_merge_request, :download_code, :read_issue, :read_snippet],
members: :read_project_member
)
2013-06-13 15:58:27 -04:00
end
def project_lfs_status(project)
if project.lfs_enabled?
content_tag(:span, class: 'lfs-enabled') do
2017-06-07 16:13:44 -04:00
s_('LFSStatus|Enabled')
end
else
content_tag(:span, class: 'lfs-disabled') do
2017-06-07 16:13:44 -04:00
s_('LFSStatus|Disabled')
end
end
end
def git_user_name
if current_user
2017-09-13 08:39:50 -04:00
current_user.name.gsub('"', '\"')
else
2017-06-07 16:13:44 -04:00
_("Your name")
end
end
def git_user_email
if current_user
current_user.commit_email_or_default
else
"your@email.com"
end
end
def default_url_to_repo(project = @project)
case default_clone_protocol
when 'ssh'
project.ssh_url_to_repo
else
project.http_url_to_repo
end
end
2018-09-06 03:27:39 -04:00
def default_clone_label
_("Copy %{protocol} clone URL") % { protocol: default_clone_protocol.upcase }
end
def default_clone_protocol
if allowed_protocols_present?
enabled_protocol
else
2018-06-20 12:38:42 -04:00
extra_default_clone_protocol
end
end
def extra_default_clone_protocol
if !current_user || current_user.require_ssh_key?
gitlab_config.protocol
else
'ssh'
end
end
def project_last_activity(project)
if project.last_activity_at
time_ago_with_tooltip(project.last_activity_at, placement: 'bottom', html_class: 'last_activity_time_ago')
else
2017-06-07 16:13:44 -04:00
s_("ProjectLastActivity|Never")
end
end
2014-12-31 08:07:48 -05:00
def project_status_css_class(status)
case status
when "started"
2018-06-05 21:09:58 -04:00
"table-active"
2014-12-31 08:07:48 -05:00
when "failed"
2018-06-05 21:09:58 -04:00
"table-danger"
2014-12-31 08:07:48 -05:00
when "finished"
2018-06-05 21:09:58 -04:00
"table-success"
2014-12-31 08:07:48 -05:00
end
end
def readme_cache_key
sha = @project.commit.try(:sha) || 'nil'
[@project.full_path, sha, "readme"].join('-')
end
def current_ref
@ref || @repository.try(:root_ref)
end
def project_child_container_class(view_path)
view_path == "projects/issues/issues" ? "gl-mt-3" : "project-show-#{view_path}"
end
def project_issues(project)
IssuesFinder.new(current_user, project_id: project.id).execute
end
def restricted_levels
return [] if current_user.admin?
Gitlab::CurrentSettings.restricted_visibility_levels || []
end
def project_permissions_settings(project)
feature = project.project_feature
{
packagesEnabled: !!project.packages_enabled,
visibilityLevel: project.visibility_level,
requestAccessEnabled: !!project.request_access_enabled,
issuesAccessLevel: feature.issues_access_level,
repositoryAccessLevel: feature.repository_access_level,
forkingAccessLevel: feature.forking_access_level,
mergeRequestsAccessLevel: feature.merge_requests_access_level,
buildsAccessLevel: feature.builds_access_level,
wikiAccessLevel: feature.wiki_access_level,
snippetsAccessLevel: feature.snippets_access_level,
pagesAccessLevel: feature.pages_access_level,
analyticsAccessLevel: feature.analytics_access_level,
containerRegistryEnabled: !!project.container_registry_enabled,
lfsEnabled: !!project.lfs_enabled,
emailsDisabled: project.emails_disabled?,
metricsDashboardAccessLevel: feature.metrics_dashboard_access_level,
operationsAccessLevel: feature.operations_access_level,
showDefaultAwardEmojis: project.show_default_award_emojis?,
warnAboutPotentiallyUnwantedCharacters: project.warn_about_potentially_unwanted_characters?,
securityAndComplianceAccessLevel: project.security_and_compliance_access_level,
containerRegistryAccessLevel: feature.container_registry_access_level
}
end
def project_allowed_visibility_levels(project)
Gitlab::VisibilityLevel.values.select do |level|
project.visibility_level_allowed?(level) && !restricted_levels.include?(level)
end
end
def find_file_path
return unless @project && !@project.empty_repo?
return unless can?(current_user, :download_code, @project)
ref = @ref || @project.repository.root_ref
project_find_file_path(@project, ref)
end
def can_show_last_commit_in_list?(project)
can?(current_user, :read_cross_project) && project.commit
end
2018-01-03 03:07:03 -05:00
def pages_https_only_disabled?
!@project.pages_domains.all?(&:https?)
end
def pages_https_only_title
return unless pages_https_only_disabled?
"You must enable HTTPS for all your domains first"
end
def pages_https_only_label_class
if pages_https_only_disabled?
"list-label disabled"
else
"list-label"
end
end
2018-06-20 12:38:42 -04:00
def filter_starrer_path(options = {})
options = params.slice(:sort).merge(options).permit!
"#{request.path}?#{options.to_param}"
end
2018-11-08 02:02:44 -05:00
def sidebar_operations_paths
%w[
environments
clusters
cluster_agents
2018-12-06 13:08:49 -05:00
functions
error_tracking
alert_management
incidents
incident_management
2018-11-08 02:02:44 -05:00
user
gcp
logs
product_analytics
metrics_dashboard
feature_flags
tracings
terraform
2018-11-08 02:02:44 -05:00
]
end
def user_can_see_auto_devops_implicitly_enabled_banner?(project, user)
Ability.allowed?(user, :admin_project, project) &&
project.has_auto_devops_implicitly_enabled? &&
project.builds_enabled? &&
!project.repository.gitlab_ci_yml
end
def show_visibility_confirm_modal?(project)
project.unlink_forks_upon_visibility_decrease_enabled? && project.visibility_level > Gitlab::VisibilityLevel::PRIVATE && project.forks_count > 0
end
def confirm_reduce_visibility_message(project)
strong_start = "<strong>".html_safe
strong_end = "</strong>".html_safe
message = _("You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end}.")
if project.group
message = _("You're about to reduce the visibility of the project %{strong_start}%{project_name}%{strong_end} in %{strong_start}%{group_name}%{strong_end}.")
end
html_escape(message) % { strong_start: strong_start, strong_end: strong_end, project_name: project.name, group_name: project.group ? project.group.name : nil }
end
def visibility_confirm_modal_data(project, target_form_id = nil)
{
target_form_id: target_form_id,
button_testid: 'reduce-project-visibility-button',
confirm_button_text: _('Reduce project visibility'),
confirm_danger_message: confirm_reduce_visibility_message(project),
phrase: project.full_path,
additional_information: _('Note: current forks will keep their visibility level.'),
html_confirmation_message: true.to_s,
show_visibility_confirm_modal: show_visibility_confirm_modal?(project).to_s
}
end
def build_project_breadcrumb_link(project)
project_name = simple_sanitize(project.name)
push_to_schema_breadcrumb(project_name, project_path(project))
link_to project_path(project) do
icon = project_icon(project, alt: project_name, class: 'avatar-tile', width: 15, height: 15) if project.avatar_url && !Rails.env.test?
[icon, content_tag("span", project_name, class: "breadcrumb-item-text js-breadcrumb-item-text")].join.html_safe
end
end
def build_namespace_breadcrumb_link(project)
if project.group
group_title(project.group, nil, nil)
else
owner = project.namespace.owner
name = simple_sanitize(owner.name)
url = user_path(owner)
push_to_schema_breadcrumb(name, url)
link_to(name, url)
end
end
2012-09-07 12:57:13 -04:00
end
ProjectsHelper.prepend_mod_with('ProjectsHelper')