diff options
Diffstat (limited to 'app/helpers')
44 files changed, 737 insertions, 578 deletions
diff --git a/app/helpers/admin/user_actions_helper.rb b/app/helpers/admin/user_actions_helper.rb new file mode 100644 index 00000000000..cd520a75b44 --- /dev/null +++ b/app/helpers/admin/user_actions_helper.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module Admin + module UserActionsHelper + def admin_actions(user) + return [] if user.internal? + + @actions ||= ['edit'] + + return @actions if user == current_user + + @user ||= user + + blocked_actions + deactivate_actions + unlock_actions + delete_actions + + @actions + end + + private + + def blocked_actions + if @user.ldap_blocked? + @actions << 'ldap' + elsif @user.blocked? && @user.blocked_pending_approval? + @actions << 'approve' + @actions << 'reject' + elsif @user.blocked? + @actions << 'unblock' + else + @actions << 'block' + end + end + + def deactivate_actions + if @user.can_be_deactivated? + @actions << 'deactivate' + elsif @user.deactivated? + @actions << 'activate' + end + end + + def unlock_actions + @actions << 'unlock' if @user.access_locked? + end + + def delete_actions + return unless can?(current_user, :destroy_user, @user) && !@user.blocked_pending_approval? && @user.can_be_removed? + + @actions << 'delete' + @actions << 'delete_with_contributions' + end + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 2a6b00c0bd8..512ba7e2a66 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -361,9 +361,13 @@ module ApplicationHelper } end - def add_page_specific_style(path) + def add_page_specific_style(path, defer: true) content_for :page_specific_styles do - stylesheet_link_tag_defer path + if defer + stylesheet_link_tag_defer path + else + stylesheet_link_tag path + end end end diff --git a/app/helpers/application_settings_helper.rb b/app/helpers/application_settings_helper.rb index 512649b3008..7866e3e3d9f 100644 --- a/app/helpers/application_settings_helper.rb +++ b/app/helpers/application_settings_helper.rb @@ -49,12 +49,12 @@ module ApplicationSettingsHelper all_protocols_enabled? || Gitlab::CurrentSettings.enabled_git_access_protocol == 'http' end - def enabled_project_button(project, protocol) + def enabled_protocol_button(container, protocol) case protocol when 'ssh' - ssh_clone_button(project, append_link: false) + ssh_clone_button(container, append_link: false) else - http_clone_button(project, append_link: false) + http_clone_button(container, append_link: false) end end @@ -198,6 +198,7 @@ module ApplicationSettingsHelper :default_project_visibility, :default_projects_limit, :default_snippet_visibility, + :disable_feed_token, :disabled_oauth_sign_in_sources, :domain_denylist, :domain_denylist_enabled, @@ -254,6 +255,9 @@ module ApplicationSettingsHelper :password_authentication_enabled_for_git, :performance_bar_allowed_group_path, :performance_bar_enabled, + :personal_access_token_prefix, + :kroki_enabled, + :kroki_url, :plantuml_enabled, :plantuml_url, :polling_interval_multiplier, diff --git a/app/helpers/auth_helper.rb b/app/helpers/auth_helper.rb index cc43ea85a11..0b79d4c36a1 100644 --- a/app/helpers/auth_helper.rb +++ b/app/helpers/auth_helper.rb @@ -113,6 +113,10 @@ module AuthHelper end end + def experiment_enabled_button_based_providers + enabled_button_based_providers & %w(google_oauth2 github).freeze + end + def button_based_providers_enabled? enabled_button_based_providers.any? end diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb index 981b5e4d92b..0c5823894c5 100644 --- a/app/helpers/blob_helper.rb +++ b/app/helpers/blob_helper.rb @@ -1,10 +1,6 @@ # frozen_string_literal: true module BlobHelper - def no_highlight_files - %w(credits changelog news copying copyright license authors) - end - def edit_blob_path(project = @project, ref = @ref, path = @path, options = {}) project_edit_blob_path(project, tree_join(ref, path), @@ -246,7 +242,7 @@ module BlobHelper def copy_blob_source_button(blob) return unless blob.rendered_as_text?(ignore_errors: false) - clipboard_button(target: ".blob-content[data-blob-id='#{blob.id}']", class: "btn btn-sm js-copy-blob-source-btn", title: _("Copy file contents")) + clipboard_button(target: ".blob-content[data-blob-id='#{blob.id}'] > pre", class: "btn btn-sm js-copy-blob-source-btn", title: _("Copy file contents")) end def open_raw_blob_button(blob) @@ -332,8 +328,9 @@ module BlobHelper end def readable_blob(options, path, project, ref) - blob = options.delete(:blob) - blob ||= project.repository.blob_at(ref, path) rescue nil + blob = options.fetch(:blob) do + project.repository.blob_at(ref, path) rescue nil + end blob if blob&.readable_text? end @@ -382,8 +379,7 @@ module BlobHelper end def show_suggest_pipeline_creation_celebration? - Feature.enabled?(:suggest_pipeline, default_enabled: true) && - @blob.path == Gitlab::FileDetector::PATTERNS[:gitlab_ci] && + @blob.path == Gitlab::FileDetector::PATTERNS[:gitlab_ci] && @blob.auxiliary_viewer&.valid?(project: @project, sha: @commit.sha, user: current_user) && @project.uses_default_ci_config? && cookies[suggest_pipeline_commit_cookie_name].present? diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb index c999d1f94ad..ea24f469ffa 100644 --- a/app/helpers/button_helper.rb +++ b/app/helpers/button_helper.rb @@ -58,10 +58,10 @@ module ButtonHelper end end - def http_clone_button(project, append_link: true) + def http_clone_button(container, append_link: true) protocol = gitlab_config.protocol.upcase dropdown_description = http_dropdown_description(protocol) - append_url = project.http_url_to_repo if append_link + append_url = container.http_url_to_repo if append_link dropdown_item_with_description(protocol, dropdown_description, href: append_url, data: { clone_type: 'http' }) end @@ -74,13 +74,13 @@ module ButtonHelper end end - def ssh_clone_button(project, append_link: true) + def ssh_clone_button(container, append_link: true) if Gitlab::CurrentSettings.user_show_add_ssh_key_message? && current_user.try(:require_ssh_key?) - dropdown_description = _("You won't be able to pull or push project code via SSH until you add an SSH key to your profile") + dropdown_description = s_("MissingSSHKeyWarningLink|You won't be able to pull or push repositories via SSH until you add an SSH key to your profile") end - append_url = project.ssh_url_to_repo if append_link + append_url = container.ssh_url_to_repo if append_link dropdown_item_with_description('SSH', dropdown_description, href: append_url, data: { clone_type: 'ssh' }) end diff --git a/app/helpers/ci/pipeline_schedules_helper.rb b/app/helpers/ci/pipeline_schedules_helper.rb deleted file mode 100644 index 20e5c90a60e..00000000000 --- a/app/helpers/ci/pipeline_schedules_helper.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module Ci - module PipelineSchedulesHelper - def timezone_data - ActiveSupport::TimeZone.all.map do |timezone| - { - name: timezone.name, - offset: timezone.now.utc_offset, - identifier: timezone.tzinfo.identifier - } - end - end - end -end diff --git a/app/helpers/ci/runners_helper.rb b/app/helpers/ci/runners_helper.rb index 432aad663e4..ba5d4e8c65a 100644 --- a/app/helpers/ci/runners_helper.rb +++ b/app/helpers/ci/runners_helper.rb @@ -8,14 +8,14 @@ module Ci status = runner.status case status when :not_connected - content_tag(:span, title: "New runner. Has not connected yet") do + content_tag(:span, title: _("New runner. Has not connected yet")) do sprite_icon("warning-solid", size: 24, css_class: "gl-vertical-align-bottom!") end when :online, :offline, :paused - content_tag :i, nil, - class: "fa fa-circle runner-status-#{status}", - title: "Runner is #{status}, last contact was #{time_ago_in_words(runner.contacted_at)} ago" + content_tag :span, nil, + class: "gl-display-inline-block gl-avatar gl-avatar-s16 gl-avatar-circle runner-status runner-status-#{status}", + title: _("Runner is %{status}, last contact was %{runner_contact} ago") % { status: status, runner_contact: time_ago_in_words(runner.contacted_at) } end end @@ -49,6 +49,14 @@ module Ci parent_shared_runners_availability: group.parent&.shared_runners_setting } end + + def toggle_shared_runners_settings_data(project) + { + is_enabled: "#{project.shared_runners_enabled?}", + is_disabled_and_unoverridable: "#{project.group&.shared_runners_setting == 'disabled_and_unoverridable'}", + update_path: toggle_shared_runners_project_runners_path(project) + } + end end end diff --git a/app/helpers/container_registry_helper.rb b/app/helpers/container_registry_helper.rb index 9a5d84a90dd..0efc8c50d58 100644 --- a/app/helpers/container_registry_helper.rb +++ b/app/helpers/container_registry_helper.rb @@ -5,4 +5,8 @@ module ContainerRegistryHelper Feature.enabled?(:container_registry_expiration_policies_throttling) && ContainerRegistry::Client.supports_tag_delete? end + + def container_repository_gid_prefix + "gid://#{GlobalID.app}/#{ContainerRepository.name}/" + end end diff --git a/app/helpers/defer_script_tag_helper.rb b/app/helpers/defer_script_tag_helper.rb deleted file mode 100644 index be927c67aaa..00000000000 --- a/app/helpers/defer_script_tag_helper.rb +++ /dev/null @@ -1,10 +0,0 @@ -# frozen_string_literal: true - -module DeferScriptTagHelper - # Override the default ActionView `javascript_include_tag` helper to support page specific deferred loading. - # PLEASE NOTE: `defer` is also critical so that we don't run JavaScript entrypoints before the DOM is ready. - # Please see https://gitlab.com/groups/gitlab-org/-/epics/4538#note_432159769. - def javascript_include_tag(*sources) - super(*sources, defer: true) - end -end diff --git a/app/helpers/diff_helper.rb b/app/helpers/diff_helper.rb index d6d06434590..69a2efebb1f 100644 --- a/app/helpers/diff_helper.rb +++ b/app/helpers/diff_helper.rb @@ -203,14 +203,6 @@ module DiffHelper set_secure_cookie(:diff_view, params.delete(:view), type: CookiesHelper::COOKIE_TYPE_PERMANENT) if params[:view].present? end - def unified_diff_lines_view_type(project) - if Feature.enabled?(:unified_diff_lines, project, default_enabled: true) - 'inline' - else - diff_view - end - end - private def diff_btn(title, name, selected) diff --git a/app/helpers/dropdowns_helper.rb b/app/helpers/dropdowns_helper.rb index e10e9a83b05..45f5281b515 100644 --- a/app/helpers/dropdowns_helper.rb +++ b/app/helpers/dropdowns_helper.rb @@ -51,7 +51,7 @@ module DropdownsHelper default_label = data_attr[:default_label] content_tag(:button, disabled: options[:disabled], class: "dropdown-menu-toggle #{options[:toggle_class] if options.key?(:toggle_class)}", id: (options[:id] if options.key?(:id)), type: "button", data: data_attr) do output = content_tag(:span, toggle_text, class: "dropdown-toggle-text #{'is-default' if toggle_text == default_label}") - output << icon('chevron-down') + output << sprite_icon('chevron-down', css_class: "dropdown-menu-toggle-icon gl-top-3") output.html_safe end end diff --git a/app/helpers/environment_helper.rb b/app/helpers/environment_helper.rb index c4487ae8e4a..491d2731e91 100644 --- a/app/helpers/environment_helper.rb +++ b/app/helpers/environment_helper.rb @@ -52,6 +52,8 @@ module EnvironmentHelper s_('Deployment|failed') when 'canceled' s_('Deployment|canceled') + when 'skipped' + s_('Deployment|skipped') end klass = "ci-status ci-#{status.dasherize}" diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index f40755b9439..e6603237676 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -256,7 +256,7 @@ module EventsHelper end else content_tag :div, class: 'system-note-image user-avatar' do - author_avatar(event, size: 40) + author_avatar(event, size: 32) end end end diff --git a/app/helpers/form_helper.rb b/app/helpers/form_helper.rb index 8a8d708b0b2..d0276c91316 100644 --- a/app/helpers/form_helper.rb +++ b/app/helpers/form_helper.rb @@ -55,7 +55,7 @@ module FormHelper dropdown_data end - def reviewers_dropdown_options(issuable_type) + def reviewers_dropdown_options(issuable_type, iid = nil, target_branch = nil) dropdown_data = { toggle_class: 'js-reviewer-search js-multiselect js-save-user-data', title: 'Request review from', @@ -78,6 +78,14 @@ module FormHelper } } + if iid + dropdown_data[:data][:iid] = iid + end + + if target_branch + dropdown_data[:data][:target_branch] = target_branch + end + if merge_request_supports_multiple_reviewers? dropdown_data = multiple_reviewers_dropdown_options(dropdown_data) end diff --git a/app/helpers/gitlab_script_tag_helper.rb b/app/helpers/gitlab_script_tag_helper.rb new file mode 100644 index 00000000000..467f3f7305b --- /dev/null +++ b/app/helpers/gitlab_script_tag_helper.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module GitlabScriptTagHelper + # Override the default ActionView `javascript_include_tag` helper to support page specific deferred loading. + # PLEASE NOTE: `defer` is also critical so that we don't run JavaScript entrypoints before the DOM is ready. + # Please see https://gitlab.com/groups/gitlab-org/-/epics/4538#note_432159769. + # The helper also makes sure the `nonce` attribute is included in every script when the content security + # policy is enabled. + def javascript_include_tag(*sources) + super(*sources, defer: true, nonce: true) + end + + # The helper makes sure the `nonce` attribute is included in every script when the content security + # policy is enabled. + def javascript_tag(content_or_options_with_block = nil, html_options = {}) + if content_or_options_with_block.is_a?(Hash) + content_or_options_with_block[:nonce] = true + else + html_options[:nonce] = true + end + + super + end +end diff --git a/app/helpers/groups/group_members_helper.rb b/app/helpers/groups/group_members_helper.rb index ee90585112b..adc9d85a384 100644 --- a/app/helpers/groups/group_members_helper.rb +++ b/app/helpers/groups/group_members_helper.rb @@ -26,7 +26,8 @@ module Groups::GroupMembersHelper { members: members_data_json(group, members), member_path: group_group_member_path(group, ':id'), - group_id: group.id + group_id: group.id, + can_manage_members: can?(current_user, :admin_group_member, group).to_s } end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb index 29ead76a607..e8eb6a5d417 100644 --- a/app/helpers/groups_helper.rb +++ b/app/helpers/groups_helper.rb @@ -21,7 +21,6 @@ module GroupsHelper integrations#edit ldap_group_links#index hooks#index - audit_events#index pipeline_quota#index ] end @@ -189,6 +188,10 @@ module GroupsHelper params.key?(:purchased_quantity) && params[:purchased_quantity].to_i > 0 end + def project_list_sort_by + @group_projects_sort || @sort || params[:sort] || sort_value_recently_created + end + private def just_created? diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb index dc6164ee898..096a3f2269b 100644 --- a/app/helpers/icons_helper.rb +++ b/app/helpers/icons_helper.rb @@ -4,25 +4,9 @@ require 'json' module IconsHelper extend self - include FontAwesome::Rails::IconHelper DEFAULT_ICON_SIZE = 16 - # Creates an icon tag given icon name(s) and possible icon modifiers. - # - # Right now this method simply delegates directly to `fa_icon` from the - # font-awesome-rails gem, but should we ever use a different icon pack in the - # future we won't have to change hundreds of method calls. - def icon(names, options = {}) - if (options.keys & %w[aria-hidden aria-label data-hidden]).empty? - # Add 'aria-hidden' and 'data-hidden' if they are not set in options. - options['aria-hidden'] = true - options['data-hidden'] = true - end - - options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options) - end - def custom_icon(icon_name, size: DEFAULT_ICON_SIZE) memoized_icon("#{icon_name}_#{size}") do # We can't simply do the below, because there are some .erb SVGs. @@ -95,9 +79,9 @@ module IconsHelper def boolean_to_icon(value) if value - sprite_icon('check', css_class: 'cgreen') + sprite_icon('check', css_class: 'gl-text-green-500') else - sprite_icon('power', css_class: 'clgray') + sprite_icon('power', css_class: 'gl-text-gray-500') end end diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb index 77ced17bc22..15842dec3dd 100644 --- a/app/helpers/issuables_helper.rb +++ b/app/helpers/issuables_helper.rb @@ -61,16 +61,6 @@ module IssuablesHelper end end - def issuable_json_path(issuable) - project = issuable.project - - if issuable.is_a?(MergeRequest) - project_merge_request_path(project, issuable.iid, :json) - else - project_issue_path(project, issuable.iid, :json) - end - end - def serialize_issuable(issuable, opts = {}) serializer_klass = case issuable when Issue @@ -174,30 +164,26 @@ module IssuablesHelper h(title || default_label) end - def to_url_reference(issuable) - case issuable - when Issue - link_to issuable.to_reference, issue_url(issuable) - when MergeRequest - link_to issuable.to_reference, merge_request_url(issuable) - else - issuable.to_reference - end + def issuable_meta_author_status(author) + return "" unless show_status_emoji?(author&.status) && status = user_status(author) + + "#{status}".html_safe end - def issuable_meta(issuable, project, text) + def issuable_meta(issuable, project) output = [] output << "Opened #{time_ago_with_tooltip(issuable.created_at)} by ".html_safe + if issuable.is_a?(Issue) && issuable.service_desk_reply_to + output << "#{html_escape(issuable.service_desk_reply_to)} via " + end + output << content_tag(:strong) do author_output = link_to_member(project, issuable.author, size: 24, mobile_classes: "d-none d-sm-inline") author_output << link_to_member(project, issuable.author, size: 24, by_username: true, avatar: false, mobile_classes: "d-inline d-sm-none") author_output << issuable_meta_author_slot(issuable.author, css_class: 'ml-1') - - if status = user_status(issuable.author) - author_output << "#{status}".html_safe - end + author_output << issuable_meta_author_status(issuable.author) author_output end @@ -336,42 +322,10 @@ module IssuablesHelper issuable_path(issuable, close_reopen_params(issuable, :reopen)) end - def close_reopen_issuable_path(issuable, should_inverse = false) - issuable.closed? ^ should_inverse ? reopen_issuable_path(issuable) : close_issuable_path(issuable) - end - - def toggle_draft_issuable_path(issuable) - wip_event = issuable.work_in_progress? ? 'unwip' : 'wip' - - issuable_path(issuable, { merge_request: { wip_event: wip_event } }) - end - def issuable_path(issuable, *options) polymorphic_path(issuable, *options) end - def issuable_url(issuable, *options) - case issuable - when Issue - issue_url(issuable, *options) - when MergeRequest - merge_request_url(issuable, *options) - end - end - - def issuable_button_visibility(issuable, closed) - return 'hidden' if issuable_button_hidden?(issuable, closed) - end - - def issuable_button_hidden?(issuable, closed) - case issuable - when Issue - issue_button_hidden?(issuable, closed) - when MergeRequest - merge_request_button_hidden?(issuable, closed) - end - end - def issuable_author_is_current_user(issuable) issuable.author == current_user end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index dee009cd3ab..0a9965496b8 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -32,14 +32,6 @@ module IssuesHelper end end - def issue_button_visibility(issue, closed) - return 'hidden' if issue_button_hidden?(issue, closed) - end - - def issue_button_hidden?(issue, closed) - issue.closed? == closed || (!closed && issue.discussion_locked) - end - def confidential_icon(issue) sprite_icon('eye-slash', css_class: 'gl-vertical-align-text-bottom') if issue.confidential? end diff --git a/app/helpers/markup_helper.rb b/app/helpers/markup_helper.rb index ed8931fe0f2..25d56ffca2c 100644 --- a/app/helpers/markup_helper.rb +++ b/app/helpers/markup_helper.rb @@ -126,16 +126,7 @@ module MarkupHelper text = wiki_page.content return '' unless text.present? - context.merge!( - pipeline: :wiki, - project: @project, - wiki: @wiki, - repository: @wiki.repository, - page_slug: wiki_page.slug, - issuable_state_filter_enabled: true - ) - - html = markup_unsafe(wiki_page.path, text, context) + html = markup_unsafe(wiki_page.path, text, render_wiki_content_context(@wiki, wiki_page, context)) prepare_for_rendering(html, context) end @@ -182,6 +173,20 @@ module MarkupHelper private + def render_wiki_content_context(wiki, wiki_page, context) + context.merge( + pipeline: :wiki, + wiki: wiki, + repository: wiki.repository, + page_slug: wiki_page.slug, + issuable_state_filter_enabled: true + ).merge(render_wiki_content_context_container(wiki)) + end + + def render_wiki_content_context_container(wiki) + { project: wiki.container } + end + # Return +text+, truncated to +max_chars+ characters, excluding any HTML # tags. def truncate_visible(text, max_chars) @@ -311,3 +316,5 @@ module MarkupHelper extend self end + +MarkupHelper.prepend_if_ee('EE::MarkupHelper') diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 9cb7edbaeb6..37e701c1c2b 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -39,19 +39,6 @@ module MergeRequestsHelper end end - def ci_build_details_path(merge_request) - build_url = merge_request.source_project.ci_service.build_page(merge_request.diff_head_sha, merge_request.source_branch) - return unless build_url - - parsed_url = URI.parse(build_url) - - unless parsed_url.userinfo.blank? - parsed_url.userinfo = '' - end - - parsed_url.to_s - end - def merge_path_description(merge_request, separator) if merge_request.for_fork? "Project:Branches: #{@merge_request.source_project_path}:#{@merge_request.source_branch} #{separator} #{@merge_request.target_project.full_path}:#{@merge_request.target_branch}" @@ -96,7 +83,7 @@ module MergeRequestsHelper end def merge_request_button_hidden?(merge_request, closed) - merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_without_fork? + merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_or_merged_without_fork? end def merge_request_version_path(project, merge_request, merge_request_diff, start_sha = nil) @@ -166,6 +153,12 @@ module MergeRequestsHelper current_user.fork_of(project) end end + + def toggle_draft_merge_request_path(issuable) + wip_event = issuable.work_in_progress? ? 'unwip' : 'wip' + + issuable_path(issuable, { merge_request: { wip_event: wip_event } }) + end end MergeRequestsHelper.prepend_if_ee('EE::MergeRequestsHelper') diff --git a/app/helpers/notifications_helper.rb b/app/helpers/notifications_helper.rb index 61fcda6a504..2b68d953431 100644 --- a/app/helpers/notifications_helper.rb +++ b/app/helpers/notifications_helper.rb @@ -106,7 +106,8 @@ module NotificationsHelper when :success_pipeline s_('NotificationEvent|Successful pipeline') else - s_(event.to_s.humanize) + event_name = "NotificationEvent|#{event.to_s.humanize}" + s_(event_name) end end diff --git a/app/helpers/notify_helper.rb b/app/helpers/notify_helper.rb index fb68029928c..db7527d9d58 100644 --- a/app/helpers/notify_helper.rb +++ b/app/helpers/notify_helper.rb @@ -5,7 +5,7 @@ module NotifyHelper link_to(entity.to_reference, merge_request_url(entity, *args)) end - def issue_reference_link(entity, *args) - link_to(entity.to_reference, issue_url(entity, *args)) + def issue_reference_link(entity, *args, full: false) + link_to(entity.to_reference(full: full), issue_url(entity, *args)) end end diff --git a/app/helpers/operations_helper.rb b/app/helpers/operations_helper.rb index 8105fce10cf..6d721776f0d 100644 --- a/app/helpers/operations_helper.rb +++ b/app/helpers/operations_helper.rb @@ -9,24 +9,14 @@ module OperationsHelper end end - def alerts_service - strong_memoize(:alerts_service) do - @project.find_or_initialize_service(::AlertsService.to_param) - end - end - def alerts_settings_data(disabled: false) { 'prometheus_activated' => prometheus_service.manual_configuration?.to_s, - 'activated' => alerts_service.activated?.to_s, 'prometheus_form_path' => scoped_integration_path(prometheus_service), - 'form_path' => scoped_integration_path(alerts_service), 'prometheus_reset_key_path' => reset_alerting_token_project_settings_operations_path(@project), 'prometheus_authorization_key' => @project.alerting_setting&.token, 'prometheus_api_url' => prometheus_service.api_url, - 'authorization_key' => alerts_service.token, 'prometheus_url' => notify_project_prometheus_alerts_url(@project, format: :json), - 'url' => alerts_service.url, 'alerts_setup_url' => help_page_path('operations/incident_management/alert_integrations.md', anchor: 'generic-http-endpoint'), 'alerts_usage_url' => project_alert_management_index_path(@project), 'disabled' => disabled.to_s, diff --git a/app/helpers/profiles_helper.rb b/app/helpers/profiles_helper.rb index 04a3b915493..87187e97df4 100644 --- a/app/helpers/profiles_helper.rb +++ b/app/helpers/profiles_helper.rb @@ -37,10 +37,4 @@ module ProfilesHelper def user_status_set_to_busy?(status) status&.availability == availability_values[:busy] end - - def show_status_emoji?(status) - return false unless status - - status.message.present? || status.emoji != UserStatus::DEFAULT_EMOJI - end end diff --git a/app/helpers/projects/alert_management_helper.rb b/app/helpers/projects/alert_management_helper.rb index c6ad6bfac01..997551d9659 100644 --- a/app/helpers/projects/alert_management_helper.rb +++ b/app/helpers/projects/alert_management_helper.rb @@ -28,7 +28,7 @@ module Projects::AlertManagementHelper def alert_management_enabled?(project) !!( - project.alerts_service_activated? || + project.alert_management_alerts.any? || project.prometheus_service_active? || AlertManagement::HttpIntegrationsFinder.new(project, active: true).execute.any? ) diff --git a/app/helpers/projects/terraform_helper.rb b/app/helpers/projects/terraform_helper.rb index b286bc4d7a5..621d97ffb69 100644 --- a/app/helpers/projects/terraform_helper.rb +++ b/app/helpers/projects/terraform_helper.rb @@ -1,10 +1,11 @@ # frozen_string_literal: true module Projects::TerraformHelper - def js_terraform_list_data(project) + def js_terraform_list_data(current_user, project) { empty_state_image: image_path('illustrations/empty-state/empty-serverless-lg.svg'), - project_path: project.full_path + project_path: project.full_path, + terraform_admin: current_user&.can?(:admin_terraform_state, project) } end end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index f25b229d198..80206654cd1 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -463,11 +463,12 @@ module ProjectsHelper issues: :read_issue, project_members: :read_project_member, wiki: :read_wiki, - feature_flags: :read_feature_flag + feature_flags: :read_feature_flag, + analytics: :read_analytics } end - def can_view_operations_tab?(current_user, project) + def view_operations_tab_ability [ :metrics_dashboard, :read_alert_management_alert, @@ -477,7 +478,13 @@ module ProjectsHelper :read_cluster, :read_feature_flag, :read_terraform_state - ].any? do |ability| + ] + end + + def can_view_operations_tab?(current_user, project) + return false unless project.feature_available?(:operations, current_user) + + view_operations_tab_ability.any? do |ability| can?(current_user, ability, project) end end @@ -606,6 +613,7 @@ module ProjectsHelper def project_permissions_settings(project) feature = project.project_feature + { packagesEnabled: !!project.packages_enabled, visibilityLevel: project.visibility_level, @@ -618,11 +626,14 @@ module ProjectsHelper 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, - showDefaultAwardEmojis: project.show_default_award_emojis? + operationsAccessLevel: feature.operations_access_level, + showDefaultAwardEmojis: project.show_default_award_emojis?, + allowEditingCommitMessages: project.allow_editing_commit_messages? } end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index de1e0e4e05e..bdc86043ddc 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -31,7 +31,7 @@ module SearchHelper [ resources_results, generic_results - ].flatten.uniq do |item| + ].flatten do |item| item[:label] end end @@ -370,7 +370,7 @@ module SearchHelper def highlight_and_truncate_issuable(issuable, search_term, _search_highlight) return unless issuable.description.present? - simple_search_highlight_and_truncate(issuable.description, search_term, highlighter: '<span class="gl-text-black-normal gl-font-weight-bold">\1</span>') + simple_search_highlight_and_truncate(issuable.description, search_term, highlighter: '<span class="gl-text-gray-900 gl-font-weight-bold">\1</span>') end def show_user_search_tab? diff --git a/app/helpers/services_helper.rb b/app/helpers/services_helper.rb index 96eb14be4b4..3516000e296 100644 --- a/app/helpers/services_helper.rb +++ b/app/helpers/services_helper.rb @@ -75,7 +75,15 @@ module ServicesHelper end end - def integration_form_data(integration) + def scoped_reset_integration_path(integration, group: nil) + if group.present? + reset_group_settings_integration_path(group, integration) + else + reset_admin_application_settings_integration_path(integration) + end + end + + def integration_form_data(integration, group: nil) { id: integration.id, show_active: integration.show_active_box?.to_s, @@ -94,7 +102,7 @@ module ServicesHelper cancel_path: scoped_integrations_path, can_test: integration.can_test?.to_s, test_path: scoped_test_integration_path(integration), - reset_path: '' + reset_path: reset_integration?(integration, group: group) ? scoped_reset_integration_path(integration, group: group) : '' } end @@ -114,14 +122,14 @@ module ServicesHelper false end - def group_level_integrations? - @group.present? && Feature.enabled?(:group_level_integrations, @group, default_enabled: true) - end - def instance_level_integrations? !Gitlab.com? end + def reset_integration?(integration, group: nil) + integration.persisted? && Feature.enabled?(:reset_integrations, group, type: :development) + end + extend self private diff --git a/app/helpers/sorting_helper.rb b/app/helpers/sorting_helper.rb index 10174e5d719..38758957dba 100644 --- a/app/helpers/sorting_helper.rb +++ b/app/helpers/sorting_helper.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module SortingHelper + include SortingTitlesValuesHelper + def sort_options_hash { sort_value_created_date => sort_title_created_date, @@ -40,6 +42,7 @@ module SortingHelper sort_value_latest_activity => sort_title_latest_activity, sort_value_recently_created => sort_title_created_date, sort_value_name => sort_title_name, + sort_value_name_desc => sort_title_name_desc, sort_value_stars_desc => sort_title_stars } @@ -95,8 +98,8 @@ module SortingHelper sort_value_name_desc => sort_title_name_desc, sort_value_recently_created => sort_title_recently_created, sort_value_oldest_created => sort_title_oldest_created, - sort_value_recently_updated => sort_title_recently_updated, - sort_value_oldest_updated => sort_title_oldest_updated + sort_value_latest_activity => sort_title_recently_updated, + sort_value_oldest_activity => sort_title_oldest_updated } end @@ -112,19 +115,6 @@ module SortingHelper ) end - def member_sort_options_hash - { - sort_value_access_level_asc => sort_title_access_level_asc, - sort_value_access_level_desc => sort_title_access_level_desc, - sort_value_last_joined => sort_title_last_joined, - sort_value_name => sort_title_name_asc, - sort_value_name_desc => sort_title_name_desc, - sort_value_oldest_joined => sort_title_oldest_joined, - sort_value_oldest_signin => sort_title_oldest_signin, - sort_value_recently_signin => sort_title_recently_signin - } - end - def milestone_sort_options_hash { sort_value_name => sort_title_name_asc, @@ -186,6 +176,19 @@ module SortingHelper } end + def member_sort_options_hash + { + sort_value_access_level_asc => sort_title_access_level_asc, + sort_value_access_level_desc => sort_title_access_level_desc, + sort_value_last_joined => sort_title_last_joined, + sort_value_name => sort_title_name_asc, + sort_value_name_desc => sort_title_name_desc, + sort_value_oldest_joined => sort_title_oldest_joined, + sort_value_oldest_signin => sort_title_oldest_signin, + sort_value_recently_signin => sort_title_recently_signin + } + end + def sortable_item(item, path, sorted_by) link_to item, path, class: sorted_by == item ? 'is-active' : '' end @@ -275,340 +278,6 @@ module SortingHelper sort_direction_button(url, reverse_sort, sort_value) end - # Titles. - def sort_title_access_level_asc - s_('SortOptions|Access level, ascending') - end - - def sort_title_access_level_desc - s_('SortOptions|Access level, descending') - end - - def sort_title_created_date - s_('SortOptions|Created date') - end - - def sort_title_downvotes - s_('SortOptions|Least popular') - end - - def sort_title_due_date - s_('SortOptions|Due date') - end - - def sort_title_due_date_later - s_('SortOptions|Due later') - end - - def sort_title_due_date_soon - s_('SortOptions|Due soon') - end - - def sort_title_label_priority - s_('SortOptions|Label priority') - end - - def sort_title_largest_group - s_('SortOptions|Largest group') - end - - def sort_title_largest_repo - s_('SortOptions|Largest repository') - end - - def sort_title_last_joined - s_('SortOptions|Last joined') - end - - def sort_title_latest_activity - s_('SortOptions|Last updated') - end - - def sort_title_milestone - s_('SortOptions|Milestone due date') - end - - def sort_title_milestone_later - s_('SortOptions|Milestone due later') - end - - def sort_title_milestone_soon - s_('SortOptions|Milestone due soon') - end - - def sort_title_name - s_('SortOptions|Name') - end - - def sort_title_name_asc - s_('SortOptions|Name, ascending') - end - - def sort_title_name_desc - s_('SortOptions|Name, descending') - end - - def sort_title_oldest_activity - s_('SortOptions|Oldest updated') - end - - def sort_title_oldest_created - s_('SortOptions|Oldest created') - end - - def sort_title_oldest_joined - s_('SortOptions|Oldest joined') - end - - def sort_title_oldest_signin - s_('SortOptions|Oldest sign in') - end - - def sort_title_oldest_starred - s_('SortOptions|Oldest starred') - end - - def sort_title_oldest_updated - s_('SortOptions|Oldest updated') - end - - def sort_title_popularity - s_('SortOptions|Popularity') - end - - def sort_title_priority - s_('SortOptions|Priority') - end - - def sort_title_recently_created - s_('SortOptions|Last created') - end - - def sort_title_recently_signin - s_('SortOptions|Recent sign in') - end - - def sort_title_recently_starred - s_('SortOptions|Recently starred') - end - - def sort_title_recently_updated - s_('SortOptions|Last updated') - end - - def sort_title_start_date_later - s_('SortOptions|Start later') - end - - def sort_title_start_date_soon - s_('SortOptions|Start soon') - end - - def sort_title_upvotes - s_('SortOptions|Most popular') - end - - def sort_title_contacted_date - s_('SortOptions|Last Contact') - end - - def sort_title_most_stars - s_('SortOptions|Most stars') - end - - def sort_title_stars - s_('SortOptions|Stars') - end - - def sort_title_oldest_last_activity - s_('SortOptions|Oldest last activity') - end - - def sort_title_recently_last_activity - s_('SortOptions|Recent last activity') - end - - def sort_title_relative_position - s_('SortOptions|Manual') - end - - def sort_title_size - s_('SortOptions|Size') - end - - def sort_title_expire_date - s_('SortOptions|Expired date') - end - - def sort_title_relevant - s_('SortOptions|Relevant') - end - - # Values. - def sort_value_access_level_asc - 'access_level_asc' - end - - def sort_value_access_level_desc - 'access_level_desc' - end - - def sort_value_created_date - 'created_date' - end - - def sort_value_downvotes - 'downvotes_desc' - end - - def sort_value_due_date - 'due_date' - end - - def sort_value_due_date_later - 'due_date_desc' - end - - def sort_value_due_date_soon - 'due_date_asc' - end - - def sort_value_label_priority - 'label_priority' - end - - def sort_value_largest_group - 'storage_size_desc' - end - - def sort_value_largest_repo - 'storage_size_desc' - end - - def sort_value_last_joined - 'last_joined' - end - - def sort_value_latest_activity - 'latest_activity_desc' - end - - def sort_value_milestone - 'milestone' - end - - def sort_value_milestone_later - 'milestone_due_desc' - end - - def sort_value_milestone_soon - 'milestone_due_asc' - end - - def sort_value_name - 'name_asc' - end - - def sort_value_name_desc - 'name_desc' - end - - def sort_value_oldest_activity - 'latest_activity_asc' - end - - def sort_value_oldest_created - 'created_asc' - end - - def sort_value_oldest_signin - 'oldest_sign_in' - end - - def sort_value_oldest_joined - 'oldest_joined' - end - - def sort_value_oldest_updated - 'updated_asc' - end - - def sort_value_popularity - 'popularity' - end - - def sort_value_most_popular - 'popularity_desc' - end - - def sort_value_least_popular - 'popularity_asc' - end - - def sort_value_priority - 'priority' - end - - def sort_value_recently_created - 'created_desc' - end - - def sort_value_recently_signin - 'recent_sign_in' - end - - def sort_value_recently_updated - 'updated_desc' - end - - def sort_value_start_date_later - 'start_date_desc' - end - - def sort_value_start_date_soon - 'start_date_asc' - end - - def sort_value_upvotes - 'upvotes_desc' - end - - def sort_value_contacted_date - 'contacted_asc' - end - - def sort_value_stars_desc - 'stars_desc' - end - - def sort_value_stars_asc - 'stars_asc' - end - - def sort_value_oldest_last_activity - 'last_activity_on_asc' - end - - def sort_value_recently_last_activity - 'last_activity_on_desc' - end - - def sort_value_relative_position - 'relative_position' - end - - def sort_value_size - 'size_desc' - end - - def sort_value_expire_date - 'expired_asc' - end - - def sort_value_relevant - 'relevant' - end - def packages_sort_options_hash { sort_value_recently_created => sort_title_created_date, diff --git a/app/helpers/sorting_titles_values_helper.rb b/app/helpers/sorting_titles_values_helper.rb new file mode 100644 index 00000000000..27f3638dc73 --- /dev/null +++ b/app/helpers/sorting_titles_values_helper.rb @@ -0,0 +1,339 @@ +# frozen_string_literal: true + +module SortingTitlesValuesHelper + # Titles. + def sort_title_access_level_asc + s_('SortOptions|Access level, ascending') + end + + def sort_title_access_level_desc + s_('SortOptions|Access level, descending') + end + + def sort_title_created_date + s_('SortOptions|Created date') + end + + def sort_title_downvotes + s_('SortOptions|Least popular') + end + + def sort_title_due_date + s_('SortOptions|Due date') + end + + def sort_title_due_date_later + s_('SortOptions|Due later') + end + + def sort_title_due_date_soon + s_('SortOptions|Due soon') + end + + def sort_title_label_priority + s_('SortOptions|Label priority') + end + + def sort_title_largest_group + s_('SortOptions|Largest group') + end + + def sort_title_largest_repo + s_('SortOptions|Largest repository') + end + + def sort_title_last_joined + s_('SortOptions|Last joined') + end + + def sort_title_latest_activity + s_('SortOptions|Last updated') + end + + def sort_title_milestone + s_('SortOptions|Milestone due date') + end + + def sort_title_milestone_later + s_('SortOptions|Milestone due later') + end + + def sort_title_milestone_soon + s_('SortOptions|Milestone due soon') + end + + def sort_title_name + s_('SortOptions|Name') + end + + def sort_title_name_asc + s_('SortOptions|Name, ascending') + end + + def sort_title_name_desc + s_('SortOptions|Name, descending') + end + + def sort_title_oldest_activity + s_('SortOptions|Oldest updated') + end + + def sort_title_oldest_created + s_('SortOptions|Oldest created') + end + + def sort_title_oldest_joined + s_('SortOptions|Oldest joined') + end + + def sort_title_oldest_signin + s_('SortOptions|Oldest sign in') + end + + def sort_title_oldest_starred + s_('SortOptions|Oldest starred') + end + + def sort_title_oldest_updated + s_('SortOptions|Oldest updated') + end + + def sort_title_popularity + s_('SortOptions|Popularity') + end + + def sort_title_priority + s_('SortOptions|Priority') + end + + def sort_title_recently_created + s_('SortOptions|Last created') + end + + def sort_title_recently_signin + s_('SortOptions|Recent sign in') + end + + def sort_title_recently_starred + s_('SortOptions|Recently starred') + end + + def sort_title_recently_updated + s_('SortOptions|Last updated') + end + + def sort_title_start_date_later + s_('SortOptions|Start later') + end + + def sort_title_start_date_soon + s_('SortOptions|Start soon') + end + + def sort_title_upvotes + s_('SortOptions|Most popular') + end + + def sort_title_contacted_date + s_('SortOptions|Last Contact') + end + + def sort_title_most_stars + s_('SortOptions|Most stars') + end + + def sort_title_stars + s_('SortOptions|Stars') + end + + def sort_title_oldest_last_activity + s_('SortOptions|Oldest last activity') + end + + def sort_title_recently_last_activity + s_('SortOptions|Recent last activity') + end + + def sort_title_relative_position + s_('SortOptions|Manual') + end + + def sort_title_size + s_('SortOptions|Size') + end + + def sort_title_expire_date + s_('SortOptions|Expired date') + end + + def sort_title_relevant + s_('SortOptions|Relevant') + end + + # Values. + def sort_value_access_level_asc + 'access_level_asc' + end + + def sort_value_access_level_desc + 'access_level_desc' + end + + def sort_value_created_date + 'created_date' + end + + def sort_value_downvotes + 'downvotes_desc' + end + + def sort_value_due_date + 'due_date' + end + + def sort_value_due_date_later + 'due_date_desc' + end + + def sort_value_due_date_soon + 'due_date_asc' + end + + def sort_value_label_priority + 'label_priority' + end + + def sort_value_largest_group + 'storage_size_desc' + end + + def sort_value_largest_repo + 'storage_size_desc' + end + + def sort_value_last_joined + 'last_joined' + end + + def sort_value_latest_activity + 'latest_activity_desc' + end + + def sort_value_milestone + 'milestone' + end + + def sort_value_milestone_later + 'milestone_due_desc' + end + + def sort_value_milestone_soon + 'milestone_due_asc' + end + + def sort_value_name + 'name_asc' + end + + def sort_value_name_desc + 'name_desc' + end + + def sort_value_oldest_activity + 'latest_activity_asc' + end + + def sort_value_oldest_created + 'created_asc' + end + + def sort_value_oldest_signin + 'oldest_sign_in' + end + + def sort_value_oldest_joined + 'oldest_joined' + end + + def sort_value_oldest_updated + 'updated_asc' + end + + def sort_value_popularity + 'popularity' + end + + def sort_value_most_popular + 'popularity_desc' + end + + def sort_value_least_popular + 'popularity_asc' + end + + def sort_value_priority + 'priority' + end + + def sort_value_recently_created + 'created_desc' + end + + def sort_value_recently_signin + 'recent_sign_in' + end + + def sort_value_recently_updated + 'updated_desc' + end + + def sort_value_start_date_later + 'start_date_desc' + end + + def sort_value_start_date_soon + 'start_date_asc' + end + + def sort_value_upvotes + 'upvotes_desc' + end + + def sort_value_contacted_date + 'contacted_asc' + end + + def sort_value_stars_desc + 'stars_desc' + end + + def sort_value_stars_asc + 'stars_asc' + end + + def sort_value_oldest_last_activity + 'last_activity_on_asc' + end + + def sort_value_recently_last_activity + 'last_activity_on_desc' + end + + def sort_value_relative_position + 'relative_position' + end + + def sort_value_size + 'size_desc' + end + + def sort_value_expire_date + 'expired_asc' + end + + def sort_value_relevant + 'relevant' + end +end + +SortingHelper.include_if_ee('::EE::SortingTitlesValuesHelper') diff --git a/app/helpers/storage_helper.rb b/app/helpers/storage_helper.rb index 13bf9c92d52..d6a4d6ac57a 100644 --- a/app/helpers/storage_helper.rb +++ b/app/helpers/storage_helper.rb @@ -15,9 +15,11 @@ module StorageHelper counter_wikis: storage_counter(statistics.wiki_size), counter_build_artifacts: storage_counter(statistics.build_artifacts_size), counter_lfs_objects: storage_counter(statistics.lfs_objects_size), - counter_snippets: storage_counter(statistics.snippets_size) + counter_snippets: storage_counter(statistics.snippets_size), + counter_packages: storage_counter(statistics.packages_size), + counter_uploads: storage_counter(statistics.uploads_size) } - _("Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets}") % counters + _("Repository: %{counter_repositories} / Wikis: %{counter_wikis} / Build Artifacts: %{counter_build_artifacts} / LFS: %{counter_lfs_objects} / Snippets: %{counter_snippets} / Packages: %{counter_packages} / Uploads: %{counter_uploads}") % counters end end diff --git a/app/helpers/suggest_pipeline_helper.rb b/app/helpers/suggest_pipeline_helper.rb index 3151b792344..f0a12f0e268 100644 --- a/app/helpers/suggest_pipeline_helper.rb +++ b/app/helpers/suggest_pipeline_helper.rb @@ -2,8 +2,6 @@ module SuggestPipelineHelper def should_suggest_gitlab_ci_yml? - Feature.enabled?(:suggest_pipeline, default_enabled: true) && - current_user && - params[:suggest_gitlab_ci_yml] == 'true' + current_user && params[:suggest_gitlab_ci_yml] == 'true' end end diff --git a/app/helpers/system_note_helper.rb b/app/helpers/system_note_helper.rb index 79f4810e13a..85e644967ea 100644 --- a/app/helpers/system_note_helper.rb +++ b/app/helpers/system_note_helper.rb @@ -38,7 +38,8 @@ module SystemNoteHelper 'status' => 'status', 'alert_issue_added' => 'issues', 'new_alert_added' => 'warning', - 'severity' => 'information-o' + 'severity' => 'information-o', + 'cloned' => 'documents' }.freeze def system_note_icon_name(note) diff --git a/app/helpers/time_zone_helper.rb b/app/helpers/time_zone_helper.rb new file mode 100644 index 00000000000..00f65b72c8e --- /dev/null +++ b/app/helpers/time_zone_helper.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +module TimeZoneHelper + TIME_ZONE_FORMAT_ATTRS = { + short: %i[identifier name offset], + full: %i[identifier name abbr offset formatted_offset] + }.freeze + private_constant :TIME_ZONE_FORMAT_ATTRS + + # format: + # * :full - all available fields + # * :short (default) + # + # Example: + # timezone_data # :short by default + # timezone_data(format: :full) + # + def timezone_data(format: :short) + attrs = TIME_ZONE_FORMAT_ATTRS.fetch(format) do + valid_formats = TIME_ZONE_FORMAT_ATTRS.keys.map { |k| ":#{k}"}.join(", ") + raise ArgumentError.new("Invalid format :#{format}. Valid formats are #{valid_formats}.") + end + + ActiveSupport::TimeZone.all.map do |timezone| + { + identifier: timezone.tzinfo.identifier, + name: timezone.name, + abbr: timezone.tzinfo.strftime('%Z'), + offset: timezone.now.utc_offset, + formatted_offset: timezone.now.formatted_offset + }.slice(*attrs) + end + end +end diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index 692971f4627..f24aa5d3bcb 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -228,12 +228,12 @@ module TreeHelper gitpod_enabled: !current_user.nil? && current_user.gitpod_enabled, is_blob: !options[:blob].nil?, - show_edit_button: show_edit_button?, + show_edit_button: show_edit_button?(options), show_web_ide_button: show_web_ide_button?, show_gitpod_button: show_gitpod_button?, web_ide_url: web_ide_url, - edit_url: edit_url, + edit_url: edit_url(options), gitpod_url: gitpod_url } end diff --git a/app/helpers/user_callouts_helper.rb b/app/helpers/user_callouts_helper.rb index e93c1b82cd7..a06a31ddf32 100644 --- a/app/helpers/user_callouts_helper.rb +++ b/app/helpers/user_callouts_helper.rb @@ -57,7 +57,10 @@ module UserCalloutsHelper end def show_registration_enabled_user_callout? - current_user&.admin? && signup_enabled? && !user_dismissed?(REGISTRATION_ENABLED_CALLOUT) + !Gitlab.com? && + current_user&.admin? && + signup_enabled? && + !user_dismissed?(REGISTRATION_ENABLED_CALLOUT) end private diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 7d4ab192f2f..a58f8a6f792 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -1,6 +1,13 @@ # frozen_string_literal: true module UsersHelper + def admin_users_data_attributes(users) + { + users: Admin::UserSerializer.new.represent(users).to_json, + paths: admin_users_paths.to_json + } + end + def user_link(user) link_to(user.name, user_path(user), title: user.email, @@ -60,6 +67,12 @@ module UsersHelper "access:#{max_project_member_access(project)}" end + def show_status_emoji?(status) + return false unless status + + status.message.present? || status.emoji != UserStatus::DEFAULT_EMOJI + end + def user_status(user) return unless user @@ -123,6 +136,19 @@ module UsersHelper } end + def user_unblock_data(user) + { + path: unblock_admin_user_path(user), + method: 'put', + modal_attributes: { + title: s_('AdminUsers|Unblock user %{username}?') % { username: sanitize_name(user.name) }, + message: s_('AdminUsers|You can always block their account again if needed.'), + okVariant: 'info', + okTitle: s_('AdminUsers|Unblock') + }.to_json + } + end + def user_block_effects header = tag.p s_('AdminUsers|Blocking user has the following effects:') @@ -136,8 +162,75 @@ module UsersHelper header + list end + def user_deactivation_data(user, message) + { + path: deactivate_admin_user_path(user), + method: 'put', + modal_attributes: { + title: s_('AdminUsers|Deactivate user %{username}?') % { username: sanitize_name(user.name) }, + messageHtml: message, + okVariant: 'warning', + okTitle: s_('AdminUsers|Deactivate') + }.to_json + } + end + + def user_activation_data(user) + { + path: activate_admin_user_path(user), + method: 'put', + modal_attributes: { + title: s_('AdminUsers|Activate user %{username}?') % { username: sanitize_name(user.name) }, + message: s_('AdminUsers|You can always deactivate their account again if needed.'), + okVariant: 'info', + okTitle: s_('AdminUsers|Activate') + }.to_json + } + end + + def user_deactivation_effects + header = tag.p s_('AdminUsers|Deactivating a user has the following effects:') + + list = tag.ul do + concat tag.li s_('AdminUsers|The user will be logged out') + concat tag.li s_('AdminUsers|The user will not be able to access git repositories') + concat tag.li s_('AdminUsers|The user will not be able to access the API') + concat tag.li s_('AdminUsers|The user will not receive any notifications') + concat tag.li s_('AdminUsers|The user will not be able to use slash commands') + concat tag.li s_('AdminUsers|When the user logs back in, their account will reactivate as a fully active account') + concat tag.li s_('AdminUsers|Personal projects, group and user history will be left intact') + end + + header + list + end + + def user_display_name(user) + return s_('UserProfile|Blocked user') if user.blocked? + + can_read_profile = can?(current_user, :read_user_profile, user) + return s_('UserProfile|Unconfirmed user') unless user.confirmed? || can_read_profile + + user.name + end + private + def admin_users_paths + { + edit: edit_admin_user_path(:id), + approve: approve_admin_user_path(:id), + reject: reject_admin_user_path(:id), + unblock: unblock_admin_user_path(:id), + block: block_admin_user_path(:id), + deactivate: deactivate_admin_user_path(:id), + activate: activate_admin_user_path(:id), + unlock: unlock_admin_user_path(:id), + delete: admin_user_path(:id), + delete_with_contributions: admin_user_path(:id), + admin_user: admin_user_path(:id) + } + end + def blocked_user_badge(user) pending_approval_badge = { text: s_('AdminUsers|Pending approval'), variant: 'info' } return pending_approval_badge if user.blocked_pending_approval? diff --git a/app/helpers/visibility_level_helper.rb b/app/helpers/visibility_level_helper.rb index 896dcdd2caf..0a37257e124 100644 --- a/app/helpers/visibility_level_helper.rb +++ b/app/helpers/visibility_level_helper.rb @@ -157,6 +157,16 @@ module VisibilityLevelHelper end end + def visibility_level_options(form_model) + available_visibility_levels(form_model).map do |level| + { + level: level, + label: visibility_level_label(level), + description: visibility_level_description(level, form_model) + } + end + end + def snippets_selected_visibility_level(visibility_levels, selected) visibility_levels.find { |level| level == selected } || visibility_levels.min end diff --git a/app/helpers/web_ide_button_helper.rb b/app/helpers/web_ide_button_helper.rb index 0a4d47eed52..7aa0adc31bd 100644 --- a/app/helpers/web_ide_button_helper.rb +++ b/app/helpers/web_ide_button_helper.rb @@ -21,8 +21,8 @@ module WebIdeButtonHelper can_collaborate? || can_create_mr_from_fork? end - def show_edit_button? - readable_blob? && show_web_ide_button? + def show_edit_button?(options = {}) + readable_blob?(options) && show_web_ide_button? end def show_gitpod_button? @@ -37,8 +37,8 @@ module WebIdeButtonHelper !project_fork.nil? && !can_push_code? end - def readable_blob? - !readable_blob({}, @path, @project, @ref).nil? + def readable_blob?(options = {}) + !readable_blob(options, @path, @project, @ref).nil? end def needs_to_fork? @@ -49,8 +49,8 @@ module WebIdeButtonHelper ide_edit_path(project_to_use, @ref, @path || '') end - def edit_url - readable_blob? ? edit_blob_path(@project, @ref, @path || '') : '' + def edit_url(options = {}) + readable_blob?(options) ? edit_blob_path(@project, @ref, @path || '') : '' end def gitpod_url diff --git a/app/helpers/whats_new_helper.rb b/app/helpers/whats_new_helper.rb index 283d443f51b..bbf5bde5904 100644 --- a/app/helpers/whats_new_helper.rb +++ b/app/helpers/whats_new_helper.rb @@ -1,25 +1,19 @@ # frozen_string_literal: true module WhatsNewHelper - include Gitlab::WhatsNew - def whats_new_most_recent_release_items_count - Gitlab::ProcessMemoryCache.cache_backend.fetch('whats_new:release_items_count', expires_in: CACHE_DURATION) do - whats_new_release_items&.count - end + ReleaseHighlight.most_recent_item_count end def whats_new_storage_key - return unless whats_new_most_recent_version + most_recent_version = ReleaseHighlight.versions&.first - ['display-whats-new-notification', whats_new_most_recent_version].join('-') - end + return unless most_recent_version - private + ['display-whats-new-notification', most_recent_version].join('-') + end - def whats_new_most_recent_version - Gitlab::ProcessMemoryCache.cache_backend.fetch('whats_new:release_version', expires_in: CACHE_DURATION) do - whats_new_release_items&.first&.[]('release') - end + def whats_new_versions + ReleaseHighlight.versions end end |