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
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-02-16 09:12:24 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-02-16 09:12:24 +0300
commit885897989971931fcb139969b49d8b06f907d7d0 (patch)
tree7c2873a6690b73d0036b56bf379634c235dfb438 /app/assets/javascripts
parentf5c9eb81b000010cf8abc91cbcfd1d6537f66c64 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/design_management/index.js1
-rw-r--r--app/assets/javascripts/emoji/awards_app/index.js1
-rw-r--r--app/assets/javascripts/invite_members/init_invite_members_modal.js1
-rw-r--r--app/assets/javascripts/invite_members/init_invite_members_trigger.js1
-rw-r--r--app/assets/javascripts/issuable/index.js1
-rw-r--r--app/assets/javascripts/issues/related_merge_requests/index.js1
-rw-r--r--app/assets/javascripts/issues/show/index.js3
-rw-r--r--app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_modal.vue34
-rw-r--r--app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js8
-rw-r--r--app/assets/javascripts/lib/utils/text_markdown.js65
-rw-r--r--app/assets/javascripts/nav/mount.js1
-rw-r--r--app/assets/javascripts/notes/discussion_filters.js2
-rw-r--r--app/assets/javascripts/notes/index.js1
-rw-r--r--app/assets/javascripts/notes/sort_discussions.js1
-rw-r--r--app/assets/javascripts/performance_bar/index.js1
-rw-r--r--app/assets/javascripts/popovers/index.js2
-rw-r--r--app/assets/javascripts/projects/project_new.js16
-rw-r--r--app/assets/javascripts/related_issues/index.js2
-rw-r--r--app/assets/javascripts/sidebar/mount_sidebar.js16
-rw-r--r--app/assets/javascripts/tooltips/index.js1
20 files changed, 146 insertions, 13 deletions
diff --git a/app/assets/javascripts/design_management/index.js b/app/assets/javascripts/design_management/index.js
index 4ae76050aa5..b856ac6c627 100644
--- a/app/assets/javascripts/design_management/index.js
+++ b/app/assets/javascripts/design_management/index.js
@@ -24,6 +24,7 @@ export default () => {
return new Vue({
el,
+ name: 'DesignRoot',
router,
apolloProvider,
provide: {
diff --git a/app/assets/javascripts/emoji/awards_app/index.js b/app/assets/javascripts/emoji/awards_app/index.js
index 1a084d37762..0986533dcd1 100644
--- a/app/assets/javascripts/emoji/awards_app/index.js
+++ b/app/assets/javascripts/emoji/awards_app/index.js
@@ -12,6 +12,7 @@ export default (el) => {
return new Vue({
el,
+ name: 'AwardsListRoot',
store: createstore(),
computed: {
...mapState(['currentUserId', 'canAwardEmoji', 'awards']),
diff --git a/app/assets/javascripts/invite_members/init_invite_members_modal.js b/app/assets/javascripts/invite_members/init_invite_members_modal.js
index 588b1c9ef52..e9d620cedf0 100644
--- a/app/assets/javascripts/invite_members/init_invite_members_modal.js
+++ b/app/assets/javascripts/invite_members/init_invite_members_modal.js
@@ -28,6 +28,7 @@ export default function initInviteMembersModal() {
return new Vue({
el,
+ name: 'InviteMembersModalRoot',
provide: {
newProjectPath: el.dataset.newProjectPath,
},
diff --git a/app/assets/javascripts/invite_members/init_invite_members_trigger.js b/app/assets/javascripts/invite_members/init_invite_members_trigger.js
index 935edb35349..54a5eab2e4b 100644
--- a/app/assets/javascripts/invite_members/init_invite_members_trigger.js
+++ b/app/assets/javascripts/invite_members/init_invite_members_trigger.js
@@ -11,6 +11,7 @@ export default function initInviteMembersTrigger() {
return triggers.forEach((el) => {
return new Vue({
el,
+ name: 'InviteMembersTriggerRoot',
render: (createElement) =>
createElement(InviteMembersTrigger, {
props: {
diff --git a/app/assets/javascripts/issuable/index.js b/app/assets/javascripts/issuable/index.js
index 57bad5182e7..00b027523e2 100644
--- a/app/assets/javascripts/issuable/index.js
+++ b/app/assets/javascripts/issuable/index.js
@@ -97,6 +97,7 @@ export function initIssuableHeaderWarnings(store) {
return new Vue({
el,
+ name: 'IssuableHeaderWarningsRoot',
store,
provide: { hidden: parseBoolean(hidden) },
render: (createElement) => createElement(IssuableHeaderWarnings),
diff --git a/app/assets/javascripts/issues/related_merge_requests/index.js b/app/assets/javascripts/issues/related_merge_requests/index.js
index 5045f7e1a2a..196084093c8 100644
--- a/app/assets/javascripts/issues/related_merge_requests/index.js
+++ b/app/assets/javascripts/issues/related_merge_requests/index.js
@@ -13,6 +13,7 @@ export function initRelatedMergeRequests() {
return new Vue({
el,
+ name: 'RelatedMergeRequestsRoot',
store: createStore(),
render: (createElement) =>
createElement(RelatedMergeRequests, {
diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js
index bf4debcdfa9..732bdc09aea 100644
--- a/app/assets/javascripts/issues/show/index.js
+++ b/app/assets/javascripts/issues/show/index.js
@@ -44,6 +44,7 @@ export function initIncidentApp(issueData = {}) {
return new Vue({
el,
+ name: 'DescriptionRoot',
apolloProvider,
provide: {
issueType: INCIDENT_TYPE,
@@ -86,6 +87,7 @@ export function initIssueApp(issueData, store) {
return new Vue({
el,
+ name: 'DescriptionRoot',
apolloProvider,
store,
provide: {
@@ -123,6 +125,7 @@ export function initHeaderActions(store, type = '') {
return new Vue({
el,
+ name: 'HeaderActionsRoot',
apolloProvider,
store,
provide: {
diff --git a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_modal.vue b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_modal.vue
index 733d0f69f5d..f3380b7b4ba 100644
--- a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_modal.vue
+++ b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_modal.vue
@@ -1,13 +1,21 @@
<script>
-import { GlModal } from '@gitlab/ui';
+import { GlModal, GlSafeHtmlDirective } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
cancelAction: { text: __('Cancel') },
+ directives: {
+ SafeHtml: GlSafeHtmlDirective,
+ },
components: {
GlModal,
},
props: {
+ title: {
+ type: String,
+ required: false,
+ default: '',
+ },
primaryText: {
type: String,
required: false,
@@ -18,11 +26,27 @@ export default {
required: false,
default: 'confirm',
},
+ modalHtmlMessage: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ hideCancel: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
},
computed: {
primaryAction() {
return { text: this.primaryText, attributes: { variant: this.primaryVariant } };
},
+ cancelAction() {
+ return this.hideCancel ? null : this.$options.cancelAction;
+ },
+ shouldShowHeader() {
+ return Boolean(this.title?.length);
+ },
},
mounted() {
this.$refs.modal.show();
@@ -36,12 +60,14 @@ export default {
size="sm"
modal-id="confirmationModal"
body-class="gl-display-flex"
+ :title="title"
:action-primary="primaryAction"
- :action-cancel="$options.cancelAction"
- hide-header
+ :action-cancel="cancelAction"
+ :hide-header="!shouldShowHeader"
@primary="$emit('confirmed')"
@hidden="$emit('closed')"
>
- <div class="gl-align-self-center"><slot></slot></div>
+ <div v-if="!modalHtmlMessage" class="gl-align-self-center"><slot></slot></div>
+ <div v-else v-safe-html="modalHtmlMessage" class="gl-align-self-center"></div>
</gl-modal>
</template>
diff --git a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js
index fdd0e045d07..a8a89d0644a 100644
--- a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js
+++ b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js
@@ -1,6 +1,9 @@
import Vue from 'vue';
-export function confirmAction(message, { primaryBtnVariant, primaryBtnText } = {}) {
+export function confirmAction(
+ message,
+ { primaryBtnVariant, primaryBtnText, modalHtmlMessage, title, hideCancel } = {},
+) {
return new Promise((resolve) => {
let confirmed = false;
@@ -15,6 +18,9 @@ export function confirmAction(message, { primaryBtnVariant, primaryBtnText } = {
props: {
primaryVariant: primaryBtnVariant,
primaryText: primaryBtnText,
+ title,
+ modalHtmlMessage,
+ hideCancel,
},
on: {
confirmed() {
diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js
index 40dd29bea76..ec6789d81ec 100644
--- a/app/assets/javascripts/lib/utils/text_markdown.js
+++ b/app/assets/javascripts/lib/utils/text_markdown.js
@@ -5,6 +5,12 @@ import { insertText } from '~/lib/utils/common_utils';
const LINK_TAG_PATTERN = '[{text}](url)';
+// at the start of a line, find any amount of whitespace followed by
+// a bullet point character (*+-) and an optional checkbox ([ ] [x])
+// OR a number with a . after it and an optional checkbox ([ ] [x])
+// followed by one or more whitespace characters
+const LIST_LINE_HEAD_PATTERN = /^(?<indent>\s*)(?<leader>((?<isOl>[*+-])|(?<isUl>\d+\.))( \[([x ])\])?\s)(?<content>.)?/;
+
function selectedText(text, textarea) {
return text.substring(textarea.selectionStart, textarea.selectionEnd);
}
@@ -13,8 +19,15 @@ function addBlockTags(blockTag, selected) {
return `${blockTag}\n${selected}\n${blockTag}`;
}
-function lineBefore(text, textarea) {
- const split = text.substring(0, textarea.selectionStart).trim().split('\n');
+function lineBefore(text, textarea, trimNewlines = true) {
+ let split = text.substring(0, textarea.selectionStart);
+
+ if (trimNewlines) {
+ split = split.trim();
+ }
+
+ split = split.split('\n');
+
return split[split.length - 1];
}
@@ -284,9 +297,9 @@ function updateText({ textArea, tag, cursorOffset, blockTag, wrap, select, tagCo
}
/* eslint-disable @gitlab/require-i18n-strings */
-export function keypressNoteText(e) {
+function handleSurroundSelectedText(e, textArea) {
if (!gon.markdown_surround_selection) return;
- if (this.selectionStart === this.selectionEnd) return;
+ if (textArea.selectionStart === textArea.selectionEnd) return;
const keys = {
'*': '**{text}**', // wraps with bold character
@@ -306,7 +319,7 @@ export function keypressNoteText(e) {
updateText({
tag,
- textArea: this,
+ textArea,
blockTag: '',
wrap: true,
select: '',
@@ -316,6 +329,48 @@ export function keypressNoteText(e) {
}
/* eslint-enable @gitlab/require-i18n-strings */
+function handleContinueList(e, textArea) {
+ if (!gon.features?.markdownContinueLists) return;
+ if (!(e.key === 'Enter')) return;
+ if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
+ if (textArea.selectionStart !== textArea.selectionEnd) return;
+
+ const currentLine = lineBefore(textArea.value, textArea, false);
+ const result = currentLine.match(LIST_LINE_HEAD_PATTERN);
+
+ if (result) {
+ const { indent, content, leader } = result.groups;
+ const prevLineEmpty = !content;
+
+ if (prevLineEmpty) {
+ // erase previous empty list item - select the text and allow the
+ // natural line feed erase the text
+ textArea.selectionStart = textArea.selectionStart - result[0].length;
+ return;
+ }
+
+ const itemInsert = `${indent}${leader}`;
+
+ e.preventDefault();
+
+ updateText({
+ tag: itemInsert,
+ textArea,
+ blockTag: '',
+ wrap: false,
+ select: '',
+ tagContent: '',
+ });
+ }
+}
+
+export function keypressNoteText(e) {
+ const textArea = this;
+
+ handleContinueList(e, textArea);
+ handleSurroundSelectedText(e, textArea);
+}
+
export function updateTextForToolbarBtn($toolbarBtn) {
return updateText({
textArea: $toolbarBtn.closest('.md-area').find('textarea'),
diff --git a/app/assets/javascripts/nav/mount.js b/app/assets/javascripts/nav/mount.js
index 51b6a31b8cb..7b0cc977107 100644
--- a/app/assets/javascripts/nav/mount.js
+++ b/app/assets/javascripts/nav/mount.js
@@ -12,6 +12,7 @@ const mount = (el, Component) => {
return new Vue({
el,
+ name: 'TopNavRoot',
store,
render(h) {
return h(Component, {
diff --git a/app/assets/javascripts/notes/discussion_filters.js b/app/assets/javascripts/notes/discussion_filters.js
index 7c9e7703d59..104e9d4183a 100644
--- a/app/assets/javascripts/notes/discussion_filters.js
+++ b/app/assets/javascripts/notes/discussion_filters.js
@@ -19,7 +19,7 @@ export default (store) => {
return new Vue({
el: discussionFilterEl,
- name: 'DiscussionFilter',
+ name: 'DiscussionFilterRoot',
components: {
DiscussionFilter,
},
diff --git a/app/assets/javascripts/notes/index.js b/app/assets/javascripts/notes/index.js
index 2ce60976adb..19fa484d659 100644
--- a/app/assets/javascripts/notes/index.js
+++ b/app/assets/javascripts/notes/index.js
@@ -14,6 +14,7 @@ export default () => {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'NotesRoot',
components: {
notesApp,
},
diff --git a/app/assets/javascripts/notes/sort_discussions.js b/app/assets/javascripts/notes/sort_discussions.js
index ecfa3223039..ca8df880fe4 100644
--- a/app/assets/javascripts/notes/sort_discussions.js
+++ b/app/assets/javascripts/notes/sort_discussions.js
@@ -8,6 +8,7 @@ export default (store) => {
return new Vue({
el,
+ name: 'SortDiscussionRoot',
store,
render(createElement) {
return createElement(SortDiscussion);
diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js
index 66e999ca43b..eb5b50dd1ec 100644
--- a/app/assets/javascripts/performance_bar/index.js
+++ b/app/assets/javascripts/performance_bar/index.js
@@ -20,6 +20,7 @@ const initPerformanceBar = (el) => {
return new Vue({
el,
+ name: 'PerformanceBarRoot',
components: {
PerformanceBarApp: () => import('./components/performance_bar_app.vue'),
},
diff --git a/app/assets/javascripts/popovers/index.js b/app/assets/javascripts/popovers/index.js
index 7db669b8c52..94340ae16a0 100644
--- a/app/assets/javascripts/popovers/index.js
+++ b/app/assets/javascripts/popovers/index.js
@@ -13,7 +13,7 @@ const getPopoversApp = () => {
document.body.appendChild(container);
const Popovers = Vue.extend(PopoversComponent);
- app = new Popovers();
+ app = new Popovers({ name: 'PopoversRoot' });
app.$mount(`#${APP_ELEMENT_ID}`);
}
diff --git a/app/assets/javascripts/projects/project_new.js b/app/assets/javascripts/projects/project_new.js
index 55913394ca3..62e2cec874a 100644
--- a/app/assets/javascripts/projects/project_new.js
+++ b/app/assets/javascripts/projects/project_new.js
@@ -1,6 +1,7 @@
import $ from 'jquery';
import { debounce } from 'lodash';
import DEFAULT_PROJECT_TEMPLATES from 'ee_else_ce/projects/default_project_templates';
+import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '../lib/utils/constants';
import axios from '../lib/utils/axios_utils';
import {
@@ -105,6 +106,21 @@ const deriveProjectPathFromUrl = ($projectImportUrl) => {
};
const bindHowToImport = () => {
+ const importLinks = document.querySelectorAll('.js-how-to-import-link');
+
+ importLinks.forEach((link) => {
+ const { modalTitle: title, modalMessage: modalHtmlMessage } = link.dataset;
+
+ link.addEventListener('click', (e) => {
+ e.preventDefault();
+ confirmAction('', {
+ modalHtmlMessage,
+ title,
+ hideCancel: true,
+ });
+ });
+ });
+
$('.how_to_import_link').on('click', (e) => {
e.preventDefault();
$(e.currentTarget).next('.modal').show();
diff --git a/app/assets/javascripts/related_issues/index.js b/app/assets/javascripts/related_issues/index.js
index bd9845e616b..35858be90b2 100644
--- a/app/assets/javascripts/related_issues/index.js
+++ b/app/assets/javascripts/related_issues/index.js
@@ -8,7 +8,7 @@ export default function initRelatedIssues() {
// eslint-disable-next-line no-new
new Vue({
el: relatedIssuesRootElement,
- name: 'RelatedIssuesApp',
+ name: 'RelatedIssuesRoot',
components: {
relatedIssuesRoot: RelatedIssuesRoot,
},
diff --git a/app/assets/javascripts/sidebar/mount_sidebar.js b/app/assets/javascripts/sidebar/mount_sidebar.js
index 6363422259e..c29784aa328 100644
--- a/app/assets/javascripts/sidebar/mount_sidebar.js
+++ b/app/assets/javascripts/sidebar/mount_sidebar.js
@@ -57,6 +57,7 @@ function mountSidebarToDoWidget() {
return new Vue({
el,
+ name: 'SidebarTodoRoot',
apolloProvider,
components: {
SidebarTodoWidget,
@@ -103,6 +104,7 @@ function mountAssigneesComponentDeprecated(mediator) {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarAssigneesRoot',
apolloProvider,
components: {
SidebarAssignees,
@@ -135,6 +137,7 @@ function mountAssigneesComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarAssigneesRoot',
apolloProvider,
components: {
SidebarAssigneesWidget,
@@ -185,6 +188,7 @@ function mountReviewersComponent(mediator) {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarReviewersRoot',
apolloProvider,
components: {
SidebarReviewers,
@@ -218,6 +222,7 @@ function mountCrmContactsComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarCrmContactsRoot',
apolloProvider,
components: {
CrmContacts,
@@ -242,6 +247,7 @@ function mountMilestoneSelect() {
return new Vue({
el,
+ name: 'SidebarMilestoneRoot',
apolloProvider,
components: {
SidebarDropdownWidget,
@@ -274,6 +280,7 @@ export function mountSidebarLabels() {
return new Vue({
el,
+ name: 'SidebarLabelsRoot',
apolloProvider,
components: {
@@ -328,6 +335,7 @@ function mountConfidentialComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarConfidentialRoot',
apolloProvider,
components: {
SidebarConfidentialityWidget,
@@ -362,6 +370,7 @@ function mountDueDateComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarDueDateRoot',
apolloProvider,
components: {
SidebarDueDateWidget,
@@ -392,6 +401,7 @@ function mountReferenceComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarReferenceRoot',
apolloProvider,
components: {
SidebarReferenceWidget,
@@ -428,6 +438,7 @@ function mountLockComponent(store) {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarLockRoot',
store,
provide: {
fullPath,
@@ -451,6 +462,7 @@ function mountParticipantsComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarParticipantsRoot',
apolloProvider,
components: {
SidebarParticipantsWidget,
@@ -479,6 +491,7 @@ function mountSubscriptionsComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarSubscriptionsRoot',
apolloProvider,
components: {
SidebarSubscriptionsWidget,
@@ -509,6 +522,7 @@ function mountTimeTrackingComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarTimeTrackingRoot',
apolloProvider,
provide: { issuableType },
render: (createElement) =>
@@ -534,6 +548,7 @@ function mountSeverityComponent() {
return new Vue({
el: severityContainerEl,
+ name: 'SidebarSeverityRoot',
apolloProvider,
components: {
SidebarSeverity,
@@ -562,6 +577,7 @@ function mountCopyEmailComponent() {
// eslint-disable-next-line no-new
new Vue({
el,
+ name: 'SidebarCopyEmailRoot',
render: (createElement) =>
createElement(CopyEmailToClipboard, { props: { issueEmailAddress: createNoteEmail } }),
});
diff --git a/app/assets/javascripts/tooltips/index.js b/app/assets/javascripts/tooltips/index.js
index 49a43b120e0..4639671984a 100644
--- a/app/assets/javascripts/tooltips/index.js
+++ b/app/assets/javascripts/tooltips/index.js
@@ -21,6 +21,7 @@ const tooltipsApp = () => {
document.body.appendChild(container);
app = new Vue({
+ name: 'TooltipsRoot',
render(h) {
return h(Tooltips, {
props: {