Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-01-02 09:26:00 +00:00
parent a1553cc271
commit 990df4a10d
10 changed files with 104 additions and 14 deletions

View File

@ -28,6 +28,7 @@ import {
WORK_ITEM_TYPE_VALUE_EPIC,
WIDGET_TYPE_WEIGHT,
WIDGET_TYPE_DEVELOPMENT,
STATE_OPEN,
} from '../constants';
import workItemUpdatedSubscription from '../graphql/work_item_updated.subscription.graphql';
@ -451,6 +452,12 @@ export default {
activeChildItemId() {
return this.activeChildItem?.id;
},
workItemIsOpen() {
return this.workItem?.state === STATE_OPEN;
},
showCreateBranchMergeRequestSplitButton() {
return this.workItemDevelopment && this.workItemIsOpen;
},
},
methods: {
handleWorkItemCreated() {
@ -865,7 +872,7 @@ export default {
@error="onUploadDesignError"
/>
<work-item-create-branch-merge-request-split-button
v-if="workItemDevelopment"
v-if="showCreateBranchMergeRequestSplitButton"
:work-item-id="workItem.id"
:work-item-iid="iid"
:work-item-full-path="workItemFullPath"

View File

@ -87,11 +87,6 @@ export default {
return { items, name: __('Branch') };
},
buttonText() {
return this.checkingBranchAvailibility
? __('Checking branch availability...')
: this.createMergeRequestButtonText;
},
createMergeRequestButtonText() {
return this.isConfidentialWorkItem
? __('Create confidential merge request')
@ -126,7 +121,7 @@ export default {
size="medium"
@click="openModal(false, true)"
>
{{ buttonText }}
{{ createMergeRequestButtonText }}
</gl-button>
<gl-disclosure-dropdown placement="bottom-end" data-testid="create-options-dropdown">
<gl-disclosure-dropdown-group :group="mergeRequestGroup" />

View File

@ -8,6 +8,8 @@ module Preloaders
end
def execute
return if groups.blank?
ActiveRecord::Associations::Preloader.new(
records: groups,
associations: [:organization]

View File

@ -10,6 +10,8 @@ module Preloaders
end
def execute
return unless @user
preload_with_traversal_ids
end

View File

@ -161,10 +161,10 @@ GitLab.com:
- `default`: Any system-wide feature.
- `free`: Namespaces and projects with a Free subscription.
- `bronze`: Namespaces and projects with a Bronze subscription. This tier is no longer available for purchase.
- `silver`: Namespaces and projects with a Premium subscription.
- `silver`: Namespaces and projects with a Premium subscription. This tier is no longer available for purchase.
- `premium`: Namespaces and projects with a Premium subscription.
- `premium_trial`: Namespaces and projects with a Premium Trial subscription.
- `gold`: Namespaces and projects with an Ultimate subscription.
- `gold`: Namespaces and projects with an Ultimate subscription. This tier is no longer available for purchase.
- `ultimate`: Namespaces and projects with an Ultimate subscription.
- `ultimate_trial`: Namespaces and projects with an Ultimate Trial subscription.
- `ultimate_trial_paid_customer`: Namespaces and projects on a Premium subscription that are trialling Ultimate for 30 days.

View File

@ -174,7 +174,7 @@ Repeat these steps to create all the labels you'll need:
- **Type:** You will use these labels to represent the different types of work typically pulled into a single iteration:
- `type::story`
- `type::bug`
- `type::mantainence`
- `type::maintenance`
### Create an iteration cadence

View File

@ -72,13 +72,18 @@ module Banzai
# Returns all the nodes that are visible to the given user.
def nodes_visible_to_user(user, nodes)
projects = lazy { projects_for_nodes(nodes) }
groups = lazy { groups_for_nodes(nodes) }
project_attr = 'data-project'
group_attr = 'data-group'
preload_associations(projects, user)
preload_group_associations(groups, user)
nodes.select do |node|
if node.has_attribute?(project_attr)
can_read_reference?(user, projects[node], node)
elsif node.has_attribute?(group_attr)
can_read_reference?(user, groups[node], node)
else
true
end
@ -233,8 +238,11 @@ module Banzai
# { node => project }
#
def projects_for_nodes(nodes)
@projects_for_nodes ||=
grouped_objects_for_nodes(nodes, Project.includes(:project_feature), 'data-project')
@projects_for_nodes ||= grouped_objects_for_nodes(nodes, Project.includes(:project_feature), 'data-project')
end
def groups_for_nodes(nodes)
@groups_for_nodes ||= grouped_objects_for_nodes(nodes, Group, 'data-group')
end
def can?(user, permission, subject = :global)
@ -279,6 +287,10 @@ module Banzai
def preload_associations(projects, user)
::Preloaders::ProjectPolicyPreloader.new(projects.values, user).execute
end
def preload_group_associations(groups, user)
::Preloaders::GroupPolicyPreloader.new(groups.values, user).execute
end
end
end
end

View File

@ -25,7 +25,7 @@ import DesignWidget from '~/work_items/components/design_management/design_manag
import DesignUploadButton from '~/work_items/components//design_management/upload_button.vue';
import WorkItemCreateBranchMergeRequestSplitButton from '~/work_items/components/work_item_development/work_item_create_branch_merge_request_split_button.vue';
import uploadDesignMutation from '~/work_items/components/design_management/graphql/upload_design.mutation.graphql';
import { i18n } from '~/work_items/constants';
import { i18n, STATE_CLOSED } from '~/work_items/constants';
import workItemByIdQuery from '~/work_items/graphql/work_item_by_id.query.graphql';
import workItemByIidQuery from '~/work_items/graphql/work_item_by_iid.query.graphql';
import updateWorkItemMutation from '~/work_items/graphql/update_work_item.mutation.graphql';
@ -934,6 +934,22 @@ describe('WorkItemDetail component', () => {
expect(findCreateMergeRequestSplitButton().exists()).toBe(true);
});
it('should not show the button when the work item is closed', async () => {
createComponent({
handler: jest.fn().mockResolvedValue(
workItemByIidResponseFactory({
canUpdate: true,
canDelete: true,
developmentWidgetPresent: true,
state: STATE_CLOSED,
}),
),
});
await waitForPromises();
expect(findCreateMergeRequestSplitButton().exists()).toBe(false);
});
});
describe('work item attributes wrapper', () => {

View File

@ -42,7 +42,7 @@ describe('WorkItemCreateBranchMergeRequestSplitButton', () => {
});
it('shows loading indicator till the permission call is made', () => {
expect(findMainButton().text()).toBe('Checking branch availability...');
expect(findMainButton().text()).toBe('Create merge request');
expect(findMainButton().props('loading')).toBe(true);
});

View File

@ -1089,6 +1089,62 @@ RSpec.describe Note, feature_category: :team_planning do
end
end
describe 'all_referenced_mentionables_allowed?' do
let_it_be(:user) { create(:user) }
let_it_be(:issue) { create(:issue) }
RSpec.shared_examples 'does not generate N+1 queries for reference parsing' do
it 'does not generate N+1 queries for reference parsing', :request_store do
ref1 = milestone1.to_reference(issue.project, format: :name, full: true, absolute_path: true)
ref2 = milestone2.to_reference(issue.project, format: :name, full: true, absolute_path: true)
ref3 = milestone3.to_reference(issue.project, format: :name, full: true, absolute_path: true)
text = "mentioned in #{ref1}"
note = create(:note, :system, noteable: issue, note: text, project: issue.project)
note.system_note_visible_for?(user)
text = "mentioned in #{ref1} and #{ref2}"
note.update!(note: text)
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
note.system_note_visible_for?(user)
end
text = "mentioned in #{ref1} and #{ref2} and #{ref3}"
note.update!(note: text)
expect do
note.system_note_visible_for?(user)
end.to issue_same_number_of_queries_as(control).or_fewer
end
end
context 'with a project level milestone' do
let_it_be(:milestone1) { create(:milestone, project: create(:project, :private)) }
let_it_be(:milestone2) { create(:milestone, project: create(:project, :private)) }
let_it_be(:milestone3) { create(:milestone, project: create(:project, :private)) }
let_it_be(:milestone_event) { create(:resource_milestone_event, issue: issue, milestone: milestone1) }
let_it_be(:note) { MilestoneNote.from_event(milestone_event, resource: issue, resource_parent: issue.project) }
it { expect(note.system_note_visible_for?(user)).to be false }
it_behaves_like 'does not generate N+1 queries for reference parsing'
end
context 'with a group level milestone' do
let_it_be(:milestone1) { create(:milestone, group: create(:group, :private)) }
let_it_be(:milestone2) { create(:milestone, group: create(:group, :private)) }
let_it_be(:milestone3) { create(:milestone, group: create(:group, :private)) }
let_it_be(:milestone_event) { create(:resource_milestone_event, issue: issue, milestone: milestone1) }
let_it_be(:note) { MilestoneNote.from_event(milestone_event, resource: issue, resource_parent: issue.project) }
it { expect(note.system_note_visible_for?(user)).to be false }
it_behaves_like 'does not generate N+1 queries for reference parsing'
end
end
describe 'clear_blank_line_code!' do
it 'clears a blank line code before validation' do
note = build(:note, line_code: ' ')