Class: ProjectPresenter

Inherits:
Gitlab::View::Presenter::Delegated show all
Includes:
ActionView::Helpers::NumberHelper, BlobHelper, ChecksCollaboration, Ci::PipelineEditorHelper, Gitlab::Experiment::Dsl, Gitlab::Utils::StrongMemoize, GitlabRoutingHelper, IconsHelper, Projects::PagesHelper, SafeFormatHelper, StorageHelper, TreeHelper
Defined in:
app/presenters/project_presenter.rb

Defined Under Namespace

Classes: AnchorData

Constant Summary collapse

MAX_TOPICS_TO_SHOW =
3

Constants included from IconsHelper

IconsHelper::DEFAULT_ICON_SIZE, IconsHelper::VARIANT_CLASSES

Constants included from Routing::PseudonymizationHelper

Routing::PseudonymizationHelper::PSEUDONOMIZED_GROUP, Routing::PseudonymizationHelper::PSEUDONOMIZED_ID, Routing::PseudonymizationHelper::PSEUDONOMIZED_NAMESPACE, Routing::PseudonymizationHelper::PSEUDONOMIZED_PROJECT, Routing::PseudonymizationHelper::PSEUDONOMIZED_USERNAME

Instance Method Summary collapse

Methods included from Projects::PagesHelper

#build_pages_url, #can_create_pages_custom_domains?, #pages_custom_domain_enabled?, #pages_subdomain

Methods included from SafeFormatHelper

#safe_format, #tag_pair

Methods included from ChecksCollaboration

#can_collaborate_with_project?, #user_access

Methods included from BlobHelper

#blob_editor_paths, #blob_icon, #blob_raw_path, #blob_raw_url, #blob_render_error_options, #blob_render_error_reason, #can_modify_blob?, #can_modify_blob_with_web_ide?, #contribution_options, #copy_blob_source_button, #copy_file_path_button, #dockerfile_names, #download_blob_button, #edit_blob_app_data, #edit_blob_button, #edit_blob_fork_params, #edit_blob_path, #edit_button_tag, #edit_disabled_button_tag, #edit_fork_button_tag, #edit_link_tag, #editing_preview_title, #encode_ide_path, #fork_and_edit_path, #fork_path_for_current_user, #gitignore_names, #gitlab_ci_ymls, #ide_edit_path, #ide_fork_and_edit_path, #ide_merge_request_path, #licenses_for_select, #open_raw_blob_button, #parent_dir_raw_path, #readable_blob, #ref_project, #sanitize_svg_data, #vue_blob_app_data, #vue_blob_header_app_data

Methods included from IconsHelper

#audit_icon, #boolean_to_icon, #custom_icon, #external_snippet_icon, #file_type_icon_class, #gl_loading_icon, #illustrations_path, #sprite_file_icons_path, #sprite_icon, #sprite_icon_path, #visibility_level_icon

Methods included from Ci::PipelineEditorHelper

#can_view_pipeline_editor?, #current_branch, #js_pipeline_editor_data

Methods included from TreeHelper

#breadcrumb_data_attributes, #can_edit_tree?, #code_dropdown_ide_data, #compact_code_dropdown_data, #compare_path, #directory_download_links, #download_links, #edit_in_new_fork_notice, #edit_in_new_fork_notice_now, #fork_modal_options, #on_top_of_branch?, #patch_branch_name, #path_breadcrumbs, #relative_url_root, #selected_branch, #tree_edit_branch, #tree_icon, #tree_join, #vue_file_list_data, #vue_tree_header_app_data, #web_ide_button_data

Methods included from WebIdeButtonHelper

#can_collaborate?, #can_create_mr_from_fork?, #edit_url, #fork?, #gitpod_url, #needs_to_fork?, #project_fork, #project_to_use, #readable_blob?, #show_edit_button?, #show_gitpod_button?, #show_pipeline_editor_button?, #show_web_ide_button?, #web_ide_url

Methods included from StorageHelper

#storage_counter, #storage_counters_details

Methods included from Routing::PackagesHelper

#package_path

Methods included from Routing::PseudonymizationHelper

#masked_page_url, #masked_query_params, #masked_referrer_url, #referrer_params

Methods included from Routing::GraphqlHelper

#graphql_etag_pipeline_path, #graphql_etag_pipeline_sha_path, #graphql_etag_project_on_demand_scan_counts_path

