Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-04-12 15:08:27 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-12 15:08:27 +0300
commite0d7577e29dcab90623e1f38cf11b351c665ee23 (patch)
tree5a34f26be66301f1af9e36b10a67dfca01fed8ec /app
parent60e7627c998b74d48df10b9a7759d6038a1f139c (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/diffs/components/app.vue112
-rw-r--r--app/assets/javascripts/diffs/components/diff_file.vue6
-rw-r--r--app/assets/javascripts/diffs/components/tree_list.vue6
-rw-r--r--app/assets/javascripts/diffs/store/actions.js15
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue15
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js2
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql1
-rw-r--r--app/assets/javascripts/super_sidebar/components/groups_list.vue2
-rw-r--r--app/assets/javascripts/super_sidebar/components/projects_list.vue2
-rw-r--r--app/assets/javascripts/work_items/components/work_item_detail.vue15
-rw-r--r--app/assets/stylesheets/page_bundles/wiki.scss11
-rw-r--r--app/controllers/projects/blame_controller.rb11
-rw-r--r--app/controllers/projects/merge_requests_controller.rb1
-rw-r--r--app/finders/group_members_finder.rb54
-rw-r--r--app/helpers/blame_helper.rb4
-rw-r--r--app/helpers/merge_requests_helper.rb4
-rw-r--r--app/models/packages/event.rb1
-rw-r--r--app/services/projects/blame_service.rb35
-rw-r--r--app/views/projects/blame/show.html.haml12
-rw-r--r--app/views/projects/merge_requests/_page.html.haml2
20 files changed, 189 insertions, 122 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 99bc3780b55..9b3db78724d 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -253,6 +253,9 @@ export default {
renderDiffFiles() {
return this.flatBlobsList.length > 0;
},
+ diffsIncomplete() {
+ return this.flatBlobsList.length !== this.diffFiles.length;
+ },
renderFileTree() {
return this.renderDiffFiles && this.showTreeList;
},
@@ -313,6 +316,11 @@ export default {
diffViewType() {
this.adjustView();
},
+ viewDiffsFileByFile(newViewFileByFile) {
+ if (!newViewFileByFile && this.diffsIncomplete && this.glFeatures.singleFileFileByFile) {
+ this.refetchDiffData({ refetchMeta: false });
+ }
+ },
shouldShow() {
// When the shouldShow property changed to true, the route is rendered for the first time
// and if we have the isLoading as true this means we didn't fetch the data
@@ -429,13 +437,15 @@ export default {
'setCodequalityEndpoint',
'fetchDiffFilesMeta',
'fetchDiffFilesBatch',
+ 'fetchFileByFile',
'fetchCoverageFiles',
'fetchCodequality',
+ 'rereadNoteHash',
'startRenderDiffsQueue',
'assignDiscussionsToDiff',
'setHighlightedRow',
'cacheTreeListWidth',
- 'scrollToFile',
+ 'goToFile',
'setShowTreeList',
'navigateToDiffFileIndex',
'setFileByFile',
@@ -448,16 +458,27 @@ export default {
subscribeToEvents() {
notesEventHub.$once('fetchDiffData', this.fetchData);
notesEventHub.$on('refetchDiffData', this.refetchDiffData);
+ if (this.glFeatures.singleFileFileByFile) {
+ diffsEventHub.$on('diffFilesModified', this.setDiscussions);
+ notesEventHub.$on('fetchedNotesData', this.rereadNoteHash);
+ }
},
unsubscribeFromEvents() {
+ if (this.glFeatures.singleFileFileByFile) {
+ notesEventHub.$off('fetchedNotesData', this.rereadNoteHash);
+ diffsEventHub.$off('diffFilesModified', this.setDiscussions);
+ }
notesEventHub.$off('refetchDiffData', this.refetchDiffData);
notesEventHub.$off('fetchDiffData', this.fetchData);
},
navigateToDiffFileNumber(number) {
- this.navigateToDiffFileIndex(number - 1);
+ this.navigateToDiffFileIndex({
+ index: number - 1,
+ singleFile: this.glFeatures.singleFileFileByFile,
+ });
},
- refetchDiffData() {
- this.fetchData(false);
+ refetchDiffData({ refetchMeta = true } = {}) {
+ this.fetchData({ toggleTree: false, fetchMeta: refetchMeta });
},
needsReload() {
return this.diffFiles.length && isSingleViewStyle(this.diffFiles[0]);
@@ -465,44 +486,52 @@ export default {
needsFirstLoad() {
return !this.diffFiles.length;
},
- fetchData(toggleTree = true) {
- this.fetchDiffFilesMeta()
- .then((data) => {
- let realSize = 0;
-
- if (data) {
- realSize = data.real_size;
- }
-
- this.diffFilesLength = parseInt(realSize, 10) || 0;
- if (toggleTree) {
- this.setTreeDisplay();
- }
-
- updateChangesTabCount({
- count: this.diffFilesLength,
+ fetchData({ toggleTree = true, fetchMeta = true } = {}) {
+ if (fetchMeta) {
+ this.fetchDiffFilesMeta()
+ .then((data) => {
+ let realSize = 0;
+
+ if (data) {
+ realSize = data.real_size;
+
+ if (this.viewDiffsFileByFile && this.glFeatures.singleFileFileByFile) {
+ this.fetchFileByFile();
+ }
+ }
+
+ this.diffFilesLength = parseInt(realSize, 10) || 0;
+ if (toggleTree) {
+ this.setTreeDisplay();
+ }
+
+ updateChangesTabCount({
+ count: this.diffFilesLength,
+ });
+ })
+ .catch(() => {
+ createAlert({
+ message: __('Something went wrong on our end. Please try again!'),
+ });
});
- })
- .catch(() => {
- createAlert({
- message: __('Something went wrong on our end. Please try again!'),
- });
- });
+ }
- this.fetchDiffFilesBatch()
- .then(() => {
- if (toggleTree) this.setTreeDisplay();
- // Guarantee the discussions are assigned after the batch finishes.
- // Just watching the length of the discussions or the diff files
- // isn't enough, because with split diff loading, neither will
- // change when loading the other half of the diff files.
- this.setDiscussions();
- })
- .catch(() => {
- createAlert({
- message: __('Something went wrong on our end. Please try again!'),
+ if (!this.viewDiffsFileByFile || !this.glFeatures.singleFileFileByFile) {
+ this.fetchDiffFilesBatch()
+ .then(() => {
+ if (toggleTree) this.setTreeDisplay();
+ // Guarantee the discussions are assigned after the batch finishes.
+ // Just watching the length of the discussions or the diff files
+ // isn't enough, because with split diff loading, neither will
+ // change when loading the other half of the diff files.
+ this.setDiscussions();
+ })
+ .catch(() => {
+ createAlert({
+ message: __('Something went wrong on our end. Please try again!'),
+ });
});
- });
+ }
if (this.endpointCoverage) {
this.fetchCoverageFiles();
@@ -578,7 +607,10 @@ export default {
jumpToFile(step) {
const targetIndex = this.currentDiffIndex + step;
if (targetIndex >= 0 && targetIndex < this.flatBlobsList.length) {
- this.scrollToFile({ path: this.flatBlobsList[targetIndex].path });
+ this.goToFile({
+ path: this.flatBlobsList[targetIndex].path,
+ singleFile: this.glFeatures.singleFileFileByFile,
+ });
}
},
setTreeDisplay() {
diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue
index c19174dda8a..a58178eaef7 100644
--- a/app/assets/javascripts/diffs/components/diff_file.vue
+++ b/app/assets/javascripts/diffs/components/diff_file.vue
@@ -209,7 +209,11 @@ export default {
if (this.hasDiff) {
this.postRender();
- } else if (this.viewDiffsFileByFile && !this.isCollapsed) {
+ } else if (
+ this.viewDiffsFileByFile &&
+ !this.isCollapsed &&
+ !this.glFeatures.singleFileFileByFile
+ ) {
this.requestDiff();
}
diff --git a/app/assets/javascripts/diffs/components/tree_list.vue b/app/assets/javascripts/diffs/components/tree_list.vue
index 2675099a2f5..4f1875e9175 100644
--- a/app/assets/javascripts/diffs/components/tree_list.vue
+++ b/app/assets/javascripts/diffs/components/tree_list.vue
@@ -5,6 +5,7 @@ import micromatch from 'micromatch';
import { debounce } from 'lodash';
import { getModifierKey } from '~/constants';
import { s__, sprintf } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { RecycleScroller } from 'vendor/vue-virtual-scroller';
import DiffFileRow from './diff_file_row.vue';
@@ -19,6 +20,7 @@ export default {
DiffFileRow,
RecycleScroller,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
hideFileStats: {
type: Boolean,
@@ -105,7 +107,7 @@ export default {
this.resizeObserver.disconnect();
},
methods: {
- ...mapActions('diffs', ['toggleTreeOpen', 'scrollToFile']),
+ ...mapActions('diffs', ['toggleTreeOpen', 'goToFile']),
clearSearch() {
this.search = '';
},
@@ -175,7 +177,7 @@ export default {
:class="{ 'tree-list-parent': item.level > 0 }"
class="gl-relative"
@toggleTreeOpen="toggleTreeOpen"
- @clickFile="(path) => scrollToFile({ path })"
+ @clickFile="(path) => goToFile({ singleFile: glFeatures.singleFileFileByFile, path })"
/>
</template>
<template #after>
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index f6552d39193..a70c907314b 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -591,8 +591,8 @@ export const setCurrentFileHash = ({ commit }, hash) => {
commit(types.SET_CURRENT_DIFF_FILE, hash);
};
-export const goToFile = ({ state, commit, dispatch, getters }, { path }) => {
- if (!state.viewDiffsFileByFile) {
+export const goToFile = ({ state, commit, dispatch, getters }, { path, singleFile }) => {
+ if (!state.viewDiffsFileByFile || !singleFile) {
dispatch('scrollToFile', { path });
} else {
if (!state.treeEntries[path]) return;
@@ -600,9 +600,9 @@ export const goToFile = ({ state, commit, dispatch, getters }, { path }) => {
const { fileHash } = state.treeEntries[path];
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
+ document.location.hash = fileHash;
if (!getters.isTreePathLoaded(path)) {
- document.location.hash = fileHash;
dispatch('fetchFileByFile')
.then(() => {
dispatch('scrollToFile', { path });
@@ -926,11 +926,18 @@ export const setCurrentDiffFileIdFromNote = ({ commit, getters, rootGetters }, n
}
};
-export const navigateToDiffFileIndex = ({ commit, getters }, index) => {
+export const navigateToDiffFileIndex = (
+ { state, getters, commit, dispatch },
+ { index, singleFile },
+) => {
const { fileHash } = getters.flatBlobsList[index];
document.location.hash = fileHash;
commit(types.SET_CURRENT_DIFF_FILE, fileHash);
+
+ if (state.viewDiffsFileByFile && singleFile) {
+ dispatch('fetchFileByFile');
+ }
};
export const setFileByFile = ({ state, commit }, { fileByFile }) => {
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue
index 5d77ff9dc0d..4e154870f55 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue
@@ -4,9 +4,10 @@ import { sprintf, n__, s__ } from '~/locale';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
+import { formatDate } from '~/lib/utils/datetime_utility';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import {
- UPDATED_AT,
+ CREATED_AT,
CLEANUP_UNSCHEDULED_TEXT,
CLEANUP_SCHEDULED_TEXT,
CLEANUP_ONGOING_TEXT,
@@ -65,11 +66,11 @@ export default {
visibilityIcon() {
return this.imageDetails?.project?.visibility === 'public' ? 'eye' : 'eye-slash';
},
- timeAgo() {
- return this.timeFormatted(this.imageDetails.updatedAt);
+ formattedCreatedAtDate() {
+ return formatDate(this.imageDetails.createdAt, 'mmm d, yyyy HH:MM', true);
},
- updatedText() {
- return sprintf(UPDATED_AT, { time: this.timeAgo });
+ createdText() {
+ return sprintf(CREATED_AT, { time: this.formattedCreatedAtDate });
},
tagCountText() {
if (this.$apollo.queries.containerRepository.loading) {
@@ -145,9 +146,9 @@ export default {
<template #metadata-updated>
<metadata-item
:icon="visibilityIcon"
- :text="updatedText"
+ :text="createdText"
size="xl"
- data-testid="updated-and-visibility"
+ data-testid="created-and-visibility"
/>
</template>
<template #right-actions>
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js
index 7bb69363743..7ac803a8ece 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js
@@ -65,7 +65,7 @@ export const MISSING_MANIFEST_WARNING_TOOLTIP = s__(
'ContainerRegistry|Invalid tag: missing manifest digest',
);
-export const UPDATED_AT = s__('ContainerRegistry|Last updated %{time}');
+export const CREATED_AT = s__('ContainerRegistry|Created %{time}');
export const NOT_AVAILABLE_TEXT = __('Not applicable.');
export const NOT_AVAILABLE_SIZE = __('0 bytes');
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql
index e2036d9e63d..eae663acb48 100644
--- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql
+++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql
@@ -7,7 +7,6 @@ query getContainerRepositoryDetails($id: ContainerRepositoryID!) {
location
canDelete
createdAt
- updatedAt
expirationPolicyStartedAt
expirationPolicyCleanupStatus
project {
diff --git a/app/assets/javascripts/super_sidebar/components/groups_list.vue b/app/assets/javascripts/super_sidebar/components/groups_list.vue
index 1360d58dc6c..eb256e4971b 100644
--- a/app/assets/javascripts/super_sidebar/components/groups_list.vue
+++ b/app/assets/javascripts/super_sidebar/components/groups_list.vue
@@ -45,7 +45,7 @@ export default {
},
},
i18n: {
- title: s__('Navigation|Frequent groups'),
+ title: s__('Navigation|Frequently visited groups'),
searchTitle: s__('Navigation|Groups'),
pristineText: s__('Navigation|Groups you visit often will appear here.'),
noResultsText: s__('Navigation|No group matches found'),
diff --git a/app/assets/javascripts/super_sidebar/components/projects_list.vue b/app/assets/javascripts/super_sidebar/components/projects_list.vue
index de22f5d9897..b7a29a78d5f 100644
--- a/app/assets/javascripts/super_sidebar/components/projects_list.vue
+++ b/app/assets/javascripts/super_sidebar/components/projects_list.vue
@@ -45,7 +45,7 @@ export default {
},
},
i18n: {
- title: s__('Navigation|Frequent projects'),
+ title: s__('Navigation|Frequently visited projects'),
searchTitle: s__('Navigation|Projects'),
pristineText: s__('Navigation|Projects you visit often will appear here.'),
noResultsText: s__('Navigation|No project matches found'),
diff --git a/app/assets/javascripts/work_items/components/work_item_detail.vue b/app/assets/javascripts/work_items/components/work_item_detail.vue
index aed2187a3e6..738305ad670 100644
--- a/app/assets/javascripts/work_items/components/work_item_detail.vue
+++ b/app/assets/javascripts/work_items/components/work_item_detail.vue
@@ -537,14 +537,13 @@ export default {
{{ workItemBreadcrumbReference }}
</li>
</ul>
- <work-item-type-icon
- v-else-if="!error"
- :work-item-icon-name="workItemIconName"
- :work-item-type="workItemType && workItemType.toUpperCase()"
- show-text
- class="gl-font-weight-bold gl-text-secondary gl-mr-auto"
- data-testid="work-item-type"
- />
+ <div v-else-if="!error" class="gl-mr-auto" data-testid="work-item-type">
+ <work-item-type-icon
+ :work-item-icon-name="workItemIconName"
+ :work-item-type="workItemType && workItemType.toUpperCase()"
+ />
+ {{ workItemBreadcrumbReference }}
+ </div>
<gl-loading-icon v-if="updateInProgress" :inline="true" class="gl-mr-3" />
<gl-badge
v-if="workItem.confidential"
diff --git a/app/assets/stylesheets/page_bundles/wiki.scss b/app/assets/stylesheets/page_bundles/wiki.scss
index 7625fbede3a..69a3ec94fda 100644
--- a/app/assets/stylesheets/page_bundles/wiki.scss
+++ b/app/assets/stylesheets/page_bundles/wiki.scss
@@ -216,17 +216,12 @@ ul.wiki-pages-list.content-list {
.drawio-editor {
position: fixed;
- top: calc(var(--header-height, 48px));
+ top: 0;
left: 0;
bottom: 0;
- width: 100%;
- height: calc(100% - var(--header-height, 48px));
+ width: 100vw;
+ height: 100vh;
border: 0;
z-index: 1100;
visibility: hidden;
}
-
-.with-performance-bar .drawio-editor {
- top: calc(var(--header-height, 48px) + 35px);
- height: calc(100% - var(--header-height, 48px) - 35px);
-}
diff --git a/app/controllers/projects/blame_controller.rb b/app/controllers/projects/blame_controller.rb
index 75d7dfd5813..bd5701a3557 100644
--- a/app/controllers/projects/blame_controller.rb
+++ b/app/controllers/projects/blame_controller.rb
@@ -21,14 +21,12 @@ class Projects::BlameController < Projects::ApplicationController
load_environment
- blame_service = Projects::BlameService.new(@blob, @commit, blame_params)
+ @blame_mode = Gitlab::Git::BlameMode.new(@commit.project, blame_params)
+ blame_service = Projects::BlameService.new(@blob, @commit, @blame_mode, blame_params)
@blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path, page: blame_service.page).fabricate!
- @streaming_possible = blame_service.streaming_possible
-
- @streaming_enabled = blame_service.streaming_enabled
- @blame_pagination = blame_service.pagination unless @streaming_enabled
+ @blame_pagination = blame_service.pagination
@blame_per_page = blame_service.per_page
@@ -40,7 +38,8 @@ class Projects::BlameController < Projects::ApplicationController
load_environment
- blame_service = Projects::BlameService.new(@blob, @commit, blame_params)
+ @blame_mode = Gitlab::Git::BlameMode.new(@commit.project, blame_params)
+ blame_service = Projects::BlameService.new(@blob, @commit, @blame_mode, blame_params)
@blame = Gitlab::View::Presenter::Factory.new(blame_service.blame, project: @project, path: @path, page: blame_service.page).fabricate!
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index e174eadbeb4..73b8ca6aafb 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -41,6 +41,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:deprecate_vulnerabilities_feedback, @project)
push_frontend_feature_flag(:refactor_code_quality_inline_findings, project)
push_frontend_feature_flag(:moved_mr_sidebar, project)
+ push_frontend_feature_flag(:single_file_file_by_file, project)
push_frontend_feature_flag(:mr_experience_survey, project)
push_frontend_feature_flag(:realtime_mr_status_change, project)
push_frontend_feature_flag(:saved_replies, current_user)
diff --git a/app/finders/group_members_finder.rb b/app/finders/group_members_finder.rb
index 05645dacab9..1025e0ebc9b 100644
--- a/app/finders/group_members_finder.rb
+++ b/app/finders/group_members_finder.rb
@@ -30,7 +30,11 @@ class GroupMembersFinder < UnionFinder
def execute(include_relations: DEFAULT_RELATIONS)
groups = groups_by_relations(include_relations)
- members = all_group_members(groups).distinct_on_user_with_max_access_level
+ shared_from_groups = if include_relations&.include?(:shared_from_groups)
+ Group.shared_into_ancestors(group).public_or_visible_to_user(user)
+ end
+
+ members = all_group_members(groups, shared_from_groups).distinct_on_user_with_max_access_level
filter_members(members)
end
@@ -47,9 +51,8 @@ class GroupMembersFinder < UnionFinder
related_groups << Group.by_id(group.id) if include_relations&.include?(:direct)
related_groups << group.ancestors if include_relations&.include?(:inherited)
related_groups << group.descendants if include_relations&.include?(:descendants)
- related_groups << Group.shared_into_ancestors(group).public_or_visible_to_user(user) if include_relations&.include?(:shared_from_groups)
- find_union(related_groups, Group)
+ related_groups
end
def filter_members(members)
@@ -78,12 +81,49 @@ class GroupMembersFinder < UnionFinder
group.members
end
- def all_group_members(groups)
- members_of_groups(groups).non_minimal_access
+ def all_group_members(groups, shared_from_groups)
+ members_of_groups(groups, shared_from_groups).non_minimal_access
+ end
+
+ def members_of_groups(groups, shared_from_groups)
+ if Feature.disabled?(:members_with_shared_group_access, @group.root_ancestor)
+ groups << shared_from_groups unless shared_from_groups.nil?
+ return GroupMember.non_request.of_groups(find_union(groups, Group))
+ end
+
+ members = GroupMember.non_request.of_groups(find_union(groups, Group))
+ return members if shared_from_groups.nil?
+
+ shared_members = GroupMember.non_request.of_groups(shared_from_groups)
+ select_attributes = GroupMember.attribute_names
+ members_shared_with_group_access = members_shared_with_group_access(shared_members, select_attributes)
+
+ # `members` and `members_shared_with_group_access` should have even select values
+ find_union([members.select(select_attributes), members_shared_with_group_access], GroupMember)
+ end
+
+ def members_shared_with_group_access(shared_members, select_attributes)
+ group_group_link_table = GroupGroupLink.arel_table
+ group_member_table = GroupMember.arel_table
+
+ member_columns = select_attributes.map do |column_name|
+ if column_name == 'access_level'
+ args = [group_group_link_table[:group_access], group_member_table[:access_level]]
+ smallest_value_arel(args, 'access_level')
+ else
+ group_member_table[column_name]
+ end
+ end
+
+ # rubocop:disable CodeReuse/ActiveRecord
+ shared_members
+ .joins("LEFT OUTER JOIN group_group_links ON members.source_id = group_group_links.shared_with_group_id")
+ .select(member_columns)
+ # rubocop:enable CodeReuse/ActiveRecord
end
- def members_of_groups(groups)
- GroupMember.non_request.of_groups(groups)
+ def smallest_value_arel(args, column_alias)
+ Arel::Nodes::As.new(Arel::Nodes::NamedFunction.new('LEAST', args), Arel::Nodes::SqlLiteral.new(column_alias))
end
def check_relation_arguments!(include_relations)
diff --git a/app/helpers/blame_helper.rb b/app/helpers/blame_helper.rb
index 92bee1795fa..4eda89e2af2 100644
--- a/app/helpers/blame_helper.rb
+++ b/app/helpers/blame_helper.rb
@@ -44,8 +44,8 @@ module BlameHelper
namespace_project_blame_page_url(namespace_id: project.namespace, project_id: project, id: id, streaming: true)
end
- def entire_blame_path(id, project, streaming_possible)
- params = streaming_possible ? { streaming: true } : { no_pagination: true }
+ def entire_blame_path(id, project, blame_mode)
+ params = blame_mode.streaming_supported? ? { streaming: true } : { no_pagination: true }
namespace_project_blame_path(namespace_id: project.namespace, project_id: project, id: id, **params)
end
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index a36d61378a0..3c52868eab4 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -260,6 +260,10 @@ module MergeRequestsHelper
Feature.enabled?(:moved_mr_sidebar, @project) && defined?(@merge_request)
end
+ def single_file_file_by_file?
+ Feature.enabled?(:single_file_file_by_file, @project)
+ end
+
def sticky_header_data
data = {
iid: @merge_request.iid,
diff --git a/app/models/packages/event.rb b/app/models/packages/event.rb
index a033f9a9393..d93c22adcda 100644
--- a/app/models/packages/event.rb
+++ b/app/models/packages/event.rb
@@ -18,6 +18,7 @@ module Packages
delete_tag
delete_tag_bulk
list_tags
+ create_tag
cli_metadata
pull_symbol_package
push_symbol_package
diff --git a/app/services/projects/blame_service.rb b/app/services/projects/blame_service.rb
index 1ea16040655..d4c01044828 100644
--- a/app/services/projects/blame_service.rb
+++ b/app/services/projects/blame_service.rb
@@ -8,23 +8,22 @@ module Projects
STREAMING_FIRST_PAGE_SIZE = 200
STREAMING_PER_PAGE = 2000
- def initialize(blob, commit, params)
+ def initialize(blob, commit, blame_mode, params)
@blob = blob
@commit = commit
- @streaming_enabled = streaming_state(params)
- @pagination_enabled = pagination_state(params)
+ @blame_mode = blame_mode
@page = extract_page(params)
@params = params
end
- attr_reader :page, :streaming_enabled
+ attr_reader :page
def blame
Gitlab::Blame.new(blob, commit, range: blame_range)
end
def pagination
- return unless pagination_enabled
+ return unless blame_mode.pagination?
Kaminari.paginate_array([], total_count: blob_lines_count, limit: per_page)
.tap { |pagination| pagination.max_paginates_per(per_page) }
@@ -32,12 +31,12 @@ module Projects
end
def per_page
- streaming_enabled ? STREAMING_PER_PAGE : PER_PAGE
+ blame_mode.streaming? ? STREAMING_PER_PAGE : PER_PAGE
end
def total_pages
total = (blob_lines_count.to_f / per_page).ceil
- return total unless streaming_enabled
+ return total unless blame_mode.streaming?
([blob_lines_count - STREAMING_FIRST_PAGE_SIZE, 0].max.to_f / per_page).ceil + 1
end
@@ -46,20 +45,16 @@ module Projects
[total_pages - 1, 0].max
end
- def streaming_possible
- Feature.enabled?(:blame_page_streaming, commit.project)
- end
-
private
- attr_reader :blob, :commit, :pagination_enabled
+ attr_reader :blob, :commit, :blame_mode
def blame_range
- return unless pagination_enabled || streaming_enabled
+ return if blame_mode.full?
first_line = (page - 1) * per_page + 1
- if streaming_enabled
+ if blame_mode.streaming?
return 1..STREAMING_FIRST_PAGE_SIZE if page == 1
first_line = STREAMING_FIRST_PAGE_SIZE + (page - 2) * per_page + 1
@@ -78,18 +73,6 @@ module Projects
page
end
- def streaming_state(params)
- return false unless streaming_possible
-
- Gitlab::Utils.to_boolean(params[:streaming], default: false)
- end
-
- def pagination_state(params)
- return false if Gitlab::Utils.to_boolean(params[:no_pagination], default: false)
-
- Feature.enabled?(:blame_page_pagination, commit.project)
- end
-
def overlimit?(page)
page > total_pages
end
diff --git a/app/views/projects/blame/show.html.haml b/app/views/projects/blame/show.html.haml
index 413a89f6399..689dcb3b2cb 100644
--- a/app/views/projects/blame/show.html.haml
+++ b/app/views/projects/blame/show.html.haml
@@ -2,7 +2,7 @@
- add_page_specific_style 'page_bundles/tree'
- blame_streaming_url = blame_pages_streaming_url(@id, @project)
-- if @streaming_enabled && total_extra_pages > 0
+- if @blame_mode.streaming? && total_extra_pages > 0
- content_for :startup_js do
= javascript_tag do
:plain
@@ -37,21 +37,21 @@
.blame-table-wrapper
= render partial: 'page'
- - if @streaming_enabled
+ - if @blame_mode.streaming?
#blame-stream-container.blame-stream-container
- - if @blame_pagination && @blame_pagination.total_pages > 1
+ - if @blame_mode.pagination? && @blame_pagination.total_pages > 1
.gl-display-flex.gl-justify-content-center.gl-flex-direction-column.gl-align-items-center.gl-p-3.gl-bg-gray-50.gl-border-t-solid.gl-border-t-1.gl-border-gray-100
- = render Pajamas::ButtonComponent.new(href: entire_blame_path(@id, @project, @streaming_possible), size: :small, button_options: { class: 'gl-mt-3' }) do |c|
+ = render Pajamas::ButtonComponent.new(href: entire_blame_path(@id, @project, @blame_mode), size: :small, button_options: { class: 'gl-mt-3' }) do |c|
= _('Show full blame')
- - if @streaming_enabled
+ - if @blame_mode.streaming?
#blame-stream-loading.blame-stream-loading
.gradient
= gl_loading_icon(size: 'sm')
%span.gl-mx-2
= _('Loading full blame...')
- - if @blame_pagination
+ - if @blame_mode.pagination?
= paginate(@blame_pagination, theme: "gitlab")
diff --git a/app/views/projects/merge_requests/_page.html.haml b/app/views/projects/merge_requests/_page.html.haml
index f042fd56132..c9c2d9ff13f 100644
--- a/app/views/projects/merge_requests/_page.html.haml
+++ b/app/views/projects/merge_requests/_page.html.haml
@@ -18,7 +18,7 @@
- add_page_specific_style 'page_bundles/ci_status'
- add_page_startup_api_call @endpoint_metadata_url
-- if mr_action == 'diffs'
+- if mr_action == 'diffs' && (!@file_by_file_default || !single_file_file_by_file?)
- add_page_startup_api_call @endpoint_diff_batch_url
.merge-request{ data: { mr_action: mr_action, url: merge_request_path(@merge_request, format: :json), project_path: project_path(@merge_request.project), lock_version: @merge_request.lock_version, diffs_batch_cache_key: @diffs_batch_cache_key } }