Skip to content

Commit d48b87d

Browse files
author
GitLab Bot
committed
Add latest changes from gitlab-org/gitlab@master
1 parent fd9a56d commit d48b87d

File tree

57 files changed

+753
-125
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+753
-125
lines changed

app/assets/javascripts/blob_edit/edit_blob.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ export default class EditBlob {
6868
blobContent: editorEl.innerText,
6969
});
7070
this.editor.use([
71+
{ definition: ToolbarExtension },
7172
{ definition: SourceEditorExtension },
7273
{ definition: FileTemplateExtension },
73-
{ definition: ToolbarExtension },
7474
]);
7575

7676
fileNameEl.addEventListener('change', () => {

app/assets/javascripts/editor/constants.js

+1
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,4 @@ export const EXTENSION_MARKDOWN_BUTTONS = [
166166
},
167167
},
168168
];
169+
export const EXTENSION_SOFTWRAP_ID = 'soft-wrap';

app/assets/javascripts/editor/extensions/source_editor_extension_base.js

+45
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
import { Range } from 'monaco-editor';
2+
import { __ } from '~/locale';
23
import {
34
EDITOR_TYPE_CODE,
45
EXTENSION_BASE_LINE_LINK_ANCHOR_CLASS,
56
EXTENSION_BASE_LINE_NUMBERS_CLASS,
7+
EDITOR_TOOLBAR_RIGHT_GROUP,
8+
EXTENSION_SOFTWRAP_ID,
69
} from '../constants';
710

811
const hashRegexp = /#?L/g;
@@ -24,6 +27,13 @@ export class SourceEditorExtension {
2427
return 'BaseExtension';
2528
}
2629

30+
onSetup(instance) {
31+
this.toolbarButtons = [];
32+
if (instance.toolbar) {
33+
this.setupToolbar(instance);
34+
}
35+
}
36+
2737
// eslint-disable-next-line class-methods-use-this
2838
onUse(instance) {
2939
SourceEditorExtension.highlightLines(instance);
@@ -32,6 +42,31 @@ export class SourceEditorExtension {
3242
}
3343
}
3444

45+
onBeforeUnuse(instance) {
46+
const ids = this.toolbarButtons.map((item) => item.id);
47+
if (instance.toolbar) {
48+
instance.toolbar.removeItems(ids);
49+
}
50+
}
51+
52+
setupToolbar(instance) {
53+
this.toolbarButtons = [
54+
{
55+
id: EXTENSION_SOFTWRAP_ID,
56+
label: __('Soft wrap'),
57+
icon: 'soft-wrap',
58+
selected: instance.getOption(116) === 'on',
59+
group: EDITOR_TOOLBAR_RIGHT_GROUP,
60+
category: 'primary',
61+
selectedLabel: __('No wrap'),
62+
selectedIcon: 'soft-unwrap',
63+
class: 'soft-wrap-toggle',
64+
onClick: () => instance.toggleSoftwrap(),
65+
},
66+
];
67+
instance.toolbar.addItems(this.toolbarButtons);
68+
}
69+
3570
static onMouseMoveHandler(e) {
3671
const target = e.target.element;
3772
if (target.classList.contains(EXTENSION_BASE_LINE_NUMBERS_CLASS)) {
@@ -108,6 +143,16 @@ export class SourceEditorExtension {
108143
highlightLines(instance, bounds = null) {
109144
SourceEditorExtension.highlightLines(instance, bounds);
110145
},
146+
147+
toggleSoftwrap(instance) {
148+
const isSoftWrapped = instance.getOption(116) === 'on';
149+
instance.updateOptions({ wordWrap: isSoftWrapped ? 'off' : 'on' });
150+
if (instance.toolbar) {
151+
instance.toolbar.updateItem(EXTENSION_SOFTWRAP_ID, {
152+
selected: !isSoftWrapped,
153+
});
154+
}
155+
},
111156
};
112157
}
113158
}

app/assets/javascripts/invite_members/components/invite_members_trigger.vue