Methods included from Routing::WikiHelper

#group_wiki_page_url, #project_wiki_page_url, #wiki_page_path, #wiki_path

Methods included from Routing::SnippetsHelper

#gitlab_raw_snippet_blob_url, #gitlab_raw_snippet_url, #gitlab_snippet_note_path, #gitlab_snippet_notes_path, #gitlab_snippet_path, #gitlab_snippet_url, #gitlab_toggle_award_emoji_snippet_note_path, #preview_markdown_path, #toggle_award_emoji_personal_snippet_path, #toggle_award_emoji_project_project_snippet_path, #toggle_award_emoji_project_project_snippet_url

Methods included from Routing::PipelineSchedulesHelper

#edit_pipeline_schedule_path, #pipeline_schedule_path, #pipeline_schedules_path, #play_pipeline_schedule_path, #take_ownership_pipeline_schedule_path

Methods included from Routing::ArtifactsHelper

#artifacts_action_path, #expose_fast_artifacts_path, #fast_browse_project_job_artifacts_path, #fast_download_project_job_artifacts_path, #fast_keep_project_job_artifacts_path

Methods included from Routing::MembersHelper

#source_members_url

Methods included from Routing::Groups::MembersHelper

#approve_access_request_group_member_path, #group_member_path, #group_members_url, #leave_group_members_path, #request_access_group_members_path, #resend_invite_group_member_path

Methods included from Routing::Projects::MembersHelper

#approve_access_request_project_member_path, #leave_project_members_path, #project_member_path, #project_members_url, #request_access_project_members_path, #resend_invite_project_member_path

Methods included from Routing::ProjectsHelper

#commit_url, #commits_url, #edit_milestone_path, #environment_delete_path, #environment_path, #issue_path, #issue_url, #merge_request_path, #merge_request_url, #pipeline_job_url, #pipeline_path, #pipeline_url, #project_commits_path, #project_ref_path, #project_tree_path, #release_url, #toggle_subscription_path, #work_item_url

Methods included from API::Helpers::RelatedResourcesHelpers

#expose_path, #expose_url, #issues_available?, #mrs_available?, #project_feature_string_access_level

Methods included from ApplicationSettingsHelper

#all_protocols_enabled?, #allowed_protocols_present?, #anti_spam_service_enabled?, #custom_admin_roles_available?, #default_search_scope_options_for_select, #deletion_protection_data, #deprecated_attributes, #enabled_protocol, #enabled_protocol_button, #expanded_by_default?, #external_authorization_allow_token_help_text, #external_authorization_client_certificate_help_text, #external_authorization_client_key_help_text, #external_authorization_client_pass_help_text, #external_authorization_client_url_help_text, #external_authorization_description, #external_authorization_service_attributes, #external_authorization_timeout_help_text, #external_authorization_url_help_text, #global_search_settings_checkboxes, #http_enabled?, #import_sources_checkboxes, #instance_clusters_enabled?, #integration_expanded?, #key_restriction_options_for_select, #kroki_available_formats, #oauth_providers_checkboxes, #pending_user_count, #registration_features_can_be_prompted?, #repository_storages_options_json, #restricted_level_checkboxes, #runner_token_expiration_interval_attributes, #sidekiq_job_limiter_mode_help_text, #sidekiq_job_limiter_modes_for_select, #signup_enabled?, #signup_form_data, #ssh_enabled?, #storage_weights, #user_oauth_applications?, #valid_runner_registrars, #visible_attributes, #vscode_extension_marketplace_settings_description, #vscode_extension_marketplace_settings_view

Methods included from ProjectsHelper

