diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-18 12:07:48 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-18 12:07:48 +0000 |
commit | 79d62647bcfad69d7272020acb7d8be5ee5df003 (patch) | |
tree | 008d96a4c5fdfdecda79dae5e942c7df07511c77 /app | |
parent | 1a9d9cc14ec54036548824e3ce17da03960f5f81 (diff) | |
download | gitlab-ce-79d62647bcfad69d7272020acb7d8be5ee5df003.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r-- | app/assets/javascripts/commit/image_file.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/due_date_select.js | 4 | ||||
-rw-r--r-- | app/assets/javascripts/error_tracking/components/error_tracking_list.vue | 238 | ||||
-rw-r--r-- | app/assets/javascripts/filterable_list.js | 2 | ||||
-rw-r--r-- | app/assets/javascripts/labels_select.js | 5 | ||||
-rw-r--r-- | app/assets/javascripts/main.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/milestone_select.js | 7 | ||||
-rw-r--r-- | app/assets/javascripts/notes/components/comment_form.vue | 1 | ||||
-rw-r--r-- | app/assets/javascripts/users_select.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/vue_shared/components/markdown/field.vue | 20 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/error_list.scss | 69 | ||||
-rw-r--r-- | app/models/blob.rb | 1 | ||||
-rw-r--r-- | app/models/blob_viewer/cargo_toml.rb | 17 | ||||
-rw-r--r-- | app/models/ci/build.rb | 8 | ||||
-rw-r--r-- | app/models/diff_note.rb | 40 | ||||
-rw-r--r-- | app/serializers/build_artifact_entity.rb | 2 | ||||
-rw-r--r-- | app/serializers/build_details_entity.rb | 2 | ||||
-rw-r--r-- | app/views/shared/_auto_devops_callout.html.haml | 15 |
18 files changed, 314 insertions, 124 deletions
diff --git a/app/assets/javascripts/commit/image_file.js b/app/assets/javascripts/commit/image_file.js index a28e17f7a56..fb8b1c17407 100644 --- a/app/assets/javascripts/commit/image_file.js +++ b/app/assets/javascripts/commit/image_file.js @@ -40,7 +40,10 @@ export default class ImageFile { .removeClass('active') .filter(`.${viewMode}`) .addClass('active'); + + // eslint-disable-next-line no-jquery/no-fade return $(`.view:visible:not(.${viewMode})`, this.file).fadeOut(200, () => { + // eslint-disable-next-line no-jquery/no-fade $(`.view.${viewMode}`, this.file).fadeIn(200); return this.initView(viewMode); }); diff --git a/app/assets/javascripts/due_date_select.js b/app/assets/javascripts/due_date_select.js index 3c650397a19..b973316b3b9 100644 --- a/app/assets/javascripts/due_date_select.js +++ b/app/assets/javascripts/due_date_select.js @@ -116,11 +116,13 @@ class DueDateSelect { } updateIssueBoardIssue() { + // eslint-disable-next-line no-jquery/no-fade this.$loading.fadeIn(); this.$dropdown.trigger('loading.gl.dropdown'); this.$selectbox.hide(); this.$value.css('display', ''); const fadeOutLoader = () => { + // eslint-disable-next-line no-jquery/no-fade this.$loading.fadeOut(); }; @@ -135,6 +137,7 @@ class DueDateSelect { const hasDueDate = this.displayedDate !== __('None'); const displayedDateStyle = hasDueDate ? 'bold' : 'no-value'; + // eslint-disable-next-line no-jquery/no-fade this.$loading.removeClass('hidden').fadeIn(); if (isDropdown) { @@ -158,6 +161,7 @@ class DueDateSelect { } this.$sidebarCollapsedValue.attr('data-original-title', tooltipText); + // eslint-disable-next-line no-jquery/no-fade return this.$loading.fadeOut(); }); } diff --git a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue index 8e2128ac713..1042029b6db 100644 --- a/app/assets/javascripts/error_tracking/components/error_tracking_list.vue +++ b/app/assets/javascripts/error_tracking/components/error_tracking_list.vue @@ -25,10 +25,33 @@ export default { PREV_PAGE: 1, NEXT_PAGE: 2, fields: [ - { key: 'error', label: __('Open errors'), thClass: 'w-70p' }, - { key: 'events', label: __('Events') }, - { key: 'users', label: __('Users') }, - { key: 'lastSeen', label: __('Last seen'), thClass: 'w-15p' }, + { + key: 'error', + label: __('Error'), + thClass: 'w-70p', + tdClass: 'table-col d-flex align-items-center d-sm-table-cell', + }, + { + key: 'events', + label: __('Events'), + tdClass: 'table-col d-flex align-items-center d-sm-table-cell', + }, + { + key: 'users', + label: __('Users'), + tdClass: 'table-col d-flex align-items-center d-sm-table-cell', + }, + { + key: 'lastSeen', + label: __('Last seen'), + thClass: 'w-15p', + tdClass: 'table-col d-flex align-items-center d-sm-table-cell', + }, + { + key: 'details', + tdClass: 'table-col d-sm-none d-flex align-items-center', + thClass: 'invisible w-0', + }, ], sortFields: { last_seen: __('Last Seen'), @@ -149,61 +172,63 @@ export default { <div class="error-list"> <div v-if="errorTrackingEnabled"> <div - class="d-flex flex-row justify-content-around align-items-center bg-secondary border mt-2" + class="row flex-column flex-sm-row align-items-sm-center row-top m-0 mt-sm-2 mx-sm-1 p-0 p-sm-3" > - <div class="filtered-search-box flex-grow-1 my-3 ml-3 mr-2"> - <gl-dropdown - :text="__('Recent searches')" - class="filtered-search-history-dropdown-wrapper d-none d-md-block" - toggle-class="filtered-search-history-dropdown-toggle-button" - :disabled="loading" - > - <div v-if="!$options.hasLocalStorage" class="px-3"> - {{ __('This feature requires local storage to be enabled') }} - </div> - <template v-else-if="recentSearches.length > 0"> - <gl-dropdown-item - v-for="searchQuery in recentSearches" - :key="searchQuery" - @click="setSearchText(searchQuery)" - >{{ searchQuery }}</gl-dropdown-item - > - <gl-dropdown-divider /> - <gl-dropdown-item ref="clearRecentSearches" @click="clearRecentSearches">{{ - __('Clear recent searches') - }}</gl-dropdown-item> - </template> - <div v-else class="px-3">{{ __("You don't have any recent searches") }}</div> - </gl-dropdown> - <div class="filtered-search-input-container flex-fill"> - <gl-form-input - v-model="errorSearchQuery" - class="pl-2 filtered-search" + <div class="search-box flex-fill mr-sm-2 my-3 m-sm-0 p-3 p-sm-0"> + <div class="filtered-search-box mb-0"> + <gl-dropdown + :text="__('Recent searches')" + class="filtered-search-history-dropdown-wrapper" + toggle-class="filtered-search-history-dropdown-toggle-button" :disabled="loading" - :placeholder="__('Search or filter results…')" - autofocus - @keyup.enter.native="searchByQuery(errorSearchQuery)" - /> - </div> - <div class="gl-search-box-by-type-right-icons"> - <gl-button - v-if="errorSearchQuery.length > 0" - v-gl-tooltip.hover - :title="__('Clear')" - class="clear-search text-secondary" - name="clear" - @click="errorSearchQuery = ''" > - <gl-icon name="close" :size="12" /> - </gl-button> + <div v-if="!$options.hasLocalStorage" class="px-3"> + {{ __('This feature requires local storage to be enabled') }} + </div> + <template v-else-if="recentSearches.length > 0"> + <gl-dropdown-item + v-for="searchQuery in recentSearches" + :key="searchQuery" + @click="setSearchText(searchQuery)" + >{{ searchQuery }} + </gl-dropdown-item> + <gl-dropdown-divider /> + <gl-dropdown-item ref="clearRecentSearches" @click="clearRecentSearches" + >{{ __('Clear recent searches') }} + </gl-dropdown-item> + </template> + <div v-else class="px-3">{{ __("You don't have any recent searches") }}</div> + </gl-dropdown> + <div class="filtered-search-input-container flex-fill"> + <gl-form-input + v-model="errorSearchQuery" + class="pl-2 filtered-search" + :disabled="loading" + :placeholder="__('Search or filter results…')" + autofocus + @keyup.enter.native="searchByQuery(errorSearchQuery)" + /> + </div> + <div class="gl-search-box-by-type-right-icons"> + <gl-button + v-if="errorSearchQuery.length > 0" + v-gl-tooltip.hover + :title="__('Clear')" + class="clear-search text-secondary" + name="clear" + @click="errorSearchQuery = ''" + > + <gl-icon name="close" :size="12" /> + </gl-button> + </div> </div> </div> <gl-dropdown + class="sort-control" :text="$options.sortFields[sortField]" left :disabled="loading" - class="mr-3" menu-class="sort-dropdown" > <gl-dropdown-item @@ -227,62 +252,77 @@ export default { <gl-loading-icon size="md" /> </div> - <gl-table - v-else - class="mt-3" - :items="errors" - :fields="$options.fields" - :show-empty="true" - fixed - stacked="sm" - > - <template slot="HEAD_events" slot-scope="data"> - <div class="text-md-right">{{ data.label }}</div> - </template> - <template slot="HEAD_users" slot-scope="data"> - <div class="text-md-right">{{ data.label }}</div> - </template> - <template slot="error" slot-scope="errors"> - <div class="d-flex flex-column"> - <gl-link class="d-flex text-dark" :href="getDetailsLink(errors.item.id)"> - <strong class="text-truncate">{{ errors.item.title.trim() }}</strong> - </gl-link> - <span class="text-secondary text-truncate"> - {{ errors.item.culprit }} - </span> - </div> - </template> - <template slot="events" slot-scope="errors"> - <div class="text-md-right">{{ errors.item.count }}</div> - </template> + <template v-else> + <h4 class="d-block d-sm-none my-3">{{ __('Open errors') }}</h4> - <template slot="users" slot-scope="errors"> - <div class="text-md-right">{{ errors.item.userCount }}</div> - </template> + <gl-table + class="mt-3" + :items="errors" + :fields="$options.fields" + :show-empty="true" + fixed + stacked="sm" + tbody-tr-class="table-row mb-4" + > + <template v-slot:head(error)> + <div class="d-none d-sm-block">{{ __('Open errors') }}</div> + </template> + <template v-slot:head(events)="data"> + <div class="text-sm-right">{{ data.label }}</div> + </template> + <template v-slot:head(users)="data"> + <div class="text-sm-right">{{ data.label }}</div> + </template> - <template slot="lastSeen" slot-scope="errors"> - <div class="d-flex align-items-center"> - <time-ago :time="errors.item.lastSeen" class="text-secondary" /> - </div> - </template> - <template slot="empty"> - <div ref="empty"> + <template v-slot:error="errors"> + <div class="d-flex flex-column"> + <gl-link class="d-flex mw-100 text-dark" :href="getDetailsLink(errors.item.id)"> + <strong class="text-truncate">{{ errors.item.title.trim() }}</strong> + </gl-link> + <span class="text-secondary text-truncate mw-100"> + {{ errors.item.culprit }} + </span> + </div> + </template> + <template v-slot:events="errors"> + <div class="text-right">{{ errors.item.count }}</div> + </template> + + <template v-slot:users="errors"> + <div class="text-right">{{ errors.item.userCount }}</div> + </template> + + <template v-slot:lastSeen="errors"> + <div class="text-md-left text-right"> + <time-ago :time="errors.item.lastSeen" class="text-secondary" /> + </div> + </template> + <template v-slot:details="errors"> + <gl-button + :href="getDetailsLink(errors.item.id)" + variant="outline-info" + class="d-block" + > + {{ __('More details') }} + </gl-button> + </template> + <template v-slot:empty> {{ __('No errors to display.') }} <gl-link class="js-try-again" @click="restartPolling"> {{ __('Check again') }} </gl-link> - </div> - </template> - </gl-table> - <gl-pagination - v-show="!loading" - v-if="paginationRequired" - :prev-page="$options.PREV_PAGE" - :next-page="$options.NEXT_PAGE" - :value="pageValue" - align="center" - @input="goToPage" - /> + </template> + </gl-table> + <gl-pagination + v-show="!loading" + v-if="paginationRequired" + :prev-page="$options.PREV_PAGE" + :next-page="$options.NEXT_PAGE" + :value="pageValue" + align="center" + @input="goToPage" + /> + </template> </div> <div v-else-if="userCanEnableErrorTracking"> <gl-empty-state diff --git a/app/assets/javascripts/filterable_list.js b/app/assets/javascripts/filterable_list.js index c21fba06d42..be2eee828ff 100644 --- a/app/assets/javascripts/filterable_list.js +++ b/app/assets/javascripts/filterable_list.js @@ -64,6 +64,7 @@ export default class FilterableList { return false; } + // eslint-disable-next-line no-jquery/no-fade $(this.listHolderElement).fadeTo(250, 0.5); this.isBusy = true; @@ -98,6 +99,7 @@ export default class FilterableList { onFilterComplete() { this.isBusy = false; + // eslint-disable-next-line no-jquery/no-fade $(this.listHolderElement).fadeTo(250, 1); } } diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 6abf723be9a..f57febbda37 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -45,6 +45,7 @@ export default class LabelsSelect { const $sidebarLabelTooltip = $block.find('.js-sidebar-labels-tooltip'); const $value = $block.find('.value'); const $dropdownMenu = $dropdown.parent().find('.dropdown-menu'); + // eslint-disable-next-line no-jquery/no-fade const $loading = $block.find('.block-loading').fadeOut(); const fieldName = $dropdown.data('fieldName'); let initialSelected = $selectbox @@ -84,6 +85,7 @@ export default class LabelsSelect { if (!selected.length) { data[abilityName].label_ids = ['']; } + // eslint-disable-next-line no-jquery/no-fade $loading.removeClass('hidden').fadeIn(); $dropdown.trigger('loading.gl.dropdown'); axios @@ -91,6 +93,7 @@ export default class LabelsSelect { .then(({ data }) => { let labelTooltipTitle; let template; + // eslint-disable-next-line no-jquery/no-fade $loading.fadeOut(); $dropdown.trigger('loaded.gl.dropdown'); $selectbox.hide(); @@ -361,6 +364,7 @@ export default class LabelsSelect { const label = clickEvent.selectedObj; const fadeOutLoader = () => { + // eslint-disable-next-line no-jquery/no-fade $loading.fadeOut(); }; @@ -422,6 +426,7 @@ export default class LabelsSelect { boardsStore.detail.issue.labels = labels; } + // eslint-disable-next-line no-jquery/no-fade $loading.fadeIn(); const oldLabels = boardsStore.detail.issue.labels; diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 674415c9d01..8373ddd7a43 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -113,6 +113,7 @@ function deferredInitialisation() { }); $('.js-remove-tr').on('ajax:success', function removeTRAjaxSuccessCallback() { + // eslint-disable-next-line no-jquery/no-fade $(this) .closest('tr') .fadeOut(); diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index 1738dbe439c..d15e4ecb537 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -52,6 +52,7 @@ export default class MilestoneSelect { const $block = $selectBox.closest('.block'); const $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon'); const $value = $block.find('.value'); + // eslint-disable-next-line no-jquery/no-fade const $loading = $block.find('.block-loading').fadeOut(); selectedMilestoneDefault = showAny ? '' : null; selectedMilestoneDefault = @@ -202,15 +203,18 @@ export default class MilestoneSelect { } $dropdown.trigger('loading.gl.dropdown'); + // eslint-disable-next-line no-jquery/no-fade $loading.removeClass('hidden').fadeIn(); boardsStore.detail.issue .update($dropdown.attr('data-issue-update')) .then(() => { $dropdown.trigger('loaded.gl.dropdown'); + // eslint-disable-next-line no-jquery/no-fade $loading.fadeOut(); }) .catch(() => { + // eslint-disable-next-line no-jquery/no-fade $loading.fadeOut(); }); } else { @@ -218,12 +222,14 @@ export default class MilestoneSelect { data = {}; data[abilityName] = {}; data[abilityName].milestone_id = selected != null ? selected : null; + // eslint-disable-next-line no-jquery/no-fade $loading.removeClass('hidden').fadeIn(); $dropdown.trigger('loading.gl.dropdown'); return axios .put(issueUpdateURL, data) .then(({ data }) => { $dropdown.trigger('loaded.gl.dropdown'); + // eslint-disable-next-line no-jquery/no-fade $loading.fadeOut(); $selectBox.hide(); $value.css('display', ''); @@ -247,6 +253,7 @@ export default class MilestoneSelect { } }) .catch(() => { + // eslint-disable-next-line no-jquery/no-fade $loading.fadeOut(); }); } diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index 492d8de3802..4ca32b9b005 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -336,6 +336,7 @@ export default { <markdown-field ref="markdownField" + :is-submitting="isSubmitting" :markdown-preview-path="markdownPreviewPath" :markdown-docs-path="markdownDocsPath" :quick-actions-docs-path="quickActionsDocsPath" diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index bf2880aca9c..6d7d863f273 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -53,6 +53,7 @@ function UsersSelect(currentUser, els, options = {}) { const abilityName = $dropdown.data('abilityName'); let $value = $block.find('.value'); const $collapsedSidebar = $block.find('.sidebar-collapsed-user'); + // eslint-disable-next-line no-jquery/no-fade const $loading = $block.find('.block-loading').fadeOut(); const selectedIdDefault = defaultNullUser && showNullUser ? 0 : null; let selectedId = $dropdown.data('selected'); @@ -188,6 +189,7 @@ function UsersSelect(currentUser, els, options = {}) { const data = {}; data[abilityName] = {}; data[abilityName].assignee_id = selected != null ? selected : null; + // eslint-disable-next-line no-jquery/no-fade $loading.removeClass('hidden').fadeIn(); $dropdown.trigger('loading.gl.dropdown'); @@ -195,6 +197,7 @@ function UsersSelect(currentUser, els, options = {}) { let user = {}; let tooltipTitle = user.name; $dropdown.trigger('loaded.gl.dropdown'); + // eslint-disable-next-line no-jquery/no-fade $loading.fadeOut(); if (data.assignee) { user = { diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index 326440f5013..4f5f3ee5cf9 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -20,6 +20,11 @@ export default { Suggestions, }, props: { + isSubmitting: { + type: Boolean, + required: false, + default: false, + }, markdownPreviewPath: { type: String, required: false, @@ -133,6 +138,20 @@ export default { ); }, }, + watch: { + isSubmitting(isSubmitting) { + if (!isSubmitting || !this.$refs['markdown-preview'].querySelectorAll) { + return; + } + const mediaInPreview = this.$refs['markdown-preview'].querySelectorAll('video, audio'); + + if (mediaInPreview) { + mediaInPreview.forEach(media => { + media.pause(); + }); + } + }, + }, mounted() { /* GLForm class handles all the toolbar buttons @@ -177,7 +196,6 @@ export default { this.renderMarkdown(); } }, - showWriteTab() { this.markdownPreview = ''; this.previewMarkdown = false; diff --git a/app/assets/stylesheets/pages/error_list.scss b/app/assets/stylesheets/pages/error_list.scss new file mode 100644 index 00000000000..f97953ce824 --- /dev/null +++ b/app/assets/stylesheets/pages/error_list.scss @@ -0,0 +1,69 @@ +$gray-border: 1px solid $border-color; + +.error-list { + .sort-control { + .btn { + padding-right: 2rem; + } + + .gl-dropdown-caret { + position: absolute; + right: 0.5rem; + top: 0.5rem; + } + } + + @include media-breakpoint-up(sm) { + .row-top { + border: $gray-border; + background-color: $gray-50; + } + } + + @include media-breakpoint-down(xs) { + .table-row { + border: $gray-border; + border-radius: 4px; + } + + .search-box { + border-top: $gray-border; + border-bottom: $gray-border; + background-color: $gray-50; + } + + .table-col { + min-height: 68px; + + &::before { + text-align: left !important; + } + + &:first-child { + div { + padding: 0 !important; + align-items: flex-end; + } + } + + &:last-child { + height: 64px; + background-color: $gray-normal; + + &::before { + content: none !important; + } + + div { + width: 100% !important; + padding: 0 !important; + + a { + color: $blue-500; + border-color: $blue-500; + } + } + } + } + } +} diff --git a/app/models/blob.rb b/app/models/blob.rb index 0a425f2b961..42ee00bc196 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -51,6 +51,7 @@ class Blob < SimpleDelegator BlobViewer::Contributing, BlobViewer::Changelog, + BlobViewer::CargoToml, BlobViewer::Cartfile, BlobViewer::ComposerJson, BlobViewer::Gemfile, diff --git a/app/models/blob_viewer/cargo_toml.rb b/app/models/blob_viewer/cargo_toml.rb new file mode 100644 index 00000000000..2f1ebd25b4f --- /dev/null +++ b/app/models/blob_viewer/cargo_toml.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +module BlobViewer + class CargoToml < DependencyManager + include Static + + self.file_types = %i(cargo_toml) + + def manager_name + 'Cargo' + end + + def manager_url + 'https://crates.io/' + end + end +end diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 7e7c580a48e..e3f0e07bb8f 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -717,8 +717,8 @@ module Ci end end - def has_expiring_artifacts? - artifacts_expire_at.present? && artifacts_expire_at > Time.now + def has_expiring_archive_artifacts? + has_expiring_artifacts? && artifacts_file&.exists? end def keep_artifacts! @@ -933,6 +933,10 @@ module Ci value.with_indifferent_access end end + + def has_expiring_artifacts? + artifacts_expire_at.present? && artifacts_expire_at > Time.now + end end end diff --git a/app/models/diff_note.rb b/app/models/diff_note.rb index 686d06d3ee0..939d8bc4bef 100644 --- a/app/models/diff_note.rb +++ b/app/models/diff_note.rb @@ -23,6 +23,12 @@ class DiffNote < Note before_validation :set_line_code, if: :on_text?, unless: :importing? after_save :keep_around_commits, unless: :importing? + + NoteDiffFileCreationError = Class.new(StandardError) + + DIFF_LINE_NOT_FOUND_MESSAGE = "Failed to find diff line for: %{file_path}, old_line: %{old_line}, new_line: %{new_line}" + DIFF_FILE_NOT_FOUND_MESSAGE = "Failed to find diff file" + after_commit :create_diff_file, on: :create def discussion_class(*) @@ -33,7 +39,16 @@ class DiffNote < Note return unless should_create_diff_file? diff_file = fetch_diff_file + raise NoteDiffFileCreationError, DIFF_FILE_NOT_FOUND_MESSAGE unless diff_file + diff_line = diff_file.line_for_position(self.original_position) + unless diff_line + raise NoteDiffFileCreationError, DIFF_LINE_NOT_FOUND_MESSAGE % { + file_path: diff_file.file_path, + old_line: original_position.old_line, + new_line: original_position.new_line + } + end creation_params = diff_file.diff.to_hash .except(:too_large) @@ -110,19 +125,20 @@ class DiffNote < Note def fetch_diff_file return note_diff_file.raw_diff_file if note_diff_file - file = - if created_at_diff?(noteable.diff_refs) - # We're able to use the already persisted diffs (Postgres) if we're - # presenting a "current version" of the MR discussion diff. - # So no need to make an extra Gitaly diff request for it. - # As an extra benefit, the returned `diff_file` already - # has `highlighted_diff_lines` data set from Redis on - # `Diff::FileCollection::MergeRequestDiff`. - noteable.diffs(original_position.diff_options).diff_files.first - else - original_position.diff_file(repository) - end + if created_at_diff?(noteable.diff_refs) + # We're able to use the already persisted diffs (Postgres) if we're + # presenting a "current version" of the MR discussion diff. + # So no need to make an extra Gitaly diff request for it. + # As an extra benefit, the returned `diff_file` already + # has `highlighted_diff_lines` data set from Redis on + # `Diff::FileCollection::MergeRequestDiff`. + file = noteable.diffs(original_position.diff_options).diff_files.first + # if line is not found in persisted diffs, fallback and retrieve file from repository using gitaly + # This is required because of https://gitlab.com/gitlab-org/gitlab/issues/42676 + file = nil if file&.line_for_position(original_position).nil? && importing? + end + file ||= original_position.diff_file(repository) file&.unfold_diff_lines(position) file diff --git a/app/serializers/build_artifact_entity.rb b/app/serializers/build_artifact_entity.rb index 414f436e76e..c173c155edf 100644 --- a/app/serializers/build_artifact_entity.rb +++ b/app/serializers/build_artifact_entity.rb @@ -14,7 +14,7 @@ class BuildArtifactEntity < Grape::Entity download_project_job_artifacts_path(project, job) end - expose :keep_path, if: -> (*) { job.has_expiring_artifacts? } do |job| + expose :keep_path, if: -> (*) { job.has_expiring_archive_artifacts? } do |job| keep_project_job_artifacts_path(project, job) end diff --git a/app/serializers/build_details_entity.rb b/app/serializers/build_details_entity.rb index 480a8cab6ff..0ef71ff8af5 100644 --- a/app/serializers/build_details_entity.rb +++ b/app/serializers/build_details_entity.rb @@ -31,7 +31,7 @@ class BuildDetailsEntity < JobEntity browse_project_job_artifacts_path(project, build) end - expose :keep_path, if: -> (*) { build.has_expiring_artifacts? && can?(current_user, :update_build, build) } do |build| + expose :keep_path, if: -> (*) { build.has_expiring_archive_artifacts? && can?(current_user, :update_build, build) } do |build| keep_project_job_artifacts_path(project, build) end diff --git a/app/views/shared/_auto_devops_callout.html.haml b/app/views/shared/_auto_devops_callout.html.haml index 084d295f2c1..128508e954e 100644 --- a/app/views/shared/_auto_devops_callout.html.haml +++ b/app/views/shared/_auto_devops_callout.html.haml @@ -1,16 +1,15 @@ -.js-autodevops-banner.banner-callout.banner-non-empty-state.append-bottom-20.prepend-top-10{ data: { uid: 'auto_devops_settings_dismissed', project_path: project_path(@project) } } - .banner-graphic - = custom_icon('icon_autodevops') +%section.js-autodevops-banner.gl-banner{ data: { uid: 'auto_devops_settings_dismissed', project_path: project_path(@project) } } + .gl-banner-illustration + = image_tag('illustrations/autodevops.svg') - .banner-body.prepend-left-10.append-bottom-10 - %h5.banner-title= s_('AutoDevOps|Auto DevOps') + .gl-banner-content + %h1.gl-banner-title= s_('AutoDevOps|Auto DevOps') %p= s_('AutoDevOps|It will automatically build, test, and deploy your application based on a predefined CI/CD configuration.') %p - link = link_to(s_('AutoDevOps|Auto DevOps documentation'), help_page_path('topics/autodevops/index.md'), target: '_blank', rel: 'noopener noreferrer') = s_('AutoDevOps|Learn more in the %{link_to_documentation}').html_safe % { link_to_documentation: link } - .banner-buttons - = link_to s_('AutoDevOps|Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'autodevops-settings'), class: 'btn js-close-callout' + = link_to s_('AutoDevOps|Enable in settings'), project_settings_ci_cd_path(@project, anchor: 'autodevops-settings'), class: 'btn btn-md new-gl-button js-close-callout' - %button.btn-transparent.banner-close.close.js-close-callout{ type: 'button', + %button.gl-banner-close.close.js-close-callout{ type: 'button', 'aria-label' => 'Dismiss Auto DevOps box' } = icon('times', class: 'dismiss-icon', 'aria-hidden' => 'true') |