+23-2
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
<script>
2-
import { GlButton, GlLink, GlIcon } from '@gitlab/ui';
2+
import { GlButton, GlLink, GlIcon, GlDropdownItem } from '@gitlab/ui';
33
import { s__ } from '~/locale';
44
import eventHub from '../event_hub';
55
import {
66
TRIGGER_ELEMENT_BUTTON,
77
TRIGGER_ELEMENT_SIDE_NAV,
88
TRIGGER_DEFAULT_QA_SELECTOR,
9+
TRIGGER_ELEMENT_WITH_EMOJI,
10+
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
911
} from '../constants';
1012
1113
export default {
12-
components: { GlButton, GlLink, GlIcon },
14+
components: { GlButton, GlLink, GlIcon, GlDropdownItem },
1315
props: {
1416
displayText: {
1517
type: String,
@@ -85,6 +87,8 @@ export default {
8587
},
8688
TRIGGER_ELEMENT_BUTTON,
8789
TRIGGER_ELEMENT_SIDE_NAV,
90+
TRIGGER_ELEMENT_WITH_EMOJI,
91+
TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI,
8892
};
8993
</script>
9094

@@ -109,6 +113,23 @@ export default {
109113
</span>
110114
<span class="nav-item-name"> {{ displayText }} </span>
111115
</gl-link>
116+
<gl-link
117+
v-else-if="checkTrigger($options.TRIGGER_ELEMENT_WITH_EMOJI)"
118+
v-bind="componentAttributes"
119+
@click="openModal"
120+
>
121+
{{ displayText }}
122+
<gl-emoji class="gl-vertical-align-baseline gl-reset-font-size gl-mr-1" :data-name="icon" />
123+
</gl-link>
124+
<gl-dropdown-item
125+
v-else-if="checkTrigger($options.TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI)"
126+
v-bind="componentAttributes"
127+
button-class="top-nav-menu-item"
128+
@click="openModal"
129+
>
130+
{{ displayText }}
131+
<gl-emoji class="gl-vertical-align-baseline gl-reset-font-size gl-mr-1" :data-name="icon" />
132+
</gl-dropdown-item>
112133
<gl-link v-else v-bind="componentAttributes" data-is-link="true" @click="openModal">
113134
{{ displayText }}
114135
</gl-link>

app/assets/javascripts/invite_members/constants.js

+3
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ export const USERS_FILTER_ALL = 'all';
2020
export const USERS_FILTER_SAML_PROVIDER_ID = 'saml_provider_id';
2121
export const TRIGGER_ELEMENT_BUTTON = 'button';
2222
export const TRIGGER_ELEMENT_SIDE_NAV = 'side-nav';
23+
export const TOP_NAV_INVITE_MEMBERS_COMPONENT = 'invite_members';
24+
export const TRIGGER_ELEMENT_WITH_EMOJI = 'text-emoji';
25+
export const TRIGGER_ELEMENT_DROPDOWN_WITH_EMOJI = 'dropdown-text-emoji';
2326
export const INVITE_MEMBER_MODAL_TRACKING_CATEGORY = 'invite_members_modal';
2427
export const TRIGGER_DEFAULT_QA_SELECTOR = 'invite_members_button';
2528
export const MEMBERS_MODAL_DEFAULT_TITLE = s__('InviteMembersModal|Invite members');

app/assets/javascripts/nav/components/top_nav_new_dropdown.vue

+17
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
<script>
22
import { GlDropdown, GlDropdownDivider, GlDropdownItem, GlDropdownSectionHeader } from '@gitlab/ui';
3+
import InviteMembersTrigger from '~/invite_members/components/invite_members_trigger.vue';
4+
import { TOP_NAV_INVITE_MEMBERS_COMPONENT } from '~/invite_members/constants';
35
46
export default {
57
components: {
68
GlDropdown,
79
GlDropdownDivider,
810
GlDropdownItem,
911
GlDropdownSectionHeader,
12+
InviteMembersTrigger,
1013
},
1114
props: {
1215
viewModel: {
@@ -22,6 +25,11 @@ export default {
2225
return this.sections.length > 1;
2326
},
2427
},
28+
methods: {
29+
isInvitedMembers(menuItem) {
30+
return menuItem.component === TOP_NAV_INVITE_MEMBERS_COMPONENT;
31+
},
32+
},
2533
};
2634
</script>
2735

@@ -41,7 +49,16 @@ export default {
4149
{{ title }}
4250
</gl-dropdown-section-header>
4351
<template v-for="menuItem in menu_items">
52+
<invite-members-trigger
53+
v-if="isInvitedMembers(menuItem)"
54+
:key="`${index}_item_${menuItem.id}`"
55+
:trigger-element="`dropdown-${menuItem.data.trigger_element}`"
56+
:display-text="menuItem.title"
57+
:icon="menuItem.icon"
58+
:trigger-source="menuItem.data.trigger_source"
59+
/>
4460
<gl-dropdown-item
61+
v-else
4562
:key="`${index}_item_${menuItem.id}`"
4663
link-class="top-nav-menu-item"
4764
:href="menuItem.href"

app/assets/javascripts/pages/shared/wikis/wikis.js

+11
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,17 @@ export default class Wikis {
1616
sidebarToggles[i].addEventListener('click', (e) => this.handleToggleSidebar(e));
1717
}
1818

19+
const listToggles = document.querySelectorAll('.js-wiki-list-toggle');
20+
21+
listToggles.forEach((listToggle) => {
22+
listToggle.querySelector('.js-wiki-list-expand-button')?.addEventListener('click', () => {
23+
listToggle.classList.remove('collapsed');
24+
});
25+
listToggle.querySelector('.js-wiki-list-collapse-button')?.addEventListener('click', () => {
26+
listToggle.classList.add('collapsed');
27+
});
28+
});
29+
1930
window.addEventListener('resize', () => this.renderSidebar());
2031
this.renderSidebar();
2132

app/assets/stylesheets/page_bundles/wiki.scss

+43-1
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,23 @@
106106
color: var(--black, $black);
107107
}
108108

109+
.active > .wiki-list {
110+
a,
111+
.wiki-list-expand-button,
112+
.wiki-list-collapse-button {
113+
color: var(--black, $black);
114+
}
115+
}
116+
117+
.wiki-list-expand-button,
118+
.wiki-list-collapse-button {
119+
color: var(--gray-400, $gray-400);
120+
121+
&:hover {
122+
color: var(--black, $black);
123+
}
124+
}
125+
109126
ul.wiki-pages,
110127
ul.wiki-pages li {
111128
list-style: none;
@@ -118,7 +135,7 @@
118135
}
119136

120137
ul.wiki-pages ul {
121-
padding-left: 15px;
138+
padding-left: 20px;
122139
}
123140

124141
.wiki-sidebar-header {
@@ -153,3 +170,28 @@ ul.wiki-pages-list.content-list {
153170
.wiki-form .markdown-area {
154171
max-height: 55vh;
155172
}
173+
174+
.wiki-list {
175+
.wiki-list-expand-button,
176+
.wiki-list-collapse-button {
177+
left: -$gl-spacing-scale-5;
178+
}
179+
180+
.wiki-list-expand-button {
181+
display: none;
182+
}
183+
184+
&.collapsed {
185+
.wiki-list-collapse-button {
186+
display: none;
187+
}
188+
189+
.wiki-list-expand-button {
190+
display: block;
191+
}
192+
}
193+
194+
&.collapsed + ul {
195+
display: none;
196+
}
197+
}

app/helpers/nav/new_dropdown_helper.rb

+6-17
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,7 @@ def group_menu_section(group)
5353
menu_items.push(create_epic_menu_item(group))
5454

5555
if can?(current_user, :admin_group_member, group)
56-
menu_items.push(
57-
invite_members_menu_item(
58-
href: group_group_members_path(group),
59-
partial: 'groups/invite_members_top_nav_link'
60-
)
61-
)
56+
menu_items.push(invite_members_menu_item(partial: 'groups/invite_members_top_nav_link'))
6257
end
6358

6459
{
@@ -105,12 +100,7 @@ def project_menu_section(project)
105100
end
106101

107102
if can_admin_project_member?(project)
108-
menu_items.push(
109-
invite_members_menu_item(
110-
href: project_project_members_path(project),
111-
partial: 'projects/invite_members_top_nav_link'
112-
)
113-
)
103+
menu_items.push(invite_members_menu_item(partial: 'projects/invite_members_top_nav_link'))
114104
end
115105

116106
{
@@ -161,17 +151,16 @@ def general_menu_section
161151
}
162152
end
163153

164-
def invite_members_menu_item(href:, partial:)
154+
def invite_members_menu_item(partial:)
165155
::Gitlab::Nav::TopNavMenuItem.build(
166156
id: 'invite',
167157
title: s_('InviteMember|Invite members'),
168158
icon: 'shaking_hands',
169159
partial: partial,
170-
href: href,
160+
component: 'invite_members',
171161
data: {
172-
track_action: 'click_link_invite_members',
173-
track_label: 'plus_menu_dropdown',
174-
track_property: 'navigation_top'
162+
trigger_source: 'top-nav',
163+
trigger_element: 'text-emoji'
175164
}
176165
)
177166
end

app/models/issue.rb

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ def most_recent
108108
validates :issue_type, presence: true
109109
validates :namespace, presence: true
110110
validates :work_item_type, presence: true
111+
validates :confidential, inclusion: { in: [true, false], message: 'must be a boolean' }
111112

112113
validate :allowed_work_item_type_change, on: :update, if: :work_item_type_id_changed?
113114
validate :due_date_after_start_date

app/services/resource_access_tokens/create_service.rb

+6-10
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# frozen_string_literal: true
22

3+
require 'securerandom'
4+
35
module ResourceAccessTokens
46
class CreateService < BaseService
57
def initialize(current_user, resource, params = {})
@@ -71,21 +73,15 @@ def default_user_params
7173
end
7274

7375
def generate_username
74-
base_username = "#{resource_type}_#{resource.id}_bot"
75-
76-
uniquify.string(base_username) { |s| User.find_by_username(s) }
76+
username
7777
end
7878

7979
def generate_email
80-
email_pattern = "#{resource_type}#{resource.id}_bot%s@noreply.#{Gitlab.config.gitlab.host}"
81-
82-
uniquify.string(-> (n) { Kernel.sprintf(email_pattern, n) }) do |s|
83-
User.find_by_email(s)
84-
end
80+
"#{username}@noreply.#{Gitlab.config.gitlab.host}"
8581
end
8682

87-
def uniquify
88-
Gitlab::Utils::Uniquify.new
83+
def username
84+
@username ||= "#{resource_type}_#{resource.id}_bot_#{SecureRandom.hex(8)}"
8985
end
9086

9187
def create_personal_access_token(user)
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
= link_to local_assigns.fetch(:href), class: local_assigns.fetch(:css_class), data: local_assigns.fetch(:data) do
2-
= local_assigns.fetch(:display_text)
3-
- if local_assigns.fetch(:icon)
4-
= " #{emoji_icon(local_assigns.fetch(:icon), 'aria-hidden': true, class: 'gl-font-base gl-vertical-align-baseline')}".html_safe
1+
- data = local_assigns.fetch(:data)
2+
- data[:display_text] = local_assigns.fetch(:display_text)
3+
- data[:icon] = local_assigns.fetch(:icon)
4+
5+
.js-invite-members-trigger{ data: data }
56

67
= render 'groups/invite_members_modal', group: local_assigns.fetch(:context)

app/views/layouts/header/_new_dropdown.html.haml

-2
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,6 @@
3131
locals: { context: view_model[:context],
3232
display_text: menu_item.fetch(:title),
3333
icon: menu_item.fetch(:icon),
34-
css_class: menu_item.fetch(:css_class),
35-
href: menu_item.fetch(:href),
3634
data: menu_item.fetch(:data) }
3735
- else
3836
= link_to menu_item.fetch(:title),

0 commit comments

Comments
 (0)