#able_to_see_forks_count?, #able_to_see_issues?, #able_to_see_merge_requests?, #any_projects?, #archiving_available?, #author_content_tag, #autodeploy_flash_notice, #badge_count, #branch_rules_path, #can_admin_associated_clusters?, #can_change_visibility_level?, #can_disable_emails?, #can_push_code?, #can_set_diff_preview_in_email?, #can_view_branch_rules?, #clusters_deprecation_alert_message, #dashboard_projects_app_data, #delete_confirm_phrase, #directory?, #error_tracking_setting_project_json, #explore_projects_tab?, #external_classification_label_help_message, #fork_button_data_attributes, #hidden_issue_icon, #home_panel_data_attributes, #http_clone_url_to_repo, #import_from_bitbucket_message, #inactive_project_deletion_date, #issue_css_classes, #issue_manual_ordering_class, #last_pipeline_from_status_cache, #last_push_event, #link_to_autodeploy_doc, #link_to_data_loss_doc, #link_to_member, #link_to_member_avatar, #link_to_namespace_change_doc, #link_to_project, #load_catalog_resources, #load_pipeline_status, #localized_project_human_access, #membership_locked?, #no_password_message, #notification_data_attributes, #project_archive_settings_app_data, #project_can_be_shared?, #project_classes, #project_coverage_chart_data_attributes, #project_incident_management_setting, #project_license_name, #project_pages_domain_choices, #project_permissions_panel_data, #project_unarchive_settings_app_data, #projects_filtered_search_and_sort_app_data, #push_project_breadcrumbs, #push_to_create_project_command, #remote_mirror_setting_enabled?, #remove_fork_project_confirm_json, #remove_fork_project_description_message, #remove_fork_project_warning_message, #remove_project_message, #show_archived_badge?, #show_auto_devops_implicitly_enabled_banner?, #show_clusters_alert?, #show_count?, #show_dashboard_projects_welcome_page?, #show_inactive_project_deletion_banner?, #show_invalid_gpg_key_message?, #show_lfs_misconfiguration_banner?, #show_mobile_devops_project_promo?, #show_no_password_message?, #show_no_ssh_key_message?, #show_terraform_banner?, #show_xcode_link?, #ssh_clone_url_to_repo, #star_count_data_attributes, #transfer_project_confirm_button, #transfer_project_message, #visibility_level_content, #visible_fork_source, #vue_fork_divergence_data, #xcode_uri_to_repo

Methods included from Gitlab::Allowable

#can?, #can_all?, #can_any?

Methods included from CompareHelper

#create_mr_button?, #create_mr_path, #project_compare_selector_data, #target_projects

Methods inherited from Gitlab::View::Presenter::Delegated

#initialize

Methods included from Gitlab::Utils::DelegatorOverride

#delegator_override, #delegator_override_with, #delegator_target, validator, validators, verify!

Methods included from Gitlab::View::Presenter::Base

#__subject__, #can?, #declarative_policy_delegate, #is_a?, #path_with_line_numbers, #present, #url_builder, #web_path, #web_url

Methods included from Gitlab::Routing

includes_helpers, redirect_legacy_paths, url_helpers

Constructor Details

This class inherits a constructor from Gitlab::View::Presenter::Delegated

Instance Method Details

#add_changelog_ide_pathObject



124
125
126
# File 'app/presenters/project_presenter.rb', line 124

def add_changelog_ide_path
  ide_edit_path(project, default_branch_or_main, 'CHANGELOG')
end

#add_changelog_pathObject



120
121
122
# File 'app/presenters/project_presenter.rb', line 120

def add_changelog_path
  add_special_file_path(file_name: 'CHANGELOG')
end

#add_contribution_guide_ide_pathObject



132
133
134
# File 'app/presenters/project_presenter.rb', line 132

def add_contribution_guide_ide_path
  ide_edit_path(project, default_branch_or_main, 'CONTRIBUTING.md')
end

#add_contribution_guide_pathObject



128
129
130
# File 'app/presenters/project_presenter.rb', line 128

def add_contribution_guide_path
  add_special_file_path(file_name: 'CONTRIBUTING.md', commit_message: 'Add CONTRIBUTING')
end

#add_license_ide_pathObject



116
117
118
# File 'app/presenters/project_presenter.rb', line 116

def add_license_ide_path
  ide_edit_path(project, default_branch_or_main, 'LICENSE')
end

#add_license_pathObject



112
113
114
# File 'app/presenters/project_presenter.rb', line 112

def add_license_path
  add_special_file_path(file_name: 'LICENSE')
end

#add_readme_ide_pathObject



140
141
142
# File 'app/presenters/project_presenter.rb', line 140

def add_readme_ide_path
  ide_edit_path(project, default_branch_or_main, 'README.md')
end

#add_readme_pathObject



136
137
138
# File 'app/presenters/project_presenter.rb', line 136

def add_readme_path
  add_special_file_path(file_name: 'README.md')
end

#all_clusters_empty?Boolean



