summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/diffs/components/app.vue58
-rw-r--r--app/assets/javascripts/diffs/components/diff_content.vue4
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue3
-rw-r--r--app/assets/javascripts/diffs/store/getters.js3
-rw-r--r--app/assets/stylesheets/framework/diffs.scss2
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss4
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/models/project.rb37
-rw-r--r--app/presenters/project_presenter.rb8
9 files changed, 95 insertions, 25 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 66157dfeaba..6a3f5993a22 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -3,6 +3,7 @@ import { GlLoadingIcon, GlPagination, GlSprintf } from '@gitlab/ui';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import Mousetrap from 'mousetrap';
import { mapState, mapGetters, mapActions } from 'vuex';
+import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scroller';
import api from '~/api';
import {
keysFor,
@@ -17,7 +18,6 @@ import { getParameterByName, parseBoolean } from '~/lib/utils/common_utils';
import { updateHistory } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import PanelResizer from '~/vue_shared/components/panel_resizer.vue';
-import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import notesEventHub from '../../notes/event_hub';
import {
@@ -69,8 +69,9 @@ export default {
PanelResizer,
GlPagination,
GlSprintf,
+ DynamicScroller,
+ DynamicScrollerItem,
},
- mixins: [glFeatureFlagsMixin()],
alerts: {
ALERT_OVERFLOW_HIDDEN,
ALERT_MERGE_CONFLICT,
@@ -196,7 +197,12 @@ export default {
'renderTreeList',
'showWhitespace',
]),
- ...mapGetters('diffs', ['whichCollapsedTypes', 'isParallelView', 'currentDiffIndex']),
+ ...mapGetters('diffs', [
+ 'whichCollapsedTypes',
+ 'isParallelView',
+ 'currentDiffIndex',
+ 'isVirtualScrollingEnabled',
+ ]),
...mapGetters('batchComments', ['draftsCount']),
...mapGetters(['isNotesFetched', 'getNoteableData']),
diffs() {
@@ -561,17 +567,41 @@ export default {
<commit-widget v-if="commit" :commit="commit" :collapsible="false" />
<div v-if="isBatchLoading" class="loading"><gl-loading-icon size="lg" /></div>
<template v-else-if="renderDiffFiles">
- <diff-file
- v-for="(file, index) in diffs"
- :key="file.newPath"
- :file="file"
- :reviewed="fileReviews[file.id]"
- :is-first-file="index === 0"
- :is-last-file="index === diffFilesLength - 1"
- :help-page-path="helpPagePath"
- :can-current-user-fork="canCurrentUserFork"
- :view-diffs-file-by-file="viewDiffsFileByFile"
- />
+ <dynamic-scroller
+ v-if="isVirtualScrollingEnabled"
+ :items="diffs"
+ :min-item-size="70"
+ :buffer="1000"
+ :use-transform="false"
+ page-mode
+ >
+ <template #default="{ item, index, active }">
+ <dynamic-scroller-item :item="item" :active="active">
+ <diff-file
+ :file="item"
+ :reviewed="fileReviews[item.id]"
+ :is-first-file="index === 0"
+ :is-last-file="index === diffFilesLength - 1"
+ :help-page-path="helpPagePath"
+ :can-current-user-fork="canCurrentUserFork"
+ :view-diffs-file-by-file="viewDiffsFileByFile"
+ />
+ </dynamic-scroller-item>
+ </template>
+ </dynamic-scroller>
+ <template v-else>
+ <diff-file
+ v-for="(file, index) in diffs"
+ :key="file.new_path"
+ :file="file"
+ :reviewed="fileReviews[file.id]"
+ :is-first-file="index === 0"
+ :is-last-file="index === diffFilesLength - 1"
+ :help-page-path="helpPagePath"
+ :can-current-user-fork="canCurrentUserFork"
+ :view-diffs-file-by-file="viewDiffsFileByFile"
+ />
+ </template>
<div
v-if="showFileByFileNavigation"
data-testid="file-by-file-navigation"
diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue
index 663d2bb3cf8..283dbc6031c 100644
--- a/app/assets/javascripts/diffs/components/diff_content.vue
+++ b/app/assets/javascripts/diffs/components/diff_content.vue
@@ -49,9 +49,7 @@ export default {
},
},
computed: {
- ...mapState({
- projectPath: (state) => state.diffs.projectPath,
- }),
+ ...mapState('diffs', ['projectPath']),
...mapGetters('diffs', [
'isInlineView',
'isParallelView',
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index d9887c2ce05..ce867dbb9e0 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -83,7 +83,7 @@ export default {
computed: {
...mapState('diffs', ['currentDiffFileId', 'codequalityDiff']),
...mapGetters(['isNotesFetched']),
- ...mapGetters('diffs', ['getDiffFileDiscussions']),
+ ...mapGetters('diffs', ['getDiffFileDiscussions', 'isVirtualScrollingEnabled']),
viewBlobHref() {
return escape(this.file.view_path);
},
@@ -290,6 +290,7 @@ export default {
'is-active': currentDiffFileId === file.file_hash,
'comments-disabled': Boolean(file.brokenSymlink),
'has-body': showBody,
+ 'is-virtual-scrolling': isVirtualScrollingEnabled,
}"
:data-path="file.new_path"
class="diff-file file-holder gl-border-none"
diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js
index dec3f87b03e..0a9623c13a3 100644
--- a/app/assets/javascripts/diffs/store/getters.js
+++ b/app/assets/javascripts/diffs/store/getters.js
@@ -170,3 +170,6 @@ export function suggestionCommitMessage(state, _, rootState) {
},
});
}
+
+export const isVirtualScrollingEnabled = (state) =>
+ !state.viewDiffsFileByFile && window.gon?.features?.diffsVirtualScrolling;
diff --git a/app/assets/stylesheets/framework/diffs.scss b/app/assets/stylesheets/framework/diffs.scss
index dd0c0bd9b60..a07e0b48cff 100644
--- a/app/assets/stylesheets/framework/diffs.scss
+++ b/app/assets/stylesheets/framework/diffs.scss
@@ -729,7 +729,7 @@ table.code {
}
.files {
- .diff-file:last-child {
+ .diff-file:not(.is-virtual-scrolling):last-child {
margin-bottom: 0;
}
}
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index 9fdc30359f8..5e9dd883635 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -7,6 +7,10 @@
.diff-files-holder {
flex: 1;
min-width: 0;
+
+ .vue-recycle-scroller__item-wrapper {
+ overflow: visible;
+ }
}
.with-system-header {
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index d1d83f35d5f..613faa200d1 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -42,6 +42,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:confidential_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:usage_data_i_testing_summary_widget_total, @project, default_enabled: :yaml)
push_frontend_feature_flag(:improved_emoji_picker, project, default_enabled: :yaml)
+ push_frontend_feature_flag(:diffs_virtual_scrolling, project, default_enabled: :yaml)
# Usage data feature flags
push_frontend_feature_flag(:users_expanding_widgets_usage_data, @project, default_enabled: :yaml)
diff --git a/app/models/project.rb b/app/models/project.rb
index cd7e49d2c4a..8f6c81485ba 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -128,8 +128,41 @@ class Project < ApplicationRecord
after_initialize :use_hashed_storage
after_create :check_repository_absence!
- acts_as_ordered_taggable
- alias_method :topics, :tag_list
+ acts_as_ordered_taggable_on :topics
+ # The 'tag_list' alias and the 'has_many' associations are required during the 'tags -> topics' migration
+ # TODO: eliminate 'tag_list', 'topic_taggings' and 'tags' in the further process of the migration
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/331081
+ alias_attribute :tag_list, :topic_list
+ has_many :topic_taggings, -> { includes(:tag).order("#{ActsAsTaggableOn::Tagging.table_name}.id") },
+ as: :taggable,
+ class_name: 'ActsAsTaggableOn::Tagging',
+ after_add: :dirtify_tag_list,
+ after_remove: :dirtify_tag_list
+ has_many :topics, -> { order("#{ActsAsTaggableOn::Tagging.table_name}.id") },
+ class_name: 'ActsAsTaggableOn::Tag',
+ through: :topic_taggings,
+ source: :tag
+ has_many :tags, -> { order("#{ActsAsTaggableOn::Tagging.table_name}.id") },
+ class_name: 'ActsAsTaggableOn::Tag',
+ through: :topic_taggings,
+ source: :tag
+
+ # Overwriting 'topic_list' and 'topic_list=' is necessary to ensure functionality during the background migration [1].
+ # [1] https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61237
+ # TODO: remove 'topic_list' and 'topic_list=' once the background migration is complete
+ # https://gitlab.com/gitlab-org/gitlab/-/issues/331081
+ def topic_list
+ # Return both old topics (context 'tags') and new topics (context 'topics')
+ tag_list_on('tags') + tag_list_on('topics')
+ end
+
+ def topic_list=(new_tags)
+ # Old topics with context 'tags' are added as new topics with context 'topics'
+ super(new_tags)
+
+ # Remove old topics with context 'tags'
+ set_tag_list_on('tags', '')
+ end
attr_accessor :old_path_with_namespace
attr_accessor :template_name
diff --git a/app/presenters/project_presenter.rb b/app/presenters/project_presenter.rb
index 3726238474f..4f803ba34f4 100644
--- a/app/presenters/project_presenter.rb
+++ b/app/presenters/project_presenter.rb
@@ -401,16 +401,16 @@ class ProjectPresenter < Gitlab::View::Presenter::Delegated
end
def topics_to_show
- project.topics.take(MAX_TOPICS_TO_SHOW) # rubocop: disable CodeReuse/ActiveRecord
+ project.topic_list.take(MAX_TOPICS_TO_SHOW) # rubocop: disable CodeReuse/ActiveRecord
end
def topics_not_shown
- project.topics - topics_to_show
+ project.topic_list - topics_to_show
end
def count_of_extra_topics_not_shown
- if project.topics.count > MAX_TOPICS_TO_SHOW
- project.topics.count - MAX_TOPICS_TO_SHOW
+ if project.topic_list.count > MAX_TOPICS_TO_SHOW
+ project.topic_list.count - MAX_TOPICS_TO_SHOW
else
0
end