summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/diffs/components/app.vue2
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions.vue12
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue16
-rw-r--r--app/assets/javascripts/diffs/components/diff_stats.vue23
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue9
-rw-r--r--app/assets/javascripts/vue_shared/components/changed_file_icon.vue11
-rw-r--r--app/assets/javascripts/vue_shared/components/file_row.vue11
-rw-r--r--app/assets/stylesheets/pages/diff.scss15
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss4
-rw-r--r--app/models/user.rb5
-rw-r--r--app/policies/project_policy.rb1
-rw-r--r--app/services/error_tracking/base_service.rb8
-rw-r--r--app/services/error_tracking/issue_details_service.rb2
-rw-r--r--app/services/error_tracking/issue_latest_event_service.rb2
-rw-r--r--app/services/error_tracking/issue_update_service.rb58
-rw-r--r--app/services/error_tracking/list_issues_service.rb2
-rw-r--r--app/services/error_tracking/list_projects_service.rb2
-rw-r--r--app/services/pages_domains/create_acme_order_service.rb5
-rw-r--r--app/services/system_note_service.rb6
-rw-r--r--app/services/users/build_service.rb2
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