456
457
458
459
460
# File 'app/presenters/project_presenter.rb', line 456

def all_clusters_empty?
  strong_memoize(:all_clusters_empty) do
    project.all_clusters.empty?
  end
end

#autodevops_anchor_data(show_auto_devops_callout: false) ⇒ Object



361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# File 'app/presenters/project_presenter.rb', line 361

def autodevops_anchor_data(show_auto_devops_callout: false)
  return unless project.feature_available?(:builds, current_user)

  if current_user && can?(current_user, :admin_pipeline, project) && !project.has_ci_config_file? && !show_auto_devops_callout
    if auto_devops_enabled?
      AnchorData.new(
        false,
        statistic_icon('settings', 'subtle') + _('Auto DevOps enabled'),
        project_settings_ci_cd_path(project, anchor: 'autodevops-settings'),
        'btn-default'
      )
    else
      AnchorData.new(
        false,
        (:span, statistic_icon('plus', 'info') + _('Enable Auto DevOps')),
        project_settings_ci_cd_path(project, anchor: 'autodevops-settings')
      )
    end
  elsif auto_devops_enabled?
    AnchorData.new(false, _('Auto DevOps enabled'), nil)
  end
end

#branches_anchor_dataObject



216
217
218
219
220
221
222
223
# File 'app/presenters/project_presenter.rb', line 216

def branches_anchor_data
  AnchorData.new(
    true,
    statistic_icon('branch', 'subtle') +
    safe_format(n_('%{strong_start}%{branch_count}%{strong_end} Branch', '%{strong_start}%{branch_count}%{strong_end} Branches', repository.branch_count), 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)
  )
end

#can_current_user_push_code?Boolean



149
150
151
152
153
154
155
156
157
# File 'app/presenters/project_presenter.rb', line 149

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

#can_current_user_push_to_branch?(branch) ⇒ Boolean



159
160
161
162
163
# File 'app/presenters/project_presenter.rb', line 159

def can_current_user_push_to_branch?(branch)
  return false unless current_user

  user_access(project).can_push_to_branch?(branch)
end

#can_current_user_push_to_default_branch?Boolean



165
166
167
# File 'app/presenters/project_presenter.rb', line 165

def can_current_user_push_to_default_branch?
  can_current_user_push_to_branch?(default_branch)
end

#can_setup_review_app?Boolean



450
451
452
453
454
# File 'app/presenters/project_presenter.rb', line 450

def can_setup_review_app?
  strong_memoize(:can_setup_review_app) do
    (can_instantiate_cluster? && all_clusters_empty?) || cicd_missing?
  end
end

#changelog_anchor_dataObject



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'app/presenters/project_presenter.rb', line 300

def changelog_anchor_data
  if can_current_user_push_to_default_branch? && repository.changelog.blank?
    icon = statistic_icon('plus', 'info')
    label = icon + _('Add CHANGELOG')
    AnchorData.new(
      false,
      label,
      empty_repo? ? add_changelog_ide_path : add_changelog_path
    )
  elsif repository.changelog.present?
    AnchorData.new(
      false,
      statistic_icon('doc-text', 'subtle') + _('CHANGELOG'),
      changelog_path,
      'btn-default'
    )
  end
end

#changelog_pathObject



98
99
100
# File 'app/presenters/project_presenter.rb', line 98

def changelog_path
  filename_path(repository.changelog&.name)
end

#commits_anchor_dataObject



207
208
209
210
211
212
213
214
# File 'app/presenters/project_presenter.rb', line 207

def commits_anchor_data
  AnchorData.new(
    true,
    statistic_icon('commit', 'subtle') +
    safe_format(n_('%{strong_start}%{commit_count}%{strong_end} Commit', '%{strong_start}%{commit_count}%{strong_end} Commits', statistics.commit_count), 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)
  )
end

#contribution_guide_anchor_dataObject



342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'app/presenters/project_presenter.rb', line 342

def contribution_guide_anchor_data
  if can_current_user_push_to_default_branch? && repository.contribution_guide.blank?
    icon = statistic_icon('plus', 'info')
    label = icon + _('Add CONTRIBUTING')
    AnchorData.new(
      false,
      label,
      empty_repo? ? add_contribution_guide_ide_path : add_contribution_guide_path
    )
  elsif repository.contribution_guide.present?
    AnchorData.new(
      false,
      statistic_icon('doc-text', 'subtle') + _('CONTRIBUTING'),
      contribution_guide_path,
      'btn-default'
    )
  end
