diff options
Diffstat (limited to 'app')
86 files changed, 370 insertions, 190 deletions
diff --git a/app/assets/javascripts/contextual_sidebar.js b/app/assets/javascripts/contextual_sidebar.js index 03dea1ec0a5..b62ec8a651b 100644 --- a/app/assets/javascripts/contextual_sidebar.js +++ b/app/assets/javascripts/contextual_sidebar.js @@ -8,6 +8,8 @@ import { parseBoolean } from '~/lib/utils/common_utils'; // https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/24555#note_134136110 const NAV_SIDEBAR_BREAKPOINT = 1200; +export const SIDEBAR_COLLAPSED_CLASS = 'js-sidebar-collapsed'; + export default class ContextualSidebar { constructor() { this.initDomElements(); @@ -62,6 +64,7 @@ export default class ContextualSidebar { const breakpoint = bp.getBreakpointSize(); const dbp = ContextualSidebar.isDesktopBreakpoint(); + this.$sidebar.toggleClass(SIDEBAR_COLLAPSED_CLASS, !show); this.$sidebar.toggleClass('sidebar-expanded-mobile', !dbp ? show : false); this.$overlay.toggleClass( 'mobile-nav-open', diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 0ed4dcdcd81..11d6672cacf 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -157,10 +157,12 @@ export default { this.adjustView(); eventHub.$once('fetchedNotesData', this.setDiscussions); eventHub.$once('fetchDiffData', this.fetchData); + eventHub.$on('refetchDiffData', this.refetchDiffData); this.CENTERED_LIMITED_CONTAINER_CLASSES = CENTERED_LIMITED_CONTAINER_CLASSES; }, beforeDestroy() { eventHub.$off('fetchDiffData', this.fetchData); + eventHub.$off('refetchDiffData', this.refetchDiffData); this.removeEventListeners(); }, methods: { @@ -175,10 +177,16 @@ export default { 'scrollToFile', 'toggleShowTreeList', ]), - fetchData() { + refetchDiffData() { + this.assignedDiscussions = false; + this.fetchData(false); + }, + fetchData(toggleTree = true) { this.fetchDiffFiles() .then(() => { - this.hideTreeListIfJustOneFile(); + if (toggleTree) { + this.hideTreeListIfJustOneFile(); + } requestIdleCallback( () => { diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 386d08aed2b..35297b7c264 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -52,7 +52,7 @@ export const fetchDiffFiles = ({ state, commit }) => { }); return axios - .get(state.endpoint, { params: { w: state.showWhitespace ? null : '1' } }) + .get(mergeUrlParams({ w: state.showWhitespace ? '0' : '1' }, state.endpoint)) .then(res => { commit(types.SET_LOADING, false); commit(types.SET_MERGE_REQUEST_DIFFS, res.data.merge_request_diffs || []); @@ -125,7 +125,8 @@ export const startRenderDiffsQueue = ({ state, commit }) => { new Promise(resolve => { const nextFile = state.diffFiles.find( file => - !file.renderIt && (!file.viewer.collapsed || !file.viewer.name === diffViewerModes.text), + !file.renderIt && + (file.viewer && (!file.viewer.collapsed || !file.viewer.name === diffViewerModes.text)), ); if (nextFile) { @@ -315,8 +316,10 @@ export const setShowWhitespace = ({ commit }, { showWhitespace, pushState = fals localStorage.setItem(WHITESPACE_STORAGE_KEY, showWhitespace); if (pushState) { - historyPushState(showWhitespace ? '?w=0' : '?w=1'); + historyPushState(mergeUrlParams({ w: showWhitespace ? '0' : '1' }, window.location.href)); } + + eventHub.$emit('refetchDiffData'); }; export const toggleFileFinder = ({ commit }, visible) => { diff --git a/app/assets/javascripts/fly_out_nav.js b/app/assets/javascripts/fly_out_nav.js index 2b6af9060d1..2566ed6b47c 100644 --- a/app/assets/javascripts/fly_out_nav.js +++ b/app/assets/javascripts/fly_out_nav.js @@ -1,4 +1,5 @@ import bp from './breakpoints'; +import { SIDEBAR_COLLAPSED_CLASS } from './contextual_sidebar'; const HIDE_INTERVAL_TIMEOUT = 300; const IS_OVER_CLASS = 'is-over'; @@ -29,7 +30,7 @@ const setHeaderHeight = () => { }; export const isSidebarCollapsed = () => - sidebar && sidebar.classList.contains('sidebar-collapsed-desktop'); + sidebar && sidebar.classList.contains(SIDEBAR_COLLAPSED_CLASS); export const canShowActiveSubItems = el => { if (el.classList.contains('active') && !isSidebarCollapsed()) { diff --git a/app/assets/javascripts/issuable_bulk_update_actions.js b/app/assets/javascripts/issuable_bulk_update_actions.js index ccbe591a63e..bc9d7fcf30d 100644 --- a/app/assets/javascripts/issuable_bulk_update_actions.js +++ b/app/assets/javascripts/issuable_bulk_update_actions.js @@ -4,6 +4,7 @@ import $ from 'jquery'; import _ from 'underscore'; import axios from './lib/utils/axios_utils'; import Flash from './flash'; +import { __ } from './locale'; export default { init({ container, form, issues, prefixId } = {}) { @@ -32,7 +33,7 @@ export default { onFormSubmitFailure() { this.form.find('[type="submit"]').enable(); - return new Flash('Issue update failed'); + return new Flash(__('Issue update failed')); }, getSelectedIssues() { diff --git a/app/assets/javascripts/issuable_index.js b/app/assets/javascripts/issuable_index.js index ffcbd7cf28c..f51c7a2f990 100644 --- a/app/assets/javascripts/issuable_index.js +++ b/app/assets/javascripts/issuable_index.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import flash from './flash'; -import { __ } from './locale'; +import { s__, __ } from './locale'; import IssuableBulkUpdateSidebar from './issuable_bulk_update_sidebar'; import IssuableBulkUpdateActions from './issuable_bulk_update_actions'; @@ -29,7 +29,7 @@ export default class IssuableIndex { $resetToken.on('click', e => { e.preventDefault(); - $resetToken.text('resetting...'); + $resetToken.text(s__('EmailToken|resetting...')); axios .put($resetToken.attr('href')) @@ -38,12 +38,12 @@ export default class IssuableIndex { .val(data.new_address) .focus(); - $resetToken.text('reset it'); + $resetToken.text(s__('EmailToken|reset it')); }) .catch(() => { flash(__('There was an error when reseting email token.')); - $resetToken.text('reset it'); + $resetToken.text(s__('EmailToken|reset it')); }); }); } diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index cd1afb6ba83..db4607ca58d 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -7,6 +7,7 @@ import flash from './flash'; import TaskList from './task_list'; import CreateMergeRequestDropdown from './create_merge_request_dropdown'; import IssuablesHelper from './helpers/issuables_helper'; +import { __ } from './locale'; export default class Issue { constructor() { @@ -44,7 +45,11 @@ export default class Issue { * @param {Array} data * @param {String} issueFailMessage */ - updateTopState(isClosed, data, issueFailMessage = 'Unable to update this issue at this time.') { + updateTopState( + isClosed, + data, + issueFailMessage = __('Unable to update this issue at this time.'), + ) { if ('id' in data) { const isClosedBadge = $('div.status-box-issue-closed'); const isOpenBadge = $('div.status-box-open'); @@ -81,7 +86,7 @@ export default class Issue { } initIssueBtnEventListeners() { - const issueFailMessage = 'Unable to update this issue at this time.'; + const issueFailMessage = __('Unable to update this issue at this time.'); return $(document).on( 'click', @@ -152,6 +157,6 @@ export default class Issue { $container.html(data.html); } }) - .catch(() => flash('Failed to load related branches')); + .catch(() => flash(__('Failed to load related branches'))); } } diff --git a/app/assets/javascripts/issue_status_select.js b/app/assets/javascripts/issue_status_select.js index c14803c80e7..75edff41a89 100644 --- a/app/assets/javascripts/issue_status_select.js +++ b/app/assets/javascripts/issue_status_select.js @@ -1,4 +1,5 @@ import $ from 'jquery'; +import { __ } from './locale'; export default function issueStatusSelect() { $('.js-issue-status').each((i, el) => { @@ -7,7 +8,7 @@ export default function issueStatusSelect() { selectable: true, fieldName, toggleLabel(selected, element, instance) { - let label = 'Author'; + let label = __('Author'); const $item = instance.dropdown.find('.is-active'); if ($item.length) { label = $item.text(); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 213d5c6521a..1af21715551 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -31,6 +31,7 @@ import initPerformanceBar from './performance_bar'; import initSearchAutocomplete from './search_autocomplete'; import GlFieldErrors from './gl_field_errors'; import initUserPopovers from './user_popovers'; +import { __ } from './locale'; // expose jQuery as global (TODO: remove these) window.jQuery = jQuery; @@ -219,9 +220,9 @@ document.addEventListener('DOMContentLoaded', () => { const ref = xhrObj.status; if (ref === 401) { - Flash('You need to be logged in.'); + Flash(__('You need to be logged in.')); } else if (ref === 404 || ref === 500) { - Flash('Something went wrong on our end.'); + Flash(__('Something went wrong on our end.')); } }); diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 509f19e6f00..e5cf43e8289 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -21,6 +21,7 @@ import { localTimeAgo } from './lib/utils/datetime_utility'; import syntaxHighlight from './syntax_highlight'; import Notes from './notes'; import { polyfillSticky } from './lib/utils/sticky'; +import { __ } from './locale'; // MergeRequestTabs // @@ -326,7 +327,7 @@ export default class MergeRequestTabs { }) .catch(() => { this.toggleLoading(false); - flash('An error occurred while fetching this tab.'); + flash(__('An error occurred while fetching this tab.')); }); } @@ -416,7 +417,7 @@ export default class MergeRequestTabs { }) .catch(() => { this.toggleLoading(false); - flash('An error occurred while fetching this tab.'); + flash(__('An error occurred while fetching this tab.')); }); } diff --git a/app/assets/javascripts/milestone.js b/app/assets/javascripts/milestone.js index f211632cf24..6aaba4e7c74 100644 --- a/app/assets/javascripts/milestone.js +++ b/app/assets/javascripts/milestone.js @@ -2,6 +2,7 @@ import $ from 'jquery'; import axios from './lib/utils/axios_utils'; import flash from './flash'; import { mouseenter, debouncedMouseleave, togglePopover } from './shared/popover'; +import { __ } from './locale'; export default class Milestone { constructor() { @@ -42,7 +43,7 @@ export default class Milestone { $(tabElId).html(data.html); $target.addClass('is-loaded'); }) - .catch(() => flash('Error loading milestone tab')); + .catch(() => flash(__('Error loading milestone tab'))); } } diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 75c18a9b6a0..43949d5cc86 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -56,14 +56,15 @@ export default class MilestoneSelect { const $value = $block.find('.value'); const $loading = $block.find('.block-loading').fadeOut(); selectedMilestoneDefault = showAny ? '' : null; - selectedMilestoneDefault = showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault; + selectedMilestoneDefault = + showNo && defaultNo ? __('No Milestone') : selectedMilestoneDefault; selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault; if (issueUpdateURL) { milestoneLinkTemplate = _.template( '<a href="<%- web_url %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>', ); - milestoneLinkNoneTemplate = '<span class="no-value">None</span>'; + milestoneLinkNoneTemplate = `<span class="no-value">${__('None')}</span>`; } return $dropdown.glDropdown({ showMenuAbove: showMenuAbove, @@ -74,28 +75,28 @@ export default class MilestoneSelect { extraOptions.push({ id: null, name: null, - title: 'Any Milestone', + title: __('Any Milestone'), }); } if (showNo) { extraOptions.push({ id: -1, - name: 'No Milestone', - title: 'No Milestone', + name: __('No Milestone'), + title: __('No Milestone'), }); } if (showUpcoming) { extraOptions.push({ id: -2, name: '#upcoming', - title: 'Upcoming', + title: __('Upcoming'), }); } if (showStarted) { extraOptions.push({ id: -3, name: '#started', - title: 'Started', + title: __('Started'), }); } if (extraOptions.length) { diff --git a/app/assets/javascripts/mini_pipeline_graph_dropdown.js b/app/assets/javascripts/mini_pipeline_graph_dropdown.js index 81ab9d8be4b..b39ad764f01 100644 --- a/app/assets/javascripts/mini_pipeline_graph_dropdown.js +++ b/app/assets/javascripts/mini_pipeline_graph_dropdown.js @@ -1,6 +1,7 @@ import $ from 'jquery'; import flash from './flash'; import axios from './lib/utils/axios_utils'; +import { __ } from './locale'; /** * In each pipelines table we have a mini pipeline graph for each pipeline. @@ -98,7 +99,7 @@ export default class MiniPipelineGraph { ) { $(button).dropdown('toggle'); } - flash('An error occurred while fetching the builds.', 'alert'); + flash(__('An error occurred while fetching the builds.'), 'alert'); }); } diff --git a/app/assets/javascripts/namespace_select.js b/app/assets/javascripts/namespace_select.js index ee1a5274ff7..03d349ac714 100644 --- a/app/assets/javascripts/namespace_select.js +++ b/app/assets/javascripts/namespace_select.js @@ -4,6 +4,7 @@ import $ from 'jquery'; import Api from './api'; import { mergeUrlParams } from './lib/utils/url_utility'; import { parseBoolean } from '~/lib/utils/common_utils'; +import { __ } from './locale'; export default class NamespaceSelect { constructor(opts) { @@ -29,7 +30,7 @@ export default class NamespaceSelect { return Api.namespaces(term, function(namespaces) { if (isFilter) { const anyNamespace = { - text: 'Any namespace', + text: __('Any namespace'), id: null, }; namespaces.unshift(anyNamespace); diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 36725e22365..d03f4508fb8 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -35,6 +35,7 @@ import { } from './lib/utils/common_utils'; import imageDiffHelper from './image_diff/helpers/index'; import { localTimeAgo } from './lib/utils/datetime_utility'; +import { sprintf, s__, __ } from './locale'; window.autosize = Autosize; @@ -253,7 +254,7 @@ export default class Notes { discussionNoteForm = $textarea.closest('.js-discussion-note-form'); if (discussionNoteForm.length) { if ($textarea.val() !== '') { - if (!window.confirm('Are you sure you want to cancel creating this comment?')) { + if (!window.confirm(__('Are you sure you want to cancel creating this comment?'))) { return; } } @@ -265,7 +266,7 @@ export default class Notes { originalText = $textarea.closest('form').data('originalNote'); newText = $textarea.val(); if (originalText !== newText) { - if (!window.confirm('Are you sure you want to cancel editing this comment?')) { + if (!window.confirm(__('Are you sure you want to cancel editing this comment?'))) { return; } } @@ -636,7 +637,7 @@ export default class Notes { this.glForm = new GLForm(form, enableGFM); textarea = form.find('.js-note-text'); key = [ - 'Note', + s__('NoteForm|Note'), form.find('#note_noteable_type').val(), form.find('#note_noteable_id').val(), form.find('#note_commit_id').val(), @@ -670,7 +671,9 @@ export default class Notes { formParentTimeline = $form.closest('.discussion-notes').find('.notes'); } return this.addFlash( - 'Your comment could not be submitted! Please check your network connection and try again.', + __( + 'Your comment could not be submitted! Please check your network connection and try again.', + ), 'alert', formParentTimeline.get(0), ); @@ -679,7 +682,7 @@ export default class Notes { updateNoteError($parentTimeline) { // eslint-disable-next-line no-new new Flash( - 'Your comment could not be updated! Please check your network connection and try again.', + __('Your comment could not be updated! Please check your network connection and try again.'), ); } @@ -1258,12 +1261,19 @@ export default class Notes { putConflictEditWarningInPlace(noteEntity, $note) { if ($note.find('.js-conflict-edit-warning').length === 0) { + const open_link = `<a href="#note_${ + noteEntity.id + }" target="_blank" rel="noopener noreferrer">`; const $alert = $(`<div class="js-conflict-edit-warning alert alert-danger"> - This comment has changed since you started editing, please review the - <a href="#note_${noteEntity.id}" target="_blank" rel="noopener noreferrer"> - updated comment - </a> - to ensure information is not lost + ${sprintf( + s__( + 'Notes|This comment has changed since you started editing, please review the %{open_link}updated comment%{close_link} to ensure information is not lost', + ), + { + open_link, + close_link: '</a>', + }, + )} </div>`); $alert.insertAfter($note.find('.note-text')); } @@ -1491,13 +1501,15 @@ export default class Notes { if (executedCommands && executedCommands.length) { if (executedCommands.length > 1) { - tempFormContent = 'Applying multiple commands'; + tempFormContent = __('Applying multiple commands'); } else { const commandDescription = executedCommands[0].description.toLowerCase(); - tempFormContent = `Applying command to ${commandDescription}`; + tempFormContent = sprintf(__('Applying command to %{commandDescription}'), { + commandDescription, + }); } } else { - tempFormContent = 'Applying command'; + tempFormContent = __('Applying command'); } return tempFormContent; @@ -1817,7 +1829,9 @@ export default class Notes { $editingNote .find('.note-headline-meta a') .html( - '<i class="fa fa-spinner fa-spin" aria-label="Comment is being updated" aria-hidden="true"></i>', + `<i class="fa fa-spinner fa-spin" aria-label="${__( + 'Comment is being updated', + )}" aria-hidden="true"></i>`, ); // Make request to update comment on server diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss index e6c55252b24..3aabb66f7a6 100644 --- a/app/assets/stylesheets/framework/blocks.scss +++ b/app/assets/stylesheets/framework/blocks.scss @@ -22,6 +22,10 @@ } } +.oneline { + line-height: 35px; +} + .row-content-block { margin-top: 0; background-color: $gray-light; @@ -77,10 +81,6 @@ color: $gl-text-color; } - .oneline { - line-height: 35px; - } - > p:last-child { margin-bottom: 0; } @@ -108,10 +108,6 @@ padding: 11px 0; margin-bottom: 11px; - .oneline { - line-height: 35px; - } - &.no-bottom-space { border-bottom: 0; margin-bottom: 0; @@ -160,8 +156,6 @@ } .cover-desc { - color: $gl-text-color; - &.username:last-child { padding-bottom: $gl-padding; } diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 2b499e50ea3..2e38b260f5f 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -439,10 +439,6 @@ img.emoji { .min-height-0 { min-height: 0; } -.w-3 { width: #{3 * $grid-size}; } - -.h-3 { width: #{3 * $grid-size}; } - .svg-w-100 { svg { width: 100%; diff --git a/app/assets/stylesheets/framework/header.scss b/app/assets/stylesheets/framework/header.scss index a57cd6737f8..1bc597bd4ae 100644 --- a/app/assets/stylesheets/framework/header.scss +++ b/app/assets/stylesheets/framework/header.scss @@ -472,6 +472,22 @@ background-color: $blue-500; } } + + .canary-badge { + .badge { + font-size: $gl-font-size-small; + line-height: $gl-line-height; + padding: 0 $grid-size; + } + + &:hover { + text-decoration: none; + + .badge { + text-decoration: none; + } + } + } } @include media-breakpoint-down(xs) { diff --git a/app/controllers/admin/application_settings_controller.rb b/app/controllers/admin/application_settings_controller.rb index d445be0eb19..d5bc723aa8c 100644 --- a/app/controllers/admin/application_settings_controller.rb +++ b/app/controllers/admin/application_settings_controller.rb @@ -89,6 +89,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ) end + # Getting ToS url requires `directory` api call to Let's Encrypt + # which could result in 500 error/slow rendering on settings page + # Because of that we use separate controller action + def lets_encrypt_terms_of_service + redirect_to ::Gitlab::LetsEncrypt.terms_of_service_url + end + private def set_application_setting diff --git a/app/controllers/concerns/project_unauthorized.rb b/app/controllers/concerns/project_unauthorized.rb index d42363b8b17..7238840440f 100644 --- a/app/controllers/concerns/project_unauthorized.rb +++ b/app/controllers/concerns/project_unauthorized.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true module ProjectUnauthorized - def project_unauthorized_proc - lambda do |project| - if project - label = project.external_authorization_classification_label + module ControllerActions + def self.on_routable_not_found + lambda do |routable| + return unless routable.is_a?(Project) + + label = routable.external_authorization_classification_label rejection_reason = nil unless ::Gitlab::ExternalAuthorization.access_allowed?(current_user, label) @@ -12,9 +14,7 @@ module ProjectUnauthorized rejection_reason ||= _('External authorization denied access to this project') end - if rejection_reason - access_denied!(rejection_reason) - end + access_denied!(rejection_reason) if rejection_reason end end end diff --git a/app/controllers/concerns/routable_actions.rb b/app/controllers/concerns/routable_actions.rb index 5624eb3aa45..ff9b0332c97 100644 --- a/app/controllers/concerns/routable_actions.rb +++ b/app/controllers/concerns/routable_actions.rb @@ -3,15 +3,13 @@ module RoutableActions extend ActiveSupport::Concern - def find_routable!(routable_klass, requested_full_path, extra_authorization_proc: nil, not_found_or_authorized_proc: nil) + def find_routable!(routable_klass, requested_full_path, extra_authorization_proc: nil) routable = routable_klass.find_by_full_path(requested_full_path, follow_redirects: request.get?) if routable_authorized?(routable, extra_authorization_proc) ensure_canonical_path(routable, requested_full_path) routable else - if not_found_or_authorized_proc - not_found_or_authorized_proc.call(routable) - end + perform_not_found_actions(routable, not_found_actions) route_not_found unless performed? @@ -19,6 +17,18 @@ module RoutableActions end end + def not_found_actions + [ProjectUnauthorized::ControllerActions.on_routable_not_found] + end + + def perform_not_found_actions(routable, actions) + actions.each do |action| + break if performed? + + instance_exec(routable, &action) + end + end + def routable_authorized?(routable, extra_authorization_proc) return false unless routable diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb index 781eac7f080..80e4f54bbf4 100644 --- a/app/controllers/projects/application_controller.rb +++ b/app/controllers/projects/application_controller.rb @@ -3,7 +3,6 @@ class Projects::ApplicationController < ApplicationController include CookiesHelper include RoutableActions - include ProjectUnauthorized include ChecksCollaboration skip_before_action :authenticate_user! @@ -22,7 +21,7 @@ class Projects::ApplicationController < ApplicationController path = File.join(params[:namespace_id], params[:project_id] || params[:id]) auth_proc = ->(project) { !project.pending_delete? } - @project = find_routable!(Project, path, extra_authorization_proc: auth_proc, not_found_or_authorized_proc: project_unauthorized_proc) + @project = find_routable!(Project, path, extra_authorization_proc: auth_proc) end def build_canonical_path(project) diff --git a/app/controllers/projects/clusters/applications_controller.rb b/app/controllers/projects/clusters/applications_controller.rb index c7b6218d007..2a04b007304 100644 --- a/app/controllers/projects/clusters/applications_controller.rb +++ b/app/controllers/projects/clusters/applications_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class Projects::Clusters::ApplicationsController < Clusters::ApplicationsController - include ProjectUnauthorized - prepend_before_action :project private @@ -12,6 +10,6 @@ class Projects::Clusters::ApplicationsController < Clusters::ApplicationsControl end def project - @project ||= find_routable!(Project, File.join(params[:namespace_id], params[:project_id]), not_found_or_authorized_proc: project_unauthorized_proc) + @project ||= find_routable!(Project, File.join(params[:namespace_id], params[:project_id])) end end diff --git a/app/controllers/projects/clusters_controller.rb b/app/controllers/projects/clusters_controller.rb index feda6deeaa6..cb02581da37 100644 --- a/app/controllers/projects/clusters_controller.rb +++ b/app/controllers/projects/clusters_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class Projects::ClustersController < Clusters::ClustersController - include ProjectUnauthorized - prepend_before_action :project before_action :repository @@ -15,7 +13,7 @@ class Projects::ClustersController < Clusters::ClustersController end def project - @project ||= find_routable!(Project, File.join(params[:namespace_id], params[:project_id]), not_found_or_authorized_proc: project_unauthorized_proc) + @project ||= find_routable!(Project, File.join(params[:namespace_id], params[:project_id])) end def repository diff --git a/app/controllers/projects/serverless/functions_controller.rb b/app/controllers/projects/serverless/functions_controller.rb index 8c3d141c888..79030da64d3 100644 --- a/app/controllers/projects/serverless/functions_controller.rb +++ b/app/controllers/projects/serverless/functions_controller.rb @@ -3,8 +3,6 @@ module Projects module Serverless class FunctionsController < Projects::ApplicationController - include ProjectUnauthorized - before_action :authorize_read_cluster! def index diff --git a/app/controllers/uploads_controller.rb b/app/controllers/uploads_controller.rb index 060b09f015c..5d28635232b 100644 --- a/app/controllers/uploads_controller.rb +++ b/app/controllers/uploads_controller.rb @@ -45,7 +45,7 @@ class UploadsController < ApplicationController when Appearance true else - permission = "read_#{model.class.to_s.underscore}".to_sym + permission = "read_#{model.class.underscore}".to_sym can?(current_user, permission, model) end diff --git a/app/helpers/dashboard_helper.rb b/app/helpers/dashboard_helper.rb index d90ef8903a7..42732eb93dd 100644 --- a/app/helpers/dashboard_helper.rb +++ b/app/helpers/dashboard_helper.rb @@ -21,6 +21,10 @@ module DashboardHelper links.any? { |link| dashboard_nav_link?(link) } end + def has_start_trial? + false + end + private def get_dashboard_nav_links diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index 96471d15aac..dc0e5511fcf 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -91,6 +91,28 @@ module EmailsHelper ].join(';') end + def closure_reason_text(closed_via, format: nil) + case closed_via + when MergeRequest + merge_request = MergeRequest.find(closed_via[:id]).present + + case format + when :html + " via merge request #{link_to(merge_request.to_reference, merge_request.web_url)}" + else + # If it's not HTML nor text then assume it's text to be safe + " via merge request #{merge_request.to_reference} (#{merge_request.web_url})" + end + when String + # Technically speaking this should be Commit but per + # https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15610#note_163812339 + # we can't deserialize Commit without custom serializer for ActiveJob + " via #{closed_via}" + else + "" + end + end + # "You are receiving this email because #{reason}" def notification_reason_text(reason) string = case reason diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb index 1371e9993b4..e990e425cb6 100644 --- a/app/helpers/events_helper.rb +++ b/app/helpers/events_helper.rb @@ -68,7 +68,7 @@ module EventsHelper end def event_preposition(event) - if event.push? || event.commented? || event.target + if event.push_action? || event.commented_action? || event.target "at" elsif event.milestone? "in" @@ -80,11 +80,11 @@ module EventsHelper words << event.author_name words << event_action_name(event) - if event.push? + if event.push_action? words << event.ref_type words << event.ref_name words << "at" - elsif event.commented? + elsif event.commented_action? words << event.note_target_reference words << "at" elsif event.milestone? @@ -121,9 +121,9 @@ module EventsHelper if event.note_target event_note_target_url(event) end - elsif event.push? + elsif event.push_action? push_event_feed_url(event) - elsif event.created_project? + elsif event.created_project_action? project_url(event.project) end end @@ -147,7 +147,7 @@ module EventsHelper def event_feed_summary(event) if event.issue? render "events/event_issue", issue: event.issue - elsif event.push? + elsif event.push_action? render "events/event_push", event: event elsif event.merge_request? render "events/event_merge_request", merge_request: event.merge_request diff --git a/app/helpers/nav_helper.rb b/app/helpers/nav_helper.rb index 05da5ebdb22..a57ba5f3a4f 100644 --- a/app/helpers/nav_helper.rb +++ b/app/helpers/nav_helper.rb @@ -58,6 +58,14 @@ module NavHelper current_path?('milestones#show') end + def admin_monitoring_nav_links + %w(system_info background_jobs logs health_check requests_profiles) + end + + def group_issues_sub_menu_items + %w(groups#issues labels#index milestones#index boards#index boards#show) + end + private def get_header_links diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 2c43b1a2067..91d15e0e4ea 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -315,6 +315,10 @@ module ProjectsHelper ) % { default_label: default_label } end + def can_import_members? + Ability.allowed?(current_user, :admin_project_member, @project) + end + private def get_project_nav_tabs(project, current_user) diff --git a/app/helpers/storage_helper.rb b/app/helpers/storage_helper.rb index 15041bd5805..e80b3f2b54a 100644 --- a/app/helpers/storage_helper.rb +++ b/app/helpers/storage_helper.rb @@ -2,6 +2,8 @@ module StorageHelper def storage_counter(size_in_bytes) + return s_('StorageSize|Unknown') unless size_in_bytes + precision = size_in_bytes < 1.megabyte ? 0 : 1 number_to_human_size(size_in_bytes, delimiter: ',', precision: precision, significant: false) diff --git a/app/mailers/devise_mailer.rb b/app/mailers/devise_mailer.rb index 7aa75ee30e6..cbaf53fced1 100644 --- a/app/mailers/devise_mailer.rb +++ b/app/mailers/devise_mailer.rb @@ -7,6 +7,7 @@ class DeviseMailer < Devise::Mailer layout 'mailer/devise' helper EmailsHelper + helper ApplicationHelper protected diff --git a/app/mailers/emails/issues.rb b/app/mailers/emails/issues.rb index d2e334fb856..2b046d17122 100644 --- a/app/mailers/emails/issues.rb +++ b/app/mailers/emails/issues.rb @@ -30,8 +30,8 @@ module Emails end # rubocop: enable CodeReuse/ActiveRecord - def closed_issue_email(recipient_id, issue_id, updated_by_user_id, reason = nil) - setup_issue_mail(issue_id, recipient_id) + def closed_issue_email(recipient_id, issue_id, updated_by_user_id, reason: nil, closed_via: nil) + setup_issue_mail(issue_id, recipient_id, closed_via: closed_via) @updated_by = User.find(updated_by_user_id) mail_answer_thread(@issue, issue_thread_options(updated_by_user_id, recipient_id, reason)) @@ -91,10 +91,11 @@ module Emails private - def setup_issue_mail(issue_id, recipient_id) + def setup_issue_mail(issue_id, recipient_id, closed_via: nil) @issue = Issue.find(issue_id) @project = @issue.project @target_url = project_issue_url(@project, @issue) + @closed_via = closed_via @sent_notification = SentNotification.record(@issue, recipient_id, reply_key) end diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb index 63148831a24..fc6ed695675 100644 --- a/app/mailers/emails/merge_requests.rb +++ b/app/mailers/emails/merge_requests.rb @@ -58,14 +58,14 @@ module Emails })) end - def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil) + def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason: nil, closed_via: nil) setup_merge_request_mail(merge_request_id, recipient_id) @updated_by = User.find(updated_by_user_id) mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason)) end - def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason = nil) + def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id, reason: nil, closed_via: nil) setup_merge_request_mail(merge_request_id, recipient_id) mail_answer_thread(@merge_request, merge_request_thread_options(updated_by_user_id, recipient_id, reason)) diff --git a/app/models/active_session.rb b/app/models/active_session.rb index 1e01f1d17e6..f355b02c428 100644 --- a/app/models/active_session.rb +++ b/app/models/active_session.rb @@ -53,7 +53,7 @@ class ActiveSession def self.list(user) Gitlab::Redis::SharedState.with do |redis| - cleaned_up_lookup_entries(redis, user.id).map do |entry| + cleaned_up_lookup_entries(redis, user).map do |entry| # rubocop:disable Security/MarshalLoad Marshal.load(entry) # rubocop:enable Security/MarshalLoad @@ -78,7 +78,7 @@ class ActiveSession def self.cleanup(user) Gitlab::Redis::SharedState.with do |redis| - cleaned_up_lookup_entries(redis, user.id) + cleaned_up_lookup_entries(redis, user) end end @@ -90,25 +90,52 @@ class ActiveSession "#{Gitlab::Redis::SharedState::USER_SESSIONS_LOOKUP_NAMESPACE}:#{user_id}" end - def self.cleaned_up_lookup_entries(redis, user_id) - lookup_key = lookup_key_name(user_id) + def self.list_sessions(user) + sessions_from_ids(session_ids_for_user(user)) + end - session_ids = redis.smembers(lookup_key) + def self.session_ids_for_user(user) + Gitlab::Redis::SharedState.with do |redis| + redis.smembers(lookup_key_name(user.id)) + end + end - entry_keys = session_ids.map { |session_id| key_name(user_id, session_id) } - return [] if entry_keys.empty? + def self.sessions_from_ids(session_ids) + return [] if session_ids.empty? - entries = redis.mget(entry_keys) + Gitlab::Redis::SharedState.with do |redis| + session_keys = session_ids.map { |session_id| "#{Gitlab::Redis::SharedState::SESSION_NAMESPACE}:#{session_id}" } - session_ids_and_entries = session_ids.zip(entries) + redis.mget(session_keys).compact.map do |raw_session| + # rubocop:disable Security/MarshalLoad + Marshal.load(raw_session) + # rubocop:enable Security/MarshalLoad + end + end + end + + def self.raw_active_session_entries(session_ids, user_id) + return [] if session_ids.empty? + + Gitlab::Redis::SharedState.with do |redis| + entry_keys = session_ids.map { |session_id| key_name(user_id, session_id) } + + redis.mget(entry_keys) + end + end + + def self.cleaned_up_lookup_entries(redis, user) + session_ids = session_ids_for_user(user) + entries = raw_active_session_entries(session_ids, user.id) # remove expired keys. # only the single key entries are automatically expired by redis, the # lookup entries in the set need to be removed manually. + session_ids_and_entries = session_ids.zip(entries) session_ids_and_entries.reject { |_session_id, entry| entry }.each do |session_id, _entry| - redis.srem(lookup_key, session_id) + redis.srem(lookup_key_name(user.id), session_id) end - session_ids_and_entries.select { |_session_id, entry| entry }.map { |_session_id, entry| entry } + entries.compact end end diff --git a/app/models/application_record.rb b/app/models/application_record.rb index d1d01368972..0979d03f6e6 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -41,4 +41,8 @@ class ApplicationRecord < ActiveRecord::Base find_or_create_by(*args) end end + + def self.underscore + Gitlab::SafeRequestStore.fetch("model:#{self}:underscore") { self.to_s.underscore } + end end diff --git a/app/models/ci/job_artifact.rb b/app/models/ci/job_artifact.rb index f9cf398556d..3beb76ffc2b 100644 --- a/app/models/ci/job_artifact.rb +++ b/app/models/ci/job_artifact.rb @@ -99,7 +99,7 @@ module Ci raw: 1, zip: 2, gzip: 3 - } + }, _suffix: true # `file_location` indicates where actual files are stored. # Ideally, actual files should be stored in the same directory, and use the same diff --git a/app/models/event.rb b/app/models/event.rb index 593acf5edfe..738080eb584 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -68,7 +68,7 @@ class Event < ApplicationRecord # Callbacks after_create :reset_project_activity - after_create :set_last_repository_updated_at, if: :push? + after_create :set_last_repository_updated_at, if: :push_action? after_create :track_user_interacted_projects # Scopes @@ -138,11 +138,11 @@ class Event < ApplicationRecord # rubocop:disable Metrics/CyclomaticComplexity # rubocop:disable Metrics/PerceivedComplexity def visible_to_user?(user = nil) - if push? || commit_note? + if push_action? || commit_note? Ability.allowed?(user, :download_code, project) elsif membership_changed? Ability.allowed?(user, :read_project, project) - elsif created_project? + elsif created_project_action? Ability.allowed?(user, :read_project, project) elsif issue? || issue_note? Ability.allowed?(user, :read_issue, note? ? note_target : target) @@ -173,56 +173,56 @@ class Event < ApplicationRecord target.try(:title) end - def created? + def created_action? action == CREATED end - def push? + def push_action? false end - def merged? + def merged_action? action == MERGED end - def closed? + def closed_action? action == CLOSED end - def reopened? + def reopened_action? action == REOPENED end - def joined? + def joined_action? action == JOINED end - def left? + def left_action? action == LEFT end - def expired? + def expired_action? action == EXPIRED end - def destroyed? + def destroyed_action? action == DESTROYED end - def commented? + def commented_action? action == COMMENTED end def membership_changed? - joined? || left? || expired? + joined_action? || left_action? || expired_action? end - def created_project? - created? && !target && target_type.nil? + def created_project_action? + created_action? && !target && target_type.nil? end def created_target? - created? && target + created_action? && target end def milestone? @@ -258,23 +258,23 @@ class Event < ApplicationRecord end def action_name - if push? + if push_action? push_action_name - elsif closed? + elsif closed_action? "closed" - elsif merged? + elsif merged_action? "accepted" - elsif joined? + elsif joined_action? 'joined' - elsif left? + elsif left_action? 'left' - elsif expired? + elsif expired_action? 'removed due to membership expiration from' - elsif destroyed? + elsif destroyed_action? 'destroyed' - elsif commented? + elsif commented_action? "commented on" - elsif created_project? + elsif created_project_action? created_project_action_name else "opened" @@ -337,7 +337,7 @@ class Event < ApplicationRecord end def body? - if push? + if push_action? push_with_commits? elsif note? true diff --git a/app/models/members/group_member.rb b/app/models/members/group_member.rb index b266c61f002..4cba69069bb 100644 --- a/app/models/members/group_member.rb +++ b/app/models/members/group_member.rb @@ -12,7 +12,7 @@ class GroupMember < Member validates :source_type, format: { with: /\ANamespace\z/ } default_scope { where(source_type: SOURCE_TYPE) } - scope :in_groups, ->(groups) { where(source_id: groups.select(:id)) } + scope :of_groups, ->(groups) { where(source_id: groups.select(:id)) } scope :count_users_by_group_id, -> { joins(:user).group(:source_id).count } diff --git a/app/models/project.rb b/app/models/project.rb index 61d245478ca..ab4da61dcf8 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -56,7 +56,6 @@ class Project < ApplicationRecord VALID_MIRROR_PROTOCOLS = %w(http https ssh git).freeze ignore_column :import_status, :import_jid, :import_error - ignore_column :ci_id cache_markdown_field :description, pipeline: :description @@ -337,8 +336,8 @@ class Project < ApplicationRecord validates :star_count, numericality: { greater_than_or_equal_to: 0 } validate :check_personal_projects_limit, on: :create validate :check_repository_path_availability, on: :update, if: ->(project) { project.renamed? } - validate :visibility_level_allowed_by_group, if: -> { changes.has_key?(:visibility_level) } - validate :visibility_level_allowed_as_fork, if: -> { changes.has_key?(:visibility_level) } + validate :visibility_level_allowed_by_group, if: :should_validate_visibility_level? + validate :visibility_level_allowed_as_fork, if: :should_validate_visibility_level? validate :check_wiki_path_conflict validate :validate_pages_https_only, if: -> { changes.has_key?(:pages_https_only) } validates :repository_storage, @@ -892,6 +891,10 @@ class Project < ApplicationRecord self.errors.add(:limit_reached, error % { limit: limit }) end + def should_validate_visibility_level? + new_record? || changes.has_key?(:visibility_level) + end + def visibility_level_allowed_by_group return if visibility_level_allowed_by_group? diff --git a/app/models/push_event.rb b/app/models/push_event.rb index 9c0267c3140..4698df39730 100644 --- a/app/models/push_event.rb +++ b/app/models/push_event.rb @@ -69,7 +69,7 @@ class PushEvent < Event PUSHED end - def push? + def push_action? true end diff --git a/app/models/repository.rb b/app/models/repository.rb index 1c02e68f2f6..f540b00a849 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1050,7 +1050,7 @@ class Repository # To support the full deprecated behaviour, set the # `rebase_commit_sha` for the merge_request here and return the value - merge_request.update(rebase_commit_sha: rebase_sha) + merge_request.update(rebase_commit_sha: rebase_sha, merge_error: nil) rebase_sha end @@ -1069,7 +1069,7 @@ class Repository remote_repository: merge_request.target_project.repository.raw, remote_branch: merge_request.target_branch ) do |commit_id| - merge_request.update!(rebase_commit_sha: commit_id) + merge_request.update!(rebase_commit_sha: commit_id, merge_error: nil) end end end diff --git a/app/services/concerns/users/participable_service.rb b/app/services/concerns/users/participable_service.rb index a3cc6014fd3..1c828234f1b 100644 --- a/app/services/concerns/users/participable_service.rb +++ b/app/services/concerns/users/participable_service.rb @@ -29,7 +29,7 @@ module Users def groups group_counts = GroupMember - .in_groups(current_user.authorized_groups) + .of_groups(current_user.authorized_groups) .non_request .count_users_by_group_id diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb index e5cc12e6082..2a19e57a94f 100644 --- a/app/services/issues/close_service.rb +++ b/app/services/issues/close_service.rb @@ -7,7 +7,7 @@ module Issues return issue unless can?(current_user, :update_issue, issue) close_issue(issue, - commit: commit, + closed_via: commit, notifications: notifications, system_note: system_note) end @@ -17,9 +17,9 @@ module Issues # # The code calling this method is responsible for ensuring that a user is # allowed to close the given issue. - def close_issue(issue, commit: nil, notifications: true, system_note: true) + def close_issue(issue, closed_via: nil, notifications: true, system_note: true) if project.jira_tracker? && project.jira_service.active && issue.is_a?(ExternalIssue) - project.jira_service.close_issue(commit, issue) + project.jira_service.close_issue(closed_via, issue) todo_service.close_issue(issue, current_user) return issue end @@ -27,8 +27,11 @@ module Issues if project.issues_enabled? && issue.close issue.update(closed_by: current_user) event_service.close_issue(issue, current_user) - create_note(issue, commit) if system_note - notification_service.async.close_issue(issue, current_user) if notifications + create_note(issue, closed_via) if system_note + + closed_via = "commit #{closed_via.id}" if closed_via.is_a?(Commit) + + notification_service.async.close_issue(issue, current_user, closed_via: closed_via) if notifications todo_service.close_issue(issue, current_user) execute_hooks(issue, 'close') invalidate_cache_counts(issue, users: issue.assignees) diff --git a/app/services/members/destroy_service.rb b/app/services/members/destroy_service.rb index f9717a9426b..c8d5e563cd8 100644 --- a/app/services/members/destroy_service.rb +++ b/app/services/members/destroy_service.rb @@ -45,7 +45,7 @@ module Members def delete_subgroup_members(member) groups = member.group.descendants - GroupMember.in_groups(groups).with_user(member.user).each do |group_member| + GroupMember.of_groups(groups).with_user(member.user).each do |group_member| self.class.new(current_user).execute(group_member, skip_authorization: @skip_auth, skip_subresources: true) end end diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 8d3b569498f..f797c0f11c6 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -89,8 +89,8 @@ class NotificationService # * project team members with notification level higher then Participating # * users with custom level checked with "close issue" # - def close_issue(issue, current_user) - close_resource_email(issue, current_user, :closed_issue_email) + def close_issue(issue, current_user, closed_via: nil) + close_resource_email(issue, current_user, :closed_issue_email, closed_via: closed_via) end # When we reassign an issue we should send an email to: @@ -504,7 +504,7 @@ class NotificationService end end - def close_resource_email(target, current_user, method, skip_current_user: true) + def close_resource_email(target, current_user, method, skip_current_user: true, closed_via: nil) action = method == :merged_merge_request_email ? "merge" : "close" recipients = NotificationRecipientService.build_recipients( @@ -515,7 +515,7 @@ class NotificationService ) recipients.each do |recipient| - mailer.send(method, recipient.user.id, target.id, current_user.id, recipient.reason).deliver_later + mailer.send(method, recipient.user.id, target.id, current_user.id, reason: recipient.reason, closed_via: closed_via).deliver_later end end diff --git a/app/uploaders/attachment_uploader.rb b/app/uploaders/attachment_uploader.rb index 0a166335b4e..b488bba00e9 100644 --- a/app/uploaders/attachment_uploader.rb +++ b/app/uploaders/attachment_uploader.rb @@ -9,6 +9,6 @@ class AttachmentUploader < GitlabUploader private def dynamic_segment - File.join(model.class.to_s.underscore, mounted_as.to_s, model.id.to_s) + File.join(model.class.underscore, mounted_as.to_s, model.id.to_s) end end diff --git a/app/uploaders/avatar_uploader.rb b/app/uploaders/avatar_uploader.rb index c0165759203..9af59b0aceb 100644 --- a/app/uploaders/avatar_uploader.rb +++ b/app/uploaders/avatar_uploader.rb @@ -25,6 +25,6 @@ class AvatarUploader < GitlabUploader private def dynamic_segment - File.join(model.class.to_s.underscore, mounted_as.to_s, model.id.to_s) + File.join(model.class.underscore, mounted_as.to_s, model.id.to_s) end end diff --git a/app/uploaders/personal_file_uploader.rb b/app/uploaders/personal_file_uploader.rb index 272837aa6ce..f4697d898af 100644 --- a/app/uploaders/personal_file_uploader.rb +++ b/app/uploaders/personal_file_uploader.rb @@ -20,7 +20,7 @@ class PersonalFileUploader < FileUploader def self.model_path_segment(model) return 'temp/' unless model - File.join(model.class.to_s.underscore, model.id.to_s) + File.join(model.class.underscore, model.id.to_s) end def object_store diff --git a/app/views/admin/application_settings/_pages.html.haml b/app/views/admin/application_settings/_pages.html.haml index 64e01fa2d00..77795dbf913 100644 --- a/app/views/admin/application_settings/_pages.html.haml +++ b/app/views/admin/application_settings/_pages.html.haml @@ -30,8 +30,7 @@ .form-check = f.check_box :lets_encrypt_terms_of_service_accepted, class: 'form-check-input' = f.label :lets_encrypt_terms_of_service_accepted, class: 'form-check-label' do - // Terms of Service should actually be a link, but the best way to get the url is using API - // So it will be done in later MR - = _("I have read and agree to the Let's Encrypt Terms of Service") + - terms_of_service_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: lets_encrypt_terms_of_service_admin_application_settings_path } + = _("I have read and agree to the Let's Encrypt %{link_start}Terms of Service%{link_end}").html_safe % { link_start: terms_of_service_link_start, link_end: '</a>'.html_safe } = f.submit _('Save changes'), class: "btn btn-success" diff --git a/app/views/admin/health_check/show.html.haml b/app/views/admin/health_check/show.html.haml index 0f5e97e288a..ac56e354a4d 100644 --- a/app/views/admin/health_check/show.html.haml +++ b/app/views/admin/health_check/show.html.haml @@ -23,7 +23,7 @@ %code= liveness_url(token: Gitlab::CurrentSettings.health_check_access_token) %li %code= metrics_url(token: Gitlab::CurrentSettings.health_check_access_token) - + = render_if_exists 'admin/health_check/health_check_url' %hr .card .card-header diff --git a/app/views/admin/projects/_projects.html.haml b/app/views/admin/projects/_projects.html.haml index 5bc695aa7b5..9117f63f939 100644 --- a/app/views/admin/projects/_projects.html.haml +++ b/app/views/admin/projects/_projects.html.haml @@ -13,7 +13,7 @@ .stats %span.badge.badge-pill - = storage_counter(project.statistics.storage_size) + = storage_counter(project.statistics&.storage_size) - if project.archived %span.badge.badge-warning archived .title diff --git a/app/views/admin/projects/show.html.haml b/app/views/admin/projects/show.html.haml index f016a157daf..1e1ad9d5e19 100644 --- a/app/views/admin/projects/show.html.haml +++ b/app/views/admin/projects/show.html.haml @@ -74,10 +74,10 @@ %li %span.light= _('Storage:') - %strong= storage_counter(@project.statistics.storage_size) - ( - = storage_counters_details(@project.statistics) - ) + %strong= storage_counter(@project.statistics&.storage_size) + - if @project.statistics + = surround '(', ')' do + = storage_counters_details(@project.statistics) %li %span.light last commit: diff --git a/app/views/clusters/platforms/kubernetes/_form.html.haml b/app/views/clusters/platforms/kubernetes/_form.html.haml index 8caa25a7b5e..c1727cf9079 100644 --- a/app/views/clusters/platforms/kubernetes/_form.html.haml +++ b/app/views/clusters/platforms/kubernetes/_form.html.haml @@ -1,7 +1,7 @@ = bootstrap_form_for cluster, url: update_cluster_url_path, html: { class: 'gl-show-field-errors' }, as: :cluster do |field| - copy_name_btn = clipboard_button(text: cluster.name, title: s_('ClusterIntegration|Copy Kubernetes cluster name'), - class: 'input-group-text btn-default') unless !cluster.read_only_kubernetes_platform_fields? + class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields? = field.text_field :name, class: 'js-select-on-focus cluster-name', required: true, title: s_('ClusterIntegration|Cluster name is required.'), readonly: cluster.read_only_kubernetes_platform_fields?, @@ -10,7 +10,7 @@ = field.fields_for :platform_kubernetes, platform do |platform_field| - copy_api_url = clipboard_button(text: platform.api_url, title: s_('ClusterIntegration|Copy API URL'), - class: 'input-group-text btn-default') unless !cluster.read_only_kubernetes_platform_fields? + class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields? = platform_field.text_field :api_url, class: 'js-select-on-focus', required: true, title: s_('ClusterIntegration|API URL should be a valid http/https url.'), readonly: cluster.read_only_kubernetes_platform_fields?, @@ -18,7 +18,7 @@ input_group_class: 'gl-field-error-anchor', append: copy_api_url - copy_ca_cert_btn = clipboard_button(text: platform.ca_cert, title: s_('ClusterIntegration|Copy CA Certificate'), - class: 'input-group-text btn-default') unless !cluster.read_only_kubernetes_platform_fields? + class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields? = platform_field.text_area :ca_cert, class: 'js-select-on-focus', rows: '5', readonly: cluster.read_only_kubernetes_platform_fields?, placeholder: s_('ClusterIntegration|Certificate Authority bundle (PEM format)'), @@ -28,7 +28,7 @@ - show_token_btn = (platform_field.button s_('ClusterIntegration|Show'), type: 'button', class: 'js-show-cluster-token btn btn-default') - copy_token_btn = clipboard_button(text: platform.token, title: s_('ClusterIntegration|Copy Service Token'), - class: 'input-group-text btn-default') unless !cluster.read_only_kubernetes_platform_fields? + class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields? = platform_field.text_field :token, type: 'password', class: 'js-select-on-focus js-cluster-token', required: true, title: s_('ClusterIntegration|Service token is required.'), diff --git a/app/views/dashboard/projects/_zero_authorized_projects.html.haml b/app/views/dashboard/projects/_zero_authorized_projects.html.haml index 18a82feb189..8933c5d7227 100644 --- a/app/views/dashboard/projects/_zero_authorized_projects.html.haml +++ b/app/views/dashboard/projects/_zero_authorized_projects.html.haml @@ -1,4 +1,4 @@ -.blank-state-parent-container +.blank-state-parent-container{ class: ('has-start-trial-container' if has_start_trial?) } .section-container.section-welcome{ class: "#{ 'section-admin-welcome' if current_user.admin? }" } .container.section-body .row @@ -7,7 +7,12 @@ Welcome to GitLab %p.blank-state-text Code, test, and deploy together - - if current_user.admin? - = render "blank_state_admin_welcome" - - else - = render "blank_state_welcome" + .blank-state-row + %div{ class: ('column-large' if has_start_trial?) } + - if current_user.admin? + = render "blank_state_admin_welcome" + - else + = render "blank_state_welcome" + - if has_start_trial? + .column-small + = render_if_exists "blank_state_ee_trial" diff --git a/app/views/devise/shared/_signup_box.html.haml b/app/views/devise/shared/_signup_box.html.haml index 9c7ca6ebbd4..427db070253 100644 --- a/app/views/devise/shared/_signup_box.html.haml +++ b/app/views/devise/shared/_signup_box.html.haml @@ -29,6 +29,7 @@ - terms_link = link_to s_("I accept the|Terms of Service and Privacy Policy"), terms_path, target: "_blank" - accept_terms_label = _("I accept the %{terms_link}") % { terms_link: terms_link } = accept_terms_label.html_safe + = render_if_exists 'devise/shared/email_opted_in', f: f %div - if Gitlab::Recaptcha.enabled? = recaptcha_tags diff --git a/app/views/devise/shared/_tabs_ldap.html.haml b/app/views/devise/shared/_tabs_ldap.html.haml index aee05b6c81c..b1a9470cf1c 100644 --- a/app/views/devise/shared/_tabs_ldap.html.haml +++ b/app/views/devise/shared/_tabs_ldap.html.haml @@ -2,6 +2,7 @@ - if crowd_enabled? %li.nav-item = link_to "Crowd", "#crowd", class: "nav-link #{active_when(form_based_auth_provider_has_active_class?(:crowd))}", 'data-toggle' => 'tab' + = render_if_exists "devise/shared/kerberos_tab" - @ldap_servers.each_with_index do |server, i| %li.nav-item = link_to server['label'], "##{server['provider_name']}", class: "nav-link #{active_when(i.zero? && form_based_auth_provider_has_active_class?(:ldapmain))} qa-ldap-tab", 'data-toggle' => 'tab' diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml index 2fcb1d1fd2b..222175c818a 100644 --- a/app/views/events/_event.html.haml +++ b/app/views/events/_event.html.haml @@ -3,11 +3,11 @@ .event-item-timestamp #{time_ago_with_tooltip(event.created_at)} - - if event.created_project? + - if event.created_project_action? = render "events/event/created_project", event: event - - elsif event.push? + - elsif event.push_action? = render "events/event/push", event: event - - elsif event.commented? + - elsif event.commented_action? = render "events/event/note", event: event - else = render "events/event/common", event: event diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index 75e4dc46c9b..50933c7d434 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -5,8 +5,7 @@ %hr %h1 - GitLab - Community Edition + = default_brand_title - if user_signed_in? %span= link_to_version = version_status_badge diff --git a/app/views/help/ui.html.haml b/app/views/help/ui.html.haml index 969df69aafb..cdc894ee5a0 100644 --- a/app/views/help/ui.html.haml +++ b/app/views/help/ui.html.haml @@ -70,7 +70,7 @@ .cover-title John Smith - .cover-desc + .cover-desc.cgray = lorem .cover-controls diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 11e83ddfe64..c357207054b 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -77,3 +77,4 @@ = render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id') = render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id') + = render_if_exists 'layouts/snowplow' diff --git a/app/views/layouts/_mailer.html.haml b/app/views/layouts/_mailer.html.haml index e13490ed410..6e8294d6adc 100644 --- a/app/views/layouts/_mailer.html.haml +++ b/app/views/layouts/_mailer.html.haml @@ -64,6 +64,8 @@ %tbody = yield + = render_if_exists 'layouts/mailer/additional_text' + %tr.footer %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } %img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/ diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml index 26a1f1e119c..006334ade07 100644 --- a/app/views/layouts/_page.html.haml +++ b/app/views/layouts/_page.html.haml @@ -5,6 +5,7 @@ = render 'shared/outdated_browser' .mobile-overlay .alert-wrapper + = render_if_exists "layouts/header/ee_license_banner" = render "layouts/broadcast" = render "layouts/header/read_only_banner" = render "layouts/nav/classification_level_banner" diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 2f3c13aaf6e..f7a561afbb3 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -26,6 +26,9 @@ - if Gitlab::CurrentSettings.sign_in_text.present? = markdown_field(Gitlab::CurrentSettings.current_application_settings, :sign_in_text) + + = render_if_exists 'layouts/devise_help_text' + .col-sm-5.new-session-forms-container = yield diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 724c9976954..1c1d1ea4645 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -18,8 +18,9 @@ %span.logo-text.d-none.d-lg-block.prepend-left-8 = logo_text - if Gitlab.com? - %span.js-canary-badge.badge.badge-pill.green-badge.align-self-center - = _('Next') + = link_to 'https://next.gitlab.com', class: 'label-link js-canary-badge canary-badge bg-transparent', target: :_blank do + %span.color-label.has-tooltip.badge.badge-pill.green-badge + = _('Next') - if current_user = render "layouts/nav/dashboard" diff --git a/app/views/layouts/header/_help_dropdown.html.haml b/app/views/layouts/header/_help_dropdown.html.haml index fbec62b02f8..5643a508ddc 100644 --- a/app/views/layouts/header/_help_dropdown.html.haml +++ b/app/views/layouts/header/_help_dropdown.html.haml @@ -8,6 +8,7 @@ = link_to _("Submit feedback"), "https://about.gitlab.com/submit-feedback" - if current_user_menu?(:help) || current_user_menu?(:settings) || current_user_menu?(:profile) = render 'shared/user_dropdown_contributing_link' + = render_if_exists 'shared/user_dropdown_instance_review' - if Gitlab.com? %li.js-canary-link = link_to _("Switch to GitLab Next"), "https://next.gitlab.com/" diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb index f8032f3262b..1a06ea68bcd 100644 --- a/app/views/layouts/mailer.text.erb +++ b/app/views/layouts/mailer.text.erb @@ -4,5 +4,6 @@ -- <%# signature marker %> <%= _("You're receiving this email because of your account on %{host}.") % { host: Gitlab.config.gitlab.host } %> +<%= render_if_exists 'layouts/mailer/additional_text' %> <%= text_footer_message %> diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml index 5a27237bf76..47710b9e9e5 100644 --- a/app/views/layouts/nav/_dashboard.html.haml +++ b/app/views/layouts/nav/_dashboard.html.haml @@ -95,3 +95,4 @@ = link_to sherlock_transactions_path, class: 'admin-icon d-none d-lg-block d-xl-block', title: _('Sherlock Transactions'), data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = icon('tachometer fw') + = render_if_exists 'layouts/nav/geo_primary_node_url' diff --git a/app/views/layouts/nav/sidebar/_admin.html.haml b/app/views/layouts/nav/sidebar/_admin.html.haml index 04d67e024ba..83fe871285a 100644 --- a/app/views/layouts/nav/sidebar/_admin.html.haml +++ b/app/views/layouts/nav/sidebar/_admin.html.haml @@ -48,7 +48,7 @@ %span = _('Gitaly Servers') - = nav_link(controller: %w(system_info background_jobs logs health_check requests_profiles)) do + = nav_link(controller: admin_monitoring_nav_links) do = link_to admin_system_info_path do .nav-icon-container = sprite_icon('monitor') @@ -81,6 +81,7 @@ = link_to admin_requests_profiles_path, title: _('Requests Profiles') do %span = _('Requests Profiles') + = render_if_exists 'layouts/nav/ee/admin/new_monitoring_sidebar' = nav_link(controller: :broadcast_messages) do = link_to admin_broadcast_messages_path do @@ -132,6 +133,8 @@ = _('Abuse Reports') %span.badge.badge-pill.count.merge_counter.js-merge-counter.fly-out-badge= number_with_delimiter(AbuseReport.count(:all)) + = render_if_exists 'layouts/nav/sidebar/licenses_link' + - if instance_clusters_enabled? = nav_link(controller: :clusters) do = link_to admin_clusters_path do @@ -158,6 +161,10 @@ %strong.fly-out-top-item-name = _('Spam Logs') + = render_if_exists 'layouts/nav/sidebar/push_rules_link' + + = render_if_exists 'layouts/nav/ee/admin/geo_sidebar' + = nav_link(controller: :deploy_keys) do = link_to admin_deploy_keys_path do .nav-icon-container diff --git a/app/views/layouts/nav/sidebar/_group.html.haml b/app/views/layouts/nav/sidebar/_group.html.haml index c2116ec63dd..0fc5ebbea7e 100644 --- a/app/views/layouts/nav/sidebar/_group.html.haml +++ b/app/views/layouts/nav/sidebar/_group.html.haml @@ -1,6 +1,5 @@ - issues_count = group_issues_count(state: 'opened') - merge_requests_count = group_merge_requests_count(state: 'opened') -- issues_sub_menu_items = ['groups#issues', 'labels#index', 'milestones#index', 'boards#index', 'boards#show'] .nav-sidebar{ class: ("sidebar-collapsed-desktop" if collapsed_sidebar?) } .nav-sidebar-inner-scroll @@ -51,7 +50,7 @@ = render_if_exists "layouts/nav/ee/epic_link", group: @group - if group_sidebar_link?(:issues) - = nav_link(path: issues_sub_menu_items) do + = nav_link(path: group_issues_sub_menu_items) do = link_to issues_group_path(@group) do .nav-icon-container = sprite_icon('issues') diff --git a/app/views/layouts/nav/sidebar/_profile.html.haml b/app/views/layouts/nav/sidebar/_profile.html.haml index 2061eac917f..7dd33f3c641 100644 --- a/app/views/layouts/nav/sidebar/_profile.html.haml +++ b/app/views/layouts/nav/sidebar/_profile.html.haml @@ -28,6 +28,8 @@ = link_to profile_account_path do %strong.fly-out-top-item-name = _('Account') + + = render_if_exists 'layouts/nav/sidebar/profile_billing_link' = nav_link(controller: 'oauth/applications') do = link_to applications_profile_path do .nav-icon-container @@ -151,4 +153,6 @@ %strong.fly-out-top-item-name = _('Authentication Log') + = render_if_exists 'layouts/nav/sidebar/profile_pipeline_quota_link' + = render 'shared/sidebar_toggle_button' diff --git a/app/views/layouts/nav/sidebar/_project.html.haml b/app/views/layouts/nav/sidebar/_project.html.haml index 3a0c2b9c284..399305baec1 100644 --- a/app/views/layouts/nav/sidebar/_project.html.haml +++ b/app/views/layouts/nav/sidebar/_project.html.haml @@ -270,6 +270,8 @@ %span= _("Got it!") = sprite_icon('thumb-up') + = render_if_exists 'layouts/nav/sidebar/project_feature_flags_link' + - if project_nav_tab? :container_registry = nav_link(controller: %w[projects/registry/repositories]) do = link_to project_container_registry_index_path(@project), class: 'shortcuts-container-registry' do @@ -283,7 +285,9 @@ %strong.fly-out-top-item-name = _('Registry') - - if project_nav_tab?(:wiki) + = render_if_exists 'layouts/nav/sidebar/project_packages_link' + + - if project_nav_tab? :wiki - wiki_url = project_wiki_path(@project, :home) = nav_link(controller: :wikis) do = link_to wiki_url, class: 'shortcuts-wiki qa-wiki-link' do diff --git a/app/views/layouts/notify.html.haml b/app/views/layouts/notify.html.haml index 8dff12c1b7f..de487a94d40 100644 --- a/app/views/layouts/notify.html.haml +++ b/app/views/layouts/notify.html.haml @@ -31,4 +31,6 @@ adjust your notification settings. = email_action @target_url + + = render_if_exists 'layouts/email_additional_text' = html_footer_message diff --git a/app/views/layouts/notify.text.erb b/app/views/layouts/notify.text.erb index 248916fba63..0ee30c2a6cf 100644 --- a/app/views/layouts/notify.text.erb +++ b/app/views/layouts/notify.text.erb @@ -12,5 +12,6 @@ <% end -%> <%= "You're receiving this email because #{notification_reason_text(@reason)}." %> +<%= render_if_exists 'layouts/mailer/additional_text' %> <%= text_footer_message -%> diff --git a/app/views/notify/closed_issue_email.html.haml b/app/views/notify/closed_issue_email.html.haml index eb148d72da1..f21cf1ad34b 100644 --- a/app/views/notify/closed_issue_email.html.haml +++ b/app/views/notify/closed_issue_email.html.haml @@ -1,2 +1,2 @@ %p - Issue was closed by #{sanitize_name(@updated_by.name)} + Issue was closed by #{sanitize_name(@updated_by.name)} #{closure_reason_text(@closed_via, format: formats.first)}. diff --git a/app/views/notify/closed_issue_email.text.haml b/app/views/notify/closed_issue_email.text.haml index b1f0a3f37ec..5567adc9165 100644 --- a/app/views/notify/closed_issue_email.text.haml +++ b/app/views/notify/closed_issue_email.text.haml @@ -1,3 +1,3 @@ -Issue was closed by #{sanitize_name(@updated_by.name)} +Issue was closed by #{sanitize_name(@updated_by.name)} #{closure_reason_text(@closed_via, format: formats.first)}. Issue ##{@issue.iid}: #{project_issue_url(@issue.project, @issue)} diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml index b72f0e39b23..b2dab0b5348 100644 --- a/app/views/projects/_flash_messages.html.haml +++ b/app/views/projects/_flash_messages.html.haml @@ -7,3 +7,4 @@ = render 'shared/no_password' - unless project.empty_repo? = render 'shared/auto_devops_implicitly_enabled_banner', project: project + = render_if_exists 'projects/above_size_limit_warning', project: project diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index 91c51d5e091..0e15f581ddc 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -10,7 +10,7 @@ .branch-info .branch-title = sprite_icon('fork', size: 12) - = link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name prepend-left-8' do + = link_to project_tree_path(@project, branch.name), class: 'item-title str-truncated-100 ref-name prepend-left-8 qa-branch-name' do = branch.name - if branch.name == @repository.root_ref %span.badge.badge-primary.prepend-left-5 default diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index 43f1cd01b67..d270e461ac8 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -1,5 +1,6 @@ - @no_container = true - page_title _('Branches') +- add_to_breadcrumbs(_('Repository'), project_tree_path(@project)) %div{ class: container_class } .top-area.adjust @@ -44,6 +45,8 @@ = link_to new_project_branch_path(@project), class: 'btn btn-success' do = s_('Branches|New branch') + = render_if_exists 'projects/commits/mirror_status' + - if can?(current_user, :admin_project, @project) - project_settings_link = link_to s_('Branches|project settings'), project_protected_branches_path(@project) .row-content-block diff --git a/app/views/projects/project_members/_new_project_member.html.haml b/app/views/projects/project_members/_new_project_member.html.haml index 0590578c3fe..efabb7f7b19 100644 --- a/app/views/projects/project_members/_new_project_member.html.haml +++ b/app/views/projects/project_members/_new_project_member.html.haml @@ -19,4 +19,5 @@ = text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date' %i.clear-icon.js-clear-input = f.submit _("Add to project"), class: "btn btn-success qa-add-member-button" - = link_to _("Import"), import_project_project_members_path(@project), class: "btn btn-default", title: _("Import members from another project") + - if can_import_members? + = link_to _("Import"), import_project_project_members_path(@project), class: "btn btn-default", title: _("Import members from another project") diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index a2df0347fd6..1e509ea0d1f 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -16,7 +16,12 @@ = ssh_clone_button(project) %li = http_clone_button(project) + = render_if_exists 'shared/kerberos_clone_button', project: project = text_field_tag :project_clone, default_url_to_repo(project), class: "js-select-on-focus form-control", readonly: true, aria: { label: 'Project clone URL' } .input-group-append = clipboard_button(target: '#project_clone', title: _("Copy URL to clipboard"), class: "input-group-text btn-default btn-clipboard") + + = render_if_exists 'shared/geo_modal_button' + += render_if_exists 'shared/geo_modal', project: project diff --git a/app/views/shared/members/_member.html.haml b/app/views/shared/members/_member.html.haml index 2e5747121b6..2db1f67a793 100644 --- a/app/views/shared/members/_member.html.haml +++ b/app/views/shared/members/_member.html.haml @@ -53,7 +53,7 @@ = time_ago_with_tooltip(member.created_at) - if show_roles - current_resource = @project || @group - .controls.member-controls.row + .controls.member-controls - if show_controls && member.source == current_resource - if member.can_resend_invite? diff --git a/app/views/users/calendar_activities.html.haml b/app/views/users/calendar_activities.html.haml index 01acbf8eadd..3191eaa1e2c 100644 --- a/app/views/users/calendar_activities.html.haml +++ b/app/views/users/calendar_activities.html.haml @@ -9,7 +9,7 @@ %i.fa.fa-clock-o = event.created_at.to_time.in_time_zone.strftime('%-I:%M%P') - if event.visible_to_user?(current_user) - - if event.push? + - if event.push_action? #{event.action_name} #{event.ref_type} %strong - commits_path = project_commits_path(event.project, event.ref_name) diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 211e3eafac6..6dc61088e65 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -45,7 +45,7 @@ = emoji_icon(@user.status.emoji) = markdown_field(@user.status, :message) - .cover-desc.member-date + .cover-desc.member-date.cgray %p %span.middle-dot-divider @#{@user.username} @@ -53,7 +53,7 @@ %span.middle-dot-divider = s_('Member since %{date}') % { date: @user.created_at.to_date.to_s(:long) } - .cover-desc + .cover-desc.cgray - unless @user.public_email.blank? .profile-link-holder.middle-dot-divider = link_to @user.public_email, "mailto:#{@user.public_email}", class: 'text-link' @@ -82,7 +82,7 @@ = @user.organization - if @user.bio.present? - .cover-desc + .cover-desc.cgray %p.profile-user-bio = @user.bio diff --git a/app/workers/process_commit_worker.rb b/app/workers/process_commit_worker.rb index 29a7f8e691a..3efb5343a96 100644 --- a/app/workers/process_commit_worker.rb +++ b/app/workers/process_commit_worker.rb @@ -48,7 +48,7 @@ class ProcessCommitWorker # Issues::CloseService#execute. IssueCollection.new(issues).updatable_by_user(user).each do |issue| Issues::CloseService.new(project, author) - .close_issue(issue, commit: commit) + .close_issue(issue, closed_via: commit) end end |