diff options
Diffstat (limited to 'app')
20 files changed, 127 insertions, 69 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 878b54f7d53..463d1427805 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -374,7 +374,7 @@ export default { <div :data-can-create-note="getNoteableData.current_user.can_create_note" - class="files d-flex" + class="files d-flex prepend-top-default" > <div v-show="showTreeList" diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue index 63ce43a193d..24542126b07 100644 --- a/app/assets/javascripts/diffs/components/compare_versions.vue +++ b/app/assets/javascripts/diffs/components/compare_versions.vue @@ -1,4 +1,5 @@ <script> +/* eslint-disable @gitlab/vue-i18n/no-bare-strings */ import { mapActions, mapGetters, mapState } from 'vuex'; import { GlTooltipDirective, GlLink, GlButton } from '@gitlab/ui'; import { __ } from '~/locale'; @@ -62,6 +63,9 @@ export default { showDropdowns() { return !this.commit && this.mergeRequestDiffs.length; }, + fileTreeIcon() { + return this.showTreeList ? 'collapse-left' : 'expand-left'; + }, toggleFileBrowserTitle() { return this.showTreeList ? __('Hide file browser') : __('Show file browser'); }, @@ -87,7 +91,7 @@ export default { </script> <template> - <div class="mr-version-controls border-top"> + <div class="mr-version-controls border-top border-bottom"> <div class="mr-version-menus-container content-block" :class="{ @@ -104,17 +108,17 @@ export default { :title="toggleFileBrowserTitle" @click="toggleShowTreeList" > - <icon name="file-tree" /> + <icon :name="fileTreeIcon" /> </button> <div v-if="showDropdowns" class="d-flex align-items-center compare-versions-container"> - {{ __('Compare') }} + Changes between <compare-versions-dropdown :other-versions="mergeRequestDiffs" :merge-request-version="mergeRequestDiff" :show-commit-count="true" class="mr-version-dropdown" /> - {{ __('and') }} + and <compare-versions-dropdown :other-versions="comparableDiffs" :base-version-path="baseVersionPath" diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index e78bea789c3..5d27c6eb865 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -123,20 +123,6 @@ export default { } return s__('MRDiff|Show full file'); }, - changedFile() { - const { - new_path: changed, - deleted_file: deleted, - new_file: tempFile, - ...diffFile - } = this.diffFile; - return { - ...diffFile, - changed: Boolean(changed), - deleted, - tempFile, - }; - }, }, mounted() { polyfillSticky(this.$refs.header); @@ -235,7 +221,7 @@ export default { <div v-if="!diffFile.submodule && addMergeRequestButtons" - class="file-actions d-none d-sm-flex align-items-center" + class="file-actions d-none d-sm-block" > <diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" /> <div class="btn-group" role="group"> diff --git a/app/assets/javascripts/diffs/components/diff_stats.vue b/app/assets/javascripts/diffs/components/diff_stats.vue index 1fa1fda7bd7..2e5855380af 100644 --- a/app/assets/javascripts/diffs/components/diff_stats.vue +++ b/app/assets/javascripts/diffs/components/diff_stats.vue @@ -1,7 +1,9 @@ <script> +import Icon from '~/vue_shared/components/icon.vue'; import { n__ } from '~/locale'; export default { + components: { Icon }, props: { addedLines: { type: Number, @@ -19,7 +21,7 @@ export default { }, computed: { filesText() { - return n__('file', 'files', this.diffFilesLength); + return n__('File', 'Files', this.diffFilesLength); }, isCompareVersionsHeader() { return Boolean(this.diffFilesLength); @@ -37,21 +39,14 @@ export default { }" > <div v-if="diffFilesLength !== null" class="diff-stats-group"> - <span class="text-secondary bold">{{ diffFilesLength }} {{ filesText }}</span> + <icon name="doc-code" class="diff-stats-icon text-secondary" /> + <strong>{{ diffFilesLength }} {{ filesText }}</strong> </div> - <div - class="diff-stats-group cgreen d-flex align-items-center" - :class="{ bold: isCompareVersionsHeader }" - > - <span>+</span> - <span class="js-file-addition-line">{{ addedLines }}</span> + <div class="diff-stats-group cgreen"> + <icon name="file-addition" class="diff-stats-icon" /> <strong>{{ addedLines }}</strong> </div> - <div - class="diff-stats-group cred d-flex align-items-center" - :class="{ bold: isCompareVersionsHeader }" - > - <span>-</span> - <span class="js-file-deletion-line">{{ removedLines }}</span> + <div class="diff-stats-group cred"> + <icon name="file-deletion" class="diff-stats-icon" /> <strong>{{ removedLines }}</strong> </div> </div> </template> diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue index 7956d05b4f1..30be2e68e76 100644 --- a/app/assets/javascripts/diffs/components/tree_list.vue +++ b/app/assets/javascripts/diffs/components/tree_list.vue @@ -4,6 +4,7 @@ import { GlTooltipDirective } from '@gitlab/ui'; import { s__, sprintf } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import FileRow from '~/vue_shared/components/file_row.vue'; +import FileRowStats from './file_row_stats.vue'; export default { directives: { @@ -47,6 +48,9 @@ export default { return acc; }, []); }, + fileRowExtraComponent() { + return this.hideFileStats ? null : FileRowStats; + }, }, methods: { ...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']), @@ -54,8 +58,8 @@ export default { this.search = ''; }, }, - searchPlaceholder: sprintf(s__('MergeRequest|Search files (%{modifier_key}P)'), { - modifier_key: /Mac/i.test(navigator.userAgent) ? '⌘' : 'Ctrl+', + searchPlaceholder: sprintf(s__('MergeRequest|Filter files or search with %{modifier_key}+p'), { + modifier_key: /Mac/i.test(navigator.userAgent) ? 'cmd' : 'ctrl', }), }; </script> @@ -93,6 +97,7 @@ export default { :file="file" :level="0" :hide-extra-on-tree="true" + :extra-component="fileRowExtraComponent" :show-changed-icon="true" @toggleTreeOpen="toggleTreeOpen" @clickFile="scrollToFile" diff --git a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue index 09cffc57688..75c3c544c77 100644 --- a/app/assets/javascripts/vue_shared/components/changed_file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/changed_file_icon.vue @@ -36,17 +36,12 @@ export default { required: false, default: true, }, - showChangedStatus: { - type: Boolean, - required: false, - default: false, - }, }, computed: { changedIcon() { // False positive i18n lint: https://gitlab.com/gitlab-org/frontend/eslint-plugin-i18n/issues/26 // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings - const suffix = this.showStagedIcon ? '-solid' : ''; + const suffix = !this.file.changed && this.file.staged && this.showStagedIcon ? '-solid' : ''; return `${getCommitIconMap(this.file).icon}${suffix}`; }, @@ -91,8 +86,8 @@ export default { <span v-gl-tooltip.right :title="tooltipTitle" - :class="[{ 'ml-auto': isCentered }, changedIconClass]" - class="file-changed-icon d-flex align-items-center " + :class="{ 'ml-auto': isCentered }" + class="file-changed-icon d-inline-block" > <icon v-if="showIcon" :name="changedIcon" :size="size" :class="changedIconClass" /> </span> diff --git a/app/assets/javascripts/vue_shared/components/file_row.vue b/app/assets/javascripts/vue_shared/components/file_row.vue index 0c9f6ea94d5..611001df32f 100644 --- a/app/assets/javascripts/vue_shared/components/file_row.vue +++ b/app/assets/javascripts/vue_shared/components/file_row.vue @@ -1,4 +1,5 @@ <script> +import Icon from '~/vue_shared/components/icon.vue'; import FileHeader from '~/vue_shared/components/file_row_header.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue'; import ChangedFileIcon from '~/vue_shared/components/changed_file_icon.vue'; @@ -8,6 +9,7 @@ export default { components: { FileHeader, FileIcon, + Icon, ChangedFileIcon, }, props: { @@ -24,7 +26,6 @@ export default { required: false, default: null, }, - hideExtraOnTree: { type: Boolean, required: false, @@ -142,17 +143,17 @@ export default { @mouseleave="toggleDropdown(false)" > <div class="file-row-name-container"> - <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated d-flex"> + <span ref="textOutput" :style="levelIndentation" class="file-row-name str-truncated"> <file-icon v-if="!showChangedIcon || file.type === 'tree'" - class="file-row-icon text-secondary mr-1" + class="file-row-icon" :file-name="file.name" :loading="file.loading" :folder="isTree" :opened="file.opened" :size="16" /> - <file-icon v-else :file-name="file.name" :size="16" css-classes="top mr-1" /> + <changed-file-icon v-else :file="file" :size="16" class="append-right-5" /> {{ file.name }} </span> <component @@ -162,7 +163,6 @@ export default { :dropdown-open="dropdownOpen" @toggle="toggleDropdown($event)" /> - <changed-file-icon :file="file" :size="16" class="append-right-5" /> </div> </div> <template v-if="file.opened || file.isHeader"> @@ -172,6 +172,7 @@ export default { :file="childFile" :level="childFilesLevel" :hide-extra-on-tree="hideExtraOnTree" + :extra-component="extraComponent" :show-changed-icon="showChangedIcon" @toggleTreeOpen="toggleTreeOpen" @clickFile="clickedFile" diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index d1053570093..f394e4ab58a 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -14,9 +14,9 @@ cursor: pointer; @media (min-width: map-get($grid-breakpoints, md)) { - // The `+11` is to ensure the file header border shows when scrolled - + // The `-1` below is to prevent two borders from clashing up against eachother - // the bottom of the compare-versions header and the top of the file header - $mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height + 11; + $mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height - 1; position: -webkit-sticky; position: sticky; @@ -552,7 +552,7 @@ table.code { .diff-stats { align-items: center; - padding: 0 1rem; + padding: 0 0.25rem; .diff-stats-group { padding: 0 0.25rem; @@ -564,7 +564,7 @@ table.code { &.is-compare-versions-header { .diff-stats-group { - padding: 0 0.25rem; + padding: 0 0.5rem; } } } @@ -1059,8 +1059,8 @@ table.code { .diff-tree-list { position: -webkit-sticky; position: sticky; - $top-pos: $header-height + $mr-tabs-height + $mr-version-controls-height + 11px; - top: $header-height + $mr-tabs-height + $mr-version-controls-height + 11px; + $top-pos: $header-height + $mr-tabs-height + $mr-version-controls-height + 10px; + top: $header-height + $mr-tabs-height + $mr-version-controls-height + 10px; max-height: calc(100vh - #{$top-pos}); z-index: 202; @@ -1097,7 +1097,10 @@ table.code { .tree-list-scroll { max-height: 100%; + padding-top: $grid-size; padding-bottom: $grid-size; + border-top: 1px solid $border-color; + border-bottom: 1px solid $border-color; overflow-y: scroll; overflow-x: auto; } diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss index 84daec4fb43..c023c9e5cbd 100644 --- a/app/assets/stylesheets/pages/merge_requests.scss +++ b/app/assets/stylesheets/pages/merge_requests.scss @@ -708,7 +708,7 @@ .mr-version-controls { position: relative; z-index: 203; - background: $white-light; + background: $gray-light; color: $gl-text-color; margin-top: -1px; @@ -732,7 +732,7 @@ } .content-block { - padding: $gl-padding; + padding: $gl-padding-top $gl-padding; border-bottom: 0; } diff --git a/app/models/user.rb b/app/models/user.rb index df54f358ffa..df6c28f5076 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -394,6 +394,11 @@ class User < ApplicationRecord Gitlab::CurrentSettings.minimum_password_length..Devise.password_length.max end + # Generate a random password that conforms to the current password length settings + def random_password + Devise.friendly_token(password_length.max) + end + # Devise method overridden to allow sign in with email or username def find_for_database_authentication(warden_conditions) conditions = warden_conditions.dup diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index e38eef527be..2789152e175 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -222,6 +222,7 @@ class ProjectPolicy < BasePolicy enable :read_deployment enable :read_merge_request enable :read_sentry_issue + enable :update_sentry_issue enable :read_prometheus end diff --git a/app/services/error_tracking/base_service.rb b/app/services/error_tracking/base_service.rb index 430d9952332..4fe01716704 100644 --- a/app/services/error_tracking/base_service.rb +++ b/app/services/error_tracking/base_service.rb @@ -7,7 +7,7 @@ module ErrorTracking return unauthorized if unauthorized begin - response = fetch + response = perform rescue Sentry::Client::Error => e return error(e.message, :bad_request) rescue Sentry::Client::MissingKeysError => e @@ -22,7 +22,7 @@ module ErrorTracking private - def fetch + def perform raise NotImplementedError, "#{self.class} does not implement #{__method__}" end @@ -62,5 +62,9 @@ module ErrorTracking def can_read? can?(current_user, :read_sentry_issue, project) end + + def can_update? + can?(current_user, :update_sentry_issue, project) + end end end diff --git a/app/services/error_tracking/issue_details_service.rb b/app/services/error_tracking/issue_details_service.rb index 368cd4517fc..31fb6a9618c 100644 --- a/app/services/error_tracking/issue_details_service.rb +++ b/app/services/error_tracking/issue_details_service.rb @@ -4,7 +4,7 @@ module ErrorTracking class IssueDetailsService < ErrorTracking::BaseService private - def fetch + def perform project_error_tracking_setting.issue_details(issue_id: params[:issue_id]) end diff --git a/app/services/error_tracking/issue_latest_event_service.rb b/app/services/error_tracking/issue_latest_event_service.rb index b6ad8f8028b..dd6b7f8285f 100644 --- a/app/services/error_tracking/issue_latest_event_service.rb +++ b/app/services/error_tracking/issue_latest_event_service.rb @@ -4,7 +4,7 @@ module ErrorTracking class IssueLatestEventService < ErrorTracking::BaseService private - def fetch + def perform project_error_tracking_setting.issue_latest_event(issue_id: params[:issue_id]) end diff --git a/app/services/error_tracking/issue_update_service.rb b/app/services/error_tracking/issue_update_service.rb index e433b4a11f2..db754d54fef 100644 --- a/app/services/error_tracking/issue_update_service.rb +++ b/app/services/error_tracking/issue_update_service.rb @@ -4,6 +4,16 @@ module ErrorTracking class IssueUpdateService < ErrorTracking::BaseService private + def perform + response = fetch + + unless parse_errors(response).present? + response[:closed_issue_iid] = update_related_issue&.iid + end + + response + end + def fetch project_error_tracking_setting.update_issue( issue_id: params[:issue_id], @@ -11,12 +21,58 @@ module ErrorTracking ) end + def update_related_issue + issue = related_issue + return unless issue + + close_and_create_note(issue) + end + + def close_and_create_note(issue) + return unless resolving? && issue.opened? + + processed_issue = close_issue(issue) + return unless processed_issue.reset.closed? + + create_system_note(processed_issue) + processed_issue + end + + def close_issue(issue) + Issues::CloseService + .new(project, current_user) + .execute(issue, system_note: false) + end + + def create_system_note(issue) + SystemNoteService.close_after_error_tracking_resolve(issue, project, current_user) + end + + def related_issue + SentryIssueFinder + .new(project, current_user: current_user) + .execute(params[:issue_id]) + &.issue + end + + def resolving? + update_params[:status] == 'resolved' + end + def update_params params.except(:issue_id) end def parse_response(response) - { updated: response[:updated].present? } + { + updated: response[:updated].present?, + closed_issue_iid: response[:closed_issue_iid] + } + end + + def check_permissions + return error('Error Tracking is not enabled') unless enabled? + return error('Access denied', :unauthorized) unless can_update? end end end diff --git a/app/services/error_tracking/list_issues_service.rb b/app/services/error_tracking/list_issues_service.rb index 132e9dfa7bd..d34ea8aa3b0 100644 --- a/app/services/error_tracking/list_issues_service.rb +++ b/app/services/error_tracking/list_issues_service.rb @@ -12,7 +12,7 @@ module ErrorTracking private - def fetch + def perform project_error_tracking_setting.list_sentry_issues( issue_status: issue_status, limit: limit, diff --git a/app/services/error_tracking/list_projects_service.rb b/app/services/error_tracking/list_projects_service.rb index 09a0b952e84..6523a66bbed 100644 --- a/app/services/error_tracking/list_projects_service.rb +++ b/app/services/error_tracking/list_projects_service.rb @@ -12,7 +12,7 @@ module ErrorTracking private - def fetch + def perform project_error_tracking_setting.list_sentry_projects end diff --git a/app/services/pages_domains/create_acme_order_service.rb b/app/services/pages_domains/create_acme_order_service.rb index 8eab5c52432..c600f497fa5 100644 --- a/app/services/pages_domains/create_acme_order_service.rb +++ b/app/services/pages_domains/create_acme_order_service.rb @@ -3,9 +3,6 @@ module PagesDomains class CreateAcmeOrderService attr_reader :pages_domain - # TODO: remove this hack after https://gitlab.com/gitlab-org/gitlab/issues/30146 is implemented - # This makes GitLab automatically retry the certificate obtaining process every 2 hours if process wasn't finished - SHORT_EXPIRATION_DELAY = 2.hours def initialize(pages_domain) @pages_domain = pages_domain @@ -20,7 +17,7 @@ module PagesDomains private_key = OpenSSL::PKey::RSA.new(4096) saved_order = pages_domain.acme_orders.create!( url: order.url, - expires_at: [order.expires, SHORT_EXPIRATION_DELAY.from_now].min, + expires_at: order.expires, private_key: private_key.to_pem, challenge_token: challenge.token, diff --git a/app/services/system_note_service.rb b/app/services/system_note_service.rb index 38e0a7d34ad..033c80fd8ed 100644 --- a/app/services/system_note_service.rb +++ b/app/services/system_note_service.rb @@ -99,6 +99,12 @@ module SystemNoteService ::SystemNotes::TimeTrackingService.new(noteable: noteable, project: project, author: author).change_time_spent end + def close_after_error_tracking_resolve(issue, project, author) + body = _('resolved the corresponding error and closed the issue.') + + create_note(NoteSummary.new(issue, project, author, body, action: 'closed')) + end + def change_status(noteable, project, author, status, source = nil) ::SystemNotes::IssuablesService.new(noteable: noteable, project: project, author: author).change_status(status, source) end diff --git a/app/services/users/build_service.rb b/app/services/users/build_service.rb index d18f20bc1db..56631bf2785 100644 --- a/app/services/users/build_service.rb +++ b/app/services/users/build_service.rb @@ -23,7 +23,7 @@ module Users @reset_token = user.generate_reset_token if params[:reset_password] if user_params[:force_random_password] - random_password = Devise.friendly_token.first(User.password_length.min) + random_password = User.random_password user.password = user.password_confirmation = random_password end end |