end

#contribution_guide_pathObject



106
107
108
109
110
# File 'app/presenters/project_presenter.rb', line 106

def contribution_guide_path
  if project && contribution_guide = repository.contribution_guide
    project_blob_path(project, tree_join(project.default_branch, contribution_guide.name))
  end
end

#count_of_extra_topics_not_shownObject



434
435
436
437
438
439
440
# File 'app/presenters/project_presenter.rb', line 434

def count_of_extra_topics_not_shown
  if project_topic_list.count > MAX_TOPICS_TO_SHOW
    project_topic_list.count - MAX_TOPICS_TO_SHOW
  else
    0
  end
end

#default_viewObject



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'app/presenters/project_presenter.rb', line 76

def default_view
  return anonymous_project_view unless current_user

  user_view = current_user.project_view

  if can?(current_user, :read_code, project)
    user_view
  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'
  else
    'activity'
  end
end

#empty_repo_statistics_anchorsObject



57
58
59
# File 'app/presenters/project_presenter.rb', line 57

def empty_repo_statistics_anchors
  []
end

#empty_repo_statistics_buttonsObject



61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'app/presenters/project_presenter.rb', line 61

def empty_repo_statistics_buttons
  [
    upload_anchor_data,
    new_file_anchor_data,
    readme_anchor_data,
    license_anchor_data,
    changelog_anchor_data,
    contribution_guide_anchor_data,
    gitlab_ci_anchor_data,
    wiki_anchor_data,
    integrations_anchor_data,
    observability_anchor_data
  ].compact.reject { |item| item.is_link }
end

#environments_anchor_dataObject



193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'app/presenters/project_presenter.rb', line 193

def environments_anchor_data
  return unless can?(current_user, :read_environment, project)

  environments_count = project.environments.available.count
  return if environments_count == 0

  AnchorData.new(
    true,
    statistic_icon('environment', 'subtle') +
    safe_format(n_('%{strong_start}%{count}%{strong_end} Environment', '%{strong_start}%{count}%{strong_end} Environments', environments_count), count: number_with_delimiter(environments_count), strong_start: '<strong class="project-stat-value">'.html_safe, strong_end: '</strong>'.html_safe),
    project_environments_path(project)
  )
end

#gitlab_ci_anchor_dataObject



396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
# File 'app/presenters/project_presenter.rb', line 396

def gitlab_ci_anchor_data
  return unless can_view_pipeline_editor?(project)

  if !cicd_enabled?
    AnchorData.new(false,
      (:span, statistic_icon('plus', 'subtle') + _('Set up CI/CD')),
      nil,
      'btn-link !gl-px-0',
      nil, nil,
      { title: _('CI/CD is disabled for this project') }
    )
  elsif cicd_missing?
    AnchorData.new(false, (:span, statistic_icon('plus', 'info') + _('Set up CI/CD')), project_ci_pipeline_editor_path(project))
  elsif project.has_ci_config_file?
    AnchorData.new(false, statistic_icon('rocket', 'subtle') + _('CI/CD configuration'), project_ci_pipeline_editor_path(project), 'btn-default')
  end
end

#has_extra_topics?Boolean



442
443
444
# File 'app/presenters/project_presenter.rb', line 442

def has_extra_topics?
  count_of_extra_topics_not_shown > 0
end

#has_review_app?Boolean



446
447
448
# File 'app/presenters/project_presenter.rb', line 446

def has_review_app?
  !project.environments_for_scope('review/*').empty?
end

#kubernetes_cluster_anchor_dataObject



384
385
386
387
388
389
390
391
392
393
394
# File 'app/presenters/project_presenter.rb', line 384

def kubernetes_cluster_anchor_data
  if can_instantiate_cluster?
    if clusters.empty?
      AnchorData.new(false, (:span, statistic_icon('plus', 'info') + _('Add Kubernetes cluster')), project_clusters_path(project))
    else
      cluster_link = clusters.count == 1 ? project_cluster_path(project, clusters.first) : project_clusters_path(project)

      AnchorData.new(false, _('Kubernetes'), cluster_link, 'btn-default')
    end
  end
end

#license_anchor_dataObject



319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'app/presenters/project_presenter.rb', line 319

def license_anchor_data
  icon = statistic_icon('scale', 'subtle')

  if repository.license_blob.present?
    AnchorData.new(
      false,
      icon + (:span, license_short_name, class: 'project-stat-value'),
      license_path,
      'btn-default',
      nil,
      'license'
    )
  elsif can_current_user_push_to_default_branch?
    icon = statistic_icon('plus', 'info')
    label = icon + _('Add LICENSE')
    AnchorData.new(
      false,
      (:span, label, class: 'add-license-link gl-flex'),
      empty_repo? ? add_license_ide_path : add_license_path
    )
  end
end

#license_pathObject



102
103
104
# File 'app/presenters/project_presenter.rb', line 102

def license_path
  filename_path(repository.license_blob&.name)
end

#license_short_nameObject



144
145
146
147
# File 'app/presenters/project_presenter.rb', line 144

def license_short_name
  license = repository.license
  license&.nickname || license&.name || 'LICENSE'
end

#new_file_anchor_dataObject



276
277
278
279
280
281
282
# File 'app/presenters/project_presenter.rb', line 276

def new_file_anchor_data
  if can_current_user_push_to_default_branch?
    new_file_path = empty_repo? ? ide_edit_path(project, default_branch_or_main) : project_new_blob_path(project, default_branch_or_main)

    AnchorData.new(false, statistic_icon('plus', 'info') + _('New file'), new_file_path)
  end
end

#observability_anchor_dataObject



469
470
471
472
473
474
475
476
477
# File 'app/presenters/project_presenter.rb', line 469

def observability_anchor_data
  return unless project.group.present? && can_read_observability? && observability_feature_enabled?

  if observability_settings.present?
    AnchorData.new(false, statistic_icon('status-health', 'subtle') + s_('Observability|Observability configuration'), group_observability_setup_path(project.group), 'btn-default')
  else
    AnchorData.new(false, (:span, statistic_icon('plus', 'info') + s_('Observability|Enable Observability')), group_observability_setup_path(project.group), nil, nil, nil)
  end
end

#pages_anchor_dataObject



462
463
464
465
466
467
# File 'app/presenters/project_presenter.rb', line 462

def pages_anchor_data
  return unless project.pages_deployed? && can?(current_user, :read_pages_content, project)

  pages_url = build_pages_url(project)
  AnchorData.new(false, statistic_icon('external-link', 'subtle') + _('GitLab Pages'), pages_url, 'btn-default', nil)
end

#readme_anchor_dataObject



284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'app/presenters/project_presenter.rb', line 284

def readme_anchor_data
  if can_current_user_push_to_default_branch? && readme_path.nil?
    icon = statistic_icon('plus', 'info')
    label = icon + _('Add README')
    AnchorData.new(false, label, empty_repo? ? add_readme_ide_path : add_readme_path)
  elsif readme_path
    AnchorData.new(
      false,
      statistic_icon('doc-text', 'subtle') + _('README'),
      default_view != 'readme' ? readme_path : '#readme',
      'btn-default',
      'doc-text'
    )
  end
end

#readme_pathObject



94
95
96
# File 'app/presenters/project_presenter.rb', line 94

def readme_path
  filename_path(repository.readme_path)
end

#releases_anchor_dataObject



179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'app/presenters/project_presenter.rb', line 179

def releases_anchor_data
  return unless can?(current_user, :read_release, project)

  releases_count = project.releases.count
  return if releases_count < 1

  AnchorData.new(
    true,
    statistic_icon('rocket-launch', 'subtle') +
    safe_format(n_('%{strong_start}%{release_count}%{strong_end} Release', '%{strong_start}%{release_count}%{strong_end} Releases', releases_count), 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)
  )
end

#statistic_icon(icon_name = 'plus', variant = 'info') ⇒ Object



25
26
27
# File 'app/presenters/project_presenter.rb', line 25

def statistic_icon(icon_name = 'plus', variant = 'info')
  sprite_icon(icon_name, css_class: 'gl-mr-3', variant: variant)
end

#statistics_anchors(show_auto_devops_callout:) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
# File 'app/presenters/project_presenter.rb', line 29

def statistics_anchors(show_auto_devops_callout:)
  [
    commits_anchor_data,
    branches_anchor_data,
    terraform_states_anchor_data,
    tags_anchor_data,
    storage_anchor_data,
    releases_anchor_data,
    environments_anchor_data
  ].compact.select(&:is_link)
end

#statistics_buttons(show_auto_devops_callout:) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'app/presenters/project_presenter.rb', line 41

def statistics_buttons(show_auto_devops_callout:)
  [
    readme_anchor_data,
    license_anchor_data,
    changelog_anchor_data,
    contribution_guide_anchor_data,
    autodevops_anchor_data(show_auto_devops_callout: show_auto_devops_callout),
    kubernetes_cluster_anchor_data,
    gitlab_ci_anchor_data,
    wiki_anchor_data,
    integrations_anchor_data,
    pages_anchor_data,
    observability_anchor_data
  ].compact.reject(&:is_link).sort_by.with_index { |item, idx| [item.class_modifier ? 0 : 1, idx] }
end

#storage_anchor_dataObject



169
170
171
172
173
174
175
176
177
# File 'app/presenters/project_presenter.rb', line 169

def storage_anchor_data
  return unless can?(current_user, :admin_project, project) && !empty_repo?

  AnchorData.new(
    true,
    statistic_icon('disk', 'subtle') + storage_anchor_text,
    project_usage_quotas_path(project)
  )
end

#tags_anchor_dataObject



243
244
245
246
247
248
249
250
# File 'app/presenters/project_presenter.rb', line 243

def tags_anchor_data
  AnchorData.new(
    true,
    statistic_icon('label', 'subtle') +
    safe_format(n_('%{strong_start}%{tag_count}%{strong_end} Tag', '%{strong_start}%{tag_count}%{strong_end} Tags', repository.tag_count), 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)
  )
end

#terraform_states_anchor_dataObject



225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
# File 'app/presenters/project_presenter.rb', line 225

def terraform_states_anchor_data
  if project.terraform_states.exists? && can_read_terraform_state?
    terraform_warn_icon = (
      :span,
      title: s_('Terraform|Support for periods (`.`) in Terraform state names might break existing states.'),
      class: 'gl-ml-2',
      data: { toggle: 'tooltip' }
    ) { sprite_icon('error', css_class: 'gl-fill-icon-subtle') }

    AnchorData.new(
      true,
      statistic_icon('terraform', 'subtle') +
      safe_format(n_('%{strong_start}%{terraform_states_count}%{strong_end} Terraform State', '%{strong_start}%{terraform_states_count}%{strong_end} Terraform States', project.terraform_states.count), terraform_states_count: number_with_delimiter(project.terraform_states.count), strong_start: '<strong class="project-stat-value">'.html_safe, strong_end: '</strong>'.html_safe) + terraform_warn_icon,
      project_terraform_index_path(project)
    )
  end
end

#topics_not_shownObject



430
431
432
# File 'app/presenters/project_presenter.rb', line 430

def topics_not_shown
  project_topic_list - topics_to_show
end

#topics_to_showObject



426
427
428
# File 'app/presenters/project_presenter.rb', line 426

def topics_to_show
  project_topic_list.take(MAX_TOPICS_TO_SHOW) # rubocop: disable CodeReuse/ActiveRecord
end

#upload_anchor_dataObject



252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'app/presenters/project_presenter.rb', line 252

def upload_anchor_data
  strong_memoize(:upload_anchor_data) do
    next unless can_current_user_push_to_default_branch?

    AnchorData.new(
      false,
      statistic_icon('upload', 'subtle') + _('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',
        'can_push_to_branch' => 'true',
        'path' => project_create_blob_path(project, default_branch_or_main),
        'project_path' => project.full_path,
        'full_name' => project.name_with_namespace
      }
    )
  end
end

#wiki_anchor_dataObject



414
415
416
417
418
419
420
421
422
423
424
# File 'app/presenters/project_presenter.rb', line 414

def wiki_anchor_data
  return unless project.wiki_enabled? && can_read_wiki?

  if project.wiki.has_home_page?
    AnchorData.new(false, statistic_icon('book', 'subtle') + _('Wiki'), project_wiki_path, 'btn-default', nil, nil)
  elsif can_create_wiki?
    icon = statistic_icon('plus', 'info')
    label = icon + _('Add Wiki')
    AnchorData.new(false, label, project_create_wiki_path, nil, nil, nil)
  end
end