diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-07 18:07:59 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-03-07 18:07:59 +0000 |
commit | 3ff3d897d6529aabb21aa6aed54eb430a9cf0fe2 (patch) | |
tree | d5aaf0b6766cd5d4118e8ccd57d1269d3e4d673e /app | |
parent | 807c4eae46f96ccd54ce1d8d13f4547eda017267 (diff) | |
download | gitlab-ce-3ff3d897d6529aabb21aa6aed54eb430a9cf0fe2.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
52 files changed, 311 insertions, 97 deletions
diff --git a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue index 7dd33da435a..cc8913c2f45 100644 --- a/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue +++ b/app/assets/javascripts/alerts_settings/components/alerts_settings_wrapper.vue @@ -2,7 +2,7 @@ import { GlButton, GlAlert, GlTabs, GlTab } from '@gitlab/ui'; import createHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql'; import updateHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql'; -import { createAlert, VARIANT_SUCCESS } from '~/flash'; +import { createAlert, VARIANT_SUCCESS } from '~/alert'; import { fetchPolicies } from '~/lib/graphql'; import { HTTP_STATUS_FORBIDDEN } from '~/lib/utils/http_status'; import { typeSet, i18n, tabIndices } from '../constants'; diff --git a/app/assets/javascripts/alerts_settings/utils/cache_updates.js b/app/assets/javascripts/alerts_settings/utils/cache_updates.js index 2e64312b0e0..e03ebffd17a 100644 --- a/app/assets/javascripts/alerts_settings/utils/cache_updates.js +++ b/app/assets/javascripts/alerts_settings/utils/cache_updates.js @@ -1,5 +1,5 @@ import produce from 'immer'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { DELETE_INTEGRATION_ERROR, ADD_INTEGRATION_ERROR } from './error_messages'; diff --git a/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue index 354db88f11c..06b80a65528 100644 --- a/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue +++ b/app/assets/javascripts/content_editor/components/bubble_menus/formatting_bubble_menu.vue @@ -7,6 +7,7 @@ import Heading from '../../extensions/heading'; import Audio from '../../extensions/audio'; import Video from '../../extensions/video'; import Image from '../../extensions/image'; +import DrawioDiagram from '../../extensions/drawio_diagram'; import ToolbarButton from '../toolbar_button.vue'; import BubbleMenu from './bubble_menu.vue'; @@ -26,7 +27,7 @@ export default { if (from === to) return false; const includes = [Paragraph.name, Heading.name]; - const excludes = [Image.name, Audio.name, Video.name]; + const excludes = [Image.name, Audio.name, Video.name, DrawioDiagram.name]; return ( includes.some((type) => editor.isActive(type)) && diff --git a/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue b/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue index 310bb1be81f..a14d49922fb 100644 --- a/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue +++ b/app/assets/javascripts/content_editor/components/bubble_menus/media_bubble_menu.vue @@ -11,23 +11,26 @@ import { } from '@gitlab/ui'; import { __ } from '~/locale'; import Audio from '../../extensions/audio'; +import DrawioDiagram from '../../extensions/drawio_diagram'; import Image from '../../extensions/image'; import Video from '../../extensions/video'; import EditorStateObserver from '../editor_state_observer.vue'; import { acceptedMimes } from '../../services/upload_helpers'; import BubbleMenu from './bubble_menu.vue'; -const MEDIA_TYPES = [Audio.name, Image.name, Video.name]; +const MEDIA_TYPES = [Audio.name, Image.name, Video.name, DrawioDiagram.name]; export default { i18n: { copySourceLabels: { [Audio.name]: __('Copy audio URL'), + [DrawioDiagram.name]: __('Copy diagram URL'), [Image.name]: __('Copy image URL'), [Video.name]: __('Copy video URL'), }, editLabels: { [Audio.name]: __('Edit audio description'), + [DrawioDiagram.name]: __('Edit diagram description'), [Image.name]: __('Edit image description'), [Video.name]: __('Edit video description'), }, @@ -38,6 +41,7 @@ export default { }, deleteLabels: { [Audio.name]: __('Delete audio'), + [DrawioDiagram.name]: __('Delete diagram'), [Image.name]: __('Delete image'), [Video.name]: __('Delete video'), }, @@ -86,6 +90,9 @@ export default { showProgressIndicator() { return this.isUploading || this.isUpdating; }, + isDrawioDiagram() { + return this.mediaType === DrawioDiagram.name; + }, }, methods: { shouldShow() { @@ -156,10 +163,21 @@ export default { this.isUpdating = false; }, + resetMediaInfo() { + this.mediaTitle = null; + this.mediaAlt = null; + this.mediaCanonicalSrc = null; + this.isUploading = false; + }, + replaceMedia() { this.$refs.fileSelector.click(); }, + editDiagram() { + this.tiptapEditor.chain().focus().createOrEditDiagram().run(); + }, + onFileSelect(e) { this.tiptapEditor .chain() @@ -191,6 +209,8 @@ export default { class="gl-shadow gl-rounded-base gl-bg-white" plugin-key="bubbleMenuMedia" :should-show="shouldShow" + @show="updateMediaInfoToState" + @hidden="resetMediaInfo" > <editor-state-observer @transaction="updateMediaInfoToState"> <gl-button-group v-if="!isEditing" class="gl-display-flex gl-align-items-center"> @@ -240,6 +260,19 @@ export default { @click="startEditingMedia" /> <gl-button + v-if="isDrawioDiagram" + v-gl-tooltip + variant="default" + category="tertiary" + size="medium" + data-testid="edit-diagram" + :aria-label="replaceLabel" + title="Edit diagram" + icon="diagram" + @click="editDiagram" + /> + <gl-button + v-else v-gl-tooltip variant="default" category="tertiary" diff --git a/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue b/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue index ca17443081c..7edc99d0e6b 100644 --- a/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue +++ b/app/assets/javascripts/content_editor/components/toolbar_more_dropdown.vue @@ -54,6 +54,10 @@ export default { action: () => this.insert('diagram', { language: 'plantuml' }), }, { + text: __('Create or edit diagram'), + action: () => this.execute('createOrEditDiagram', 'drawioDiagram'), + }, + { text: __('Table of contents'), action: () => this.execute('insertTableOfContents', 'tableOfContents'), }, diff --git a/app/assets/javascripts/content_editor/constants/index.js b/app/assets/javascripts/content_editor/constants/index.js index 14862727811..6a3740a5952 100644 --- a/app/assets/javascripts/content_editor/constants/index.js +++ b/app/assets/javascripts/content_editor/constants/index.js @@ -47,6 +47,7 @@ export const KEYDOWN_EVENT = 'keydown'; export const PARSE_HTML_PRIORITY_LOWEST = 1; export const PARSE_HTML_PRIORITY_DEFAULT = 50; +export const PARSE_HTML_PRIORITY_HIGH = 75; export const PARSE_HTML_PRIORITY_HIGHEST = 100; export const EXTENSION_PRIORITY_LOWER = 75; diff --git a/app/assets/javascripts/content_editor/extensions/drawio_diagram.js b/app/assets/javascripts/content_editor/extensions/drawio_diagram.js new file mode 100644 index 00000000000..8c3012ecf59 --- /dev/null +++ b/app/assets/javascripts/content_editor/extensions/drawio_diagram.js @@ -0,0 +1,41 @@ +import { create } from '~/drawio/content_editor_facade'; +import { launchDrawioEditor } from '~/drawio/drawio_editor'; +import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants'; +import createAssetResolver from '../services/asset_resolver'; +import Image from './image'; + +export default Image.extend({ + name: 'drawioDiagram', + addOptions() { + return { + ...this.parent?.(), + uploadsPath: null, + renderMarkdown: null, + }; + }, + parseHTML() { + return [ + { + priority: PARSE_HTML_PRIORITY_HIGHEST, + tag: 'a.no-attachment-icon[data-canonical-src$="drawio.svg"]', + }, + { + tag: 'img[src]', + }, + ]; + }, + addCommands() { + return { + createOrEditDiagram: () => () => { + launchDrawioEditor({ + editorFacade: create({ + tiptapEditor: this.editor, + drawioNodeName: this.name, + uploadsPath: this.options.uploadsPath, + assetResolver: createAssetResolver({ renderMarkdown: this.options.renderMarkdown }), + }), + }); + }, + }; + }, +}); diff --git a/app/assets/javascripts/content_editor/extensions/image.js b/app/assets/javascripts/content_editor/extensions/image.js index fc4c108b773..58c16297886 100644 --- a/app/assets/javascripts/content_editor/extensions/image.js +++ b/app/assets/javascripts/content_editor/extensions/image.js @@ -1,5 +1,5 @@ import { Image } from '@tiptap/extension-image'; -import { PARSE_HTML_PRIORITY_HIGHEST } from '../constants'; +import { PARSE_HTML_PRIORITY_HIGH } from '../constants'; const resolveImageEl = (element) => element.nodeName === 'IMG' ? element : element.querySelector('img'); @@ -77,7 +77,7 @@ export default Image.extend({ parseHTML() { return [ { - priority: PARSE_HTML_PRIORITY_HIGHEST, + priority: PARSE_HTML_PRIORITY_HIGH, tag: 'a.no-attachment-icon', }, { diff --git a/app/assets/javascripts/content_editor/services/create_content_editor.js b/app/assets/javascripts/content_editor/services/create_content_editor.js index 61c6be574d0..c9ed0bb2757 100644 --- a/app/assets/javascripts/content_editor/services/create_content_editor.js +++ b/app/assets/javascripts/content_editor/services/create_content_editor.js @@ -16,6 +16,7 @@ import DescriptionList from '../extensions/description_list'; import Details from '../extensions/details'; import DetailsContent from '../extensions/details_content'; import Diagram from '../extensions/diagram'; +import DrawioDiagram from '../extensions/drawio_diagram'; import Document from '../extensions/document'; import Dropcursor from '../extensions/dropcursor'; import Emoji from '../extensions/emoji'; @@ -109,6 +110,7 @@ export const createContentEditor = ({ DetailsContent, Document, Diagram, + DrawioDiagram.configure({ uploadsPath, renderMarkdown }), Dropcursor, Emoji, Figure, diff --git a/app/assets/javascripts/content_editor/services/markdown_serializer.js b/app/assets/javascripts/content_editor/services/markdown_serializer.js index 4e29f85004b..e27a427372c 100644 --- a/app/assets/javascripts/content_editor/services/markdown_serializer.js +++ b/app/assets/javascripts/content_editor/services/markdown_serializer.js @@ -12,6 +12,7 @@ import DescriptionItem from '../extensions/description_item'; import DescriptionList from '../extensions/description_list'; import Details from '../extensions/details'; import DetailsContent from '../extensions/details_content'; +import DrawioDiagram from '../extensions/drawio_diagram'; import Comment from '../extensions/comment'; import Diagram from '../extensions/diagram'; import Emoji from '../extensions/emoji'; @@ -134,6 +135,10 @@ const defaultSerializerConfig = { [CodeBlockHighlight.name]: preserveUnchanged(renderCodeBlock), [Comment.name]: renderComment, [Diagram.name]: preserveUnchanged(renderCodeBlock), + [DrawioDiagram.name]: preserveUnchanged({ + render: renderImage, + inline: true, + }), [DescriptionList.name]: renderHTMLNode('dl', true), [DescriptionItem.name]: (state, node, parent, index) => { if (index === 1) state.ensureNewLine(); diff --git a/app/assets/javascripts/content_editor/services/upload_helpers.js b/app/assets/javascripts/content_editor/services/upload_helpers.js index 09f0738b51b..abfb73183dd 100644 --- a/app/assets/javascripts/content_editor/services/upload_helpers.js +++ b/app/assets/javascripts/content_editor/services/upload_helpers.js @@ -4,17 +4,27 @@ import { __ } from '~/locale'; import { extractFilename, readFileAsDataURL } from './utils'; export const acceptedMimes = { - image: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'], - audio: [ - 'audio/basic', - 'audio/mid', - 'audio/mpeg', - 'audio/x-aiff', - 'audio/ogg', - 'audio/vorbis', - 'audio/vnd.wav', - ], - video: ['video/mp4', 'video/quicktime'], + drawioDiagram: { + mimes: ['image/svg+xml'], + ext: 'drawio.svg', + }, + image: { + mimes: ['image/jpeg', 'image/png', 'image/gif', 'image/jpg'], + }, + audio: { + mimes: [ + 'audio/basic', + 'audio/mid', + 'audio/mpeg', + 'audio/x-aiff', + 'audio/ogg', + 'audio/vorbis', + 'audio/vnd.wav', + ], + }, + video: { + mimes: ['video/mp4', 'video/quicktime'], + }, }; const extractAttachmentLinkUrl = (html) => { @@ -128,8 +138,8 @@ const uploadAttachment = async ({ editor, file, uploadsPath, renderMarkdown, eve export const handleFileEvent = ({ editor, file, uploadsPath, renderMarkdown, eventHub }) => { if (!file) return false; - for (const [type, mimes] of Object.entries(acceptedMimes)) { - if (mimes.includes(file?.type)) { + for (const [type, { mimes, ext }] of Object.entries(acceptedMimes)) { + if (mimes.includes(file?.type) && (!ext || file?.name.endsWith(ext))) { uploadContent({ type, editor, file, uploadsPath, renderMarkdown, eventHub }); return true; diff --git a/app/assets/javascripts/drawio/constants.js b/app/assets/javascripts/drawio/constants.js index a5f1d1e71d2..2e1e074db3b 100644 --- a/app/assets/javascripts/drawio/constants.js +++ b/app/assets/javascripts/drawio/constants.js @@ -11,3 +11,5 @@ export const DARK_BACKGROUND_COLOR = '#202020'; export const DIAGRAM_BACKGROUND_COLOR = '#ffffff'; export const DRAWIO_IFRAME_TIMEOUT = 4000; + +export const DIAGRAM_MAX_SIZE = 10 * 1024 * 1024; // 1MB diff --git a/app/assets/javascripts/drawio/content_editor_facade.js b/app/assets/javascripts/drawio/content_editor_facade.js new file mode 100644 index 00000000000..1c41194c1f5 --- /dev/null +++ b/app/assets/javascripts/drawio/content_editor_facade.js @@ -0,0 +1,80 @@ +import axios from '~/lib/utils/axios_utils'; + +/** + * A set of functions to decouple the content_editor component from + * the draw.io editor. + * It allows the draw.io editor to obtain a selected drawio_diagram + * and replace it or insert a new drawio_diagram node without coupling + * the drawio_editor to the Content Editor implementation details + * * + * @param {Object} params Factory function parameters + * @param {Object} params.tiptapEditor See https://tiptap.dev/api/editor + * @param {String} params.drawioNodeName Name of the drawio_diagram node in + * the ProseMirror document + * @param {String} params.uploadsPath API endpoint to upload files + * @param {Object} params.assetResolver See + * app/assets/javascripts/content_editor/services/asset_resolver.js + * + * @returns A content_editor_facade object with operations + * to get a selected diagram, upload a diagram, insert a new one in the + * Content Editor, and update an existing’s diagram URL. + */ +export const create = ({ tiptapEditor, drawioNodeName, uploadsPath, assetResolver }) => ({ + getDiagram: async () => { + const { node } = tiptapEditor.state.selection; + + if (!node || node.type.name !== drawioNodeName) { + return null; + } + + const { src } = node.attrs; + const response = await axios.get(src, { responseType: 'text' }); + const diagramSvg = response.data; + const contentType = response.headers['content-type']; + const filename = src.split('/').pop(); + + return { + diagramURL: src, + filename, + diagramSvg, + contentType, + }; + }, + updateDiagram: async ({ uploadResults: { file_path: canonicalSrc } }) => { + const src = await assetResolver.resolveUrl(canonicalSrc); + + tiptapEditor + .chain() + .focus() + .updateAttributes(drawioNodeName, { + src, + canonicalSrc, + }) + .run(); + }, + insertDiagram: async ({ uploadResults: { file_path: canonicalSrc } }) => { + const src = await assetResolver.resolveUrl(canonicalSrc); + + tiptapEditor + .chain() + .focus() + .insertContent({ + type: drawioNodeName, + attrs: { + src, + canonicalSrc, + }, + }) + .run(); + }, + uploadDiagram: async ({ filename, diagramSvg }) => { + const blob = new Blob([diagramSvg], { type: 'image/svg+xml' }); + const formData = new FormData(); + + formData.append('file', blob, filename); + + const response = await axios.post(uploadsPath, formData); + + return response.data; + }, +}); diff --git a/app/assets/javascripts/drawio/drawio_editor.js b/app/assets/javascripts/drawio/drawio_editor.js index 06e7f536426..9668c2835ce 100644 --- a/app/assets/javascripts/drawio/drawio_editor.js +++ b/app/assets/javascripts/drawio/drawio_editor.js @@ -9,6 +9,7 @@ import { DRAWIO_FRAME_ID, DIAGRAM_BACKGROUND_COLOR, DRAWIO_IFRAME_TIMEOUT, + DIAGRAM_MAX_SIZE, } from './constants'; function updateDrawioEditorState(drawIOEditorState, data) { @@ -109,14 +110,24 @@ async function loadExistingDiagram(drawIOEditorState, editorFacade) { try { diagram = await editorFacade.getDiagram(); } catch (e) { - throw new Error(__('Cannot load the diagram into the draw.io editor')); + throw new Error(__('Cannot load the diagram into the diagrams.net editor')); } if (diagram) { - const { diagramMarkdown, filename, diagramSvg, contentType } = diagram; + const { diagramMarkdown, filename, diagramSvg, contentType, diagramURL } = diagram; + const resolvedURL = new URL(diagramURL, window.location.origin); + const diagramSvgSize = new Blob([diagramSvg]).size; if (contentType !== 'image/svg+xml') { - throw new Error(__('The selected image is not a diagram')); + throw new Error(__('The selected image is not a valid SVG diagram')); + } + + if (resolvedURL.origin !== window.location.origin) { + throw new Error(__('The selected image is not an asset uploaded in the application')); + } + + if (diagramSvgSize > DIAGRAM_MAX_SIZE) { + throw new Error(__('The selected image is too large.')); } updateDrawioEditorState(drawIOEditorState, { @@ -142,7 +153,7 @@ async function prepareEditor(drawIOEditorState, editorFacade) { try { await loadExistingDiagram(drawIOEditorState, editorFacade); - iframe.style.visibility = ''; + iframe.style.visibility = 'visible'; iframe.style.cursor = ''; window.scrollTo(0, 0); } catch (e) { @@ -212,23 +223,15 @@ function createEditorIFrame(drawIOEditorState) { setAttributes(iframe, { id: DRAWIO_FRAME_ID, src: DRAWIO_EDITOR_URL, + class: 'drawio-editor', }); - iframe.style.position = 'absolute'; - iframe.style.border = '0'; - iframe.style.top = '0px'; - iframe.style.left = '0px'; - iframe.style.width = '100%'; - iframe.style.height = '100%'; - iframe.style.zIndex = '1100'; - iframe.style.visibility = 'hidden'; - document.body.appendChild(iframe); setTimeout(() => { if (drawIOEditorState.initialized === false) { disposeDrawioEditor(drawIOEditorState); - createAlert({ message: __('The draw.io editor could not be loaded.') }); + createAlert({ message: __('The diagrams.net editor could not be loaded.') }); } }, DRAWIO_IFRAME_TIMEOUT); diff --git a/app/assets/javascripts/drawio/markdown_field_editor_facade.js b/app/assets/javascripts/drawio/markdown_field_editor_facade.js index b2506ce6bf8..4ef203c7aa0 100644 --- a/app/assets/javascripts/drawio/markdown_field_editor_facade.js +++ b/app/assets/javascripts/drawio/markdown_field_editor_facade.js @@ -32,6 +32,7 @@ export const create = ({ textArea, markdownPreviewPath, uploadsPath }) => ({ const contentType = response.headers['content-type']; return { + diagramURL: imageURL, diagramMarkdown: imageMarkdown, filename, diagramSvg, diff --git a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue index 89400bc4742..420c34a88f1 100644 --- a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue +++ b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue @@ -8,7 +8,7 @@ import { GlSearchBoxByType, } from '@gitlab/ui'; import { debounce } from 'lodash'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { __, sprintf } from '~/locale'; diff --git a/app/assets/javascripts/issuable/components/csv_export_modal.vue b/app/assets/javascripts/issuable/components/csv_export_modal.vue index 736da92fa9f..c1de507cd80 100644 --- a/app/assets/javascripts/issuable/components/csv_export_modal.vue +++ b/app/assets/javascripts/issuable/components/csv_export_modal.vue @@ -1,7 +1,7 @@ <script> import { GlModal, GlSprintf, GlIcon } from '@gitlab/ui'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __, n__ } from '~/locale'; -import { ISSUABLE_TYPE } from '../constants'; export default { actionCancel: { @@ -19,7 +19,7 @@ export default { }, inject: { issuableType: { - default: ISSUABLE_TYPE.issues, + default: TYPE_ISSUE, }, email: { default: '', @@ -47,14 +47,17 @@ export default { href: this.exportCsvPath, variant: 'confirm', 'data-method': 'post', - 'data-qa-selector': `export_${this.issuableType}_button`, + 'data-qa-selector': `export_issues_button`, 'data-track-action': 'click_button', - 'data-track-label': `export_${this.issuableType}_csv`, + 'data-track-label': this.dataTrackLabel, }, }; }, isIssue() { - return this.issuableType === ISSUABLE_TYPE.issues; + return this.issuableType === TYPE_ISSUE; + }, + dataTrackLabel() { + return this.isIssue ? 'export_issues_csv' : 'export_merge-requests_csv'; }, exportText() { return this.isIssue ? __('Export issues') : __('Export merge requests'); diff --git a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue index dadb1419649..2cc01c302ec 100644 --- a/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue +++ b/app/assets/javascripts/issuable/components/csv_import_export_buttons.vue @@ -7,8 +7,8 @@ import { GlTooltipDirective, GlModalDirective, } from '@gitlab/ui'; +import { TYPE_ISSUE } from '~/issues/constants'; import { __ } from '~/locale'; -import { ISSUABLE_TYPE } from '../constants'; import CsvExportModal from './csv_export_modal.vue'; import CsvImportModal from './csv_import_modal.vue'; @@ -34,7 +34,7 @@ export default { }, inject: { issuableType: { - default: ISSUABLE_TYPE.issues, + default: TYPE_ISSUE, }, showExportButton: { default: false, diff --git a/app/assets/javascripts/issuable/constants.js b/app/assets/javascripts/issuable/constants.js index 5327f251fda..88fc6859acd 100644 --- a/app/assets/javascripts/issuable/constants.js +++ b/app/assets/javascripts/issuable/constants.js @@ -1,11 +1 @@ export const EVENT_ISSUABLE_VUE_APP_CHANGE = 'issuable_vue_app:change'; - -export const ISSUABLE_TYPE = { - issues: 'issues', - mergeRequests: 'merge-requests', -}; - -export const ISSUABLE_INDEX = { - ISSUE: 'issue_', - MERGE_REQUEST: 'merge_request_', -}; diff --git a/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue b/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue index 40cb7fbb0ff..c2b7d33c14c 100644 --- a/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue +++ b/app/assets/javascripts/issues/show/components/incidents/create_timeline_event.vue @@ -113,7 +113,7 @@ export default { > <div v-if="hasTimelineEvents" - class="gl-display-flex gl-align-items-center gl-justify-content-center gl-align-self-start gl-bg-white gl-text-gray-200 gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-full gl-mt-2 gl-w-8 gl-h-8 gl-z-index-1" + class="gl-display-flex gl-align-items-center gl-justify-content-center gl-align-self-start gl-bg-white gl-text-gray-200 gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-full gl-mt-2 gl-w-8 gl-h-8 gl-flex-shrink-0 gl-p-3 gl-z-index-1" > <gl-icon name="comment" class="note-icon" /> </div> diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue index 7944362a40f..243666b2323 100644 --- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue +++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_form.vue @@ -255,11 +255,10 @@ export default { </gl-form-group> </div> <gl-form-group class="gl-mb-0"> - <div class="gl-display-flex"> + <div class="gl-display-flex gl-flex-wrap gl-gap-3"> <gl-button variant="confirm" category="primary" - class="gl-mr-3" data-testid="save-button" :disabled="!isTimelineTextValid" :loading="isEventProcessed" @@ -271,7 +270,6 @@ export default { v-if="showSaveAndAdd" variant="confirm" category="secondary" - class="gl-mr-3 gl-ml-n2" data-testid="save-and-add-button" :disabled="!isTimelineTextValid" :loading="isEventProcessed" @@ -279,7 +277,7 @@ export default { > {{ $options.i18n.saveAndAdd }} </gl-button> - <gl-button class="gl-ml-n2" :disabled="isEventProcessed" @click="$emit('cancel')"> + <gl-button :disabled="isEventProcessed" @click="$emit('cancel')"> {{ $options.i18n.cancel }} </gl-button> <gl-button diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue index fdc6e75c932..ea6ebb614f4 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/pypi_installation.vue @@ -28,6 +28,9 @@ export default { }, }, computed: { + isPrivatePackage() { + return !this.packageEntity.publicPackage; + }, pypiPipCommand() { // eslint-disable-next-line @gitlab/require-i18n-strings return `pip install ${this.packageEntity.name} --index-url ${this.packageEntity.pypiUrl}`; @@ -75,7 +78,7 @@ password = <your personal access token>`; :tracking-action="$options.tracking.TRACKING_ACTION_COPY_PIP_INSTALL_COMMAND" :tracking-label="$options.tracking.TRACKING_LABEL_CODE_INSTRUCTION" /> - <template #description> + <template v-if="isPrivatePackage" #description> <gl-sprintf :message="$options.i18n.tokenText"> <template #link="{ content }"> <gl-link diff --git a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql index 109d535469b..b5313f929f8 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql +++ b/app/assets/javascripts/packages_and_registries/package_registry/graphql/queries/get_package_details.query.graphql @@ -15,6 +15,7 @@ query getPackageDetails( updatedAt status canDestroy + publicPackage npmUrl mavenUrl conanUrl diff --git a/app/assets/javascripts/pages/projects/merge_requests/index/index.js b/app/assets/javascripts/pages/projects/merge_requests/index/index.js index af75c05b300..3ae8018714a 100644 --- a/app/assets/javascripts/pages/projects/merge_requests/index/index.js +++ b/app/assets/javascripts/pages/projects/merge_requests/index/index.js @@ -3,10 +3,9 @@ import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation'; import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys'; import { FILTERED_SEARCH } from '~/filtered_search/constants'; import { initBulkUpdateSidebar, initCsvImportExportButtons, initIssuableByEmail } from '~/issuable'; -import { ISSUABLE_INDEX } from '~/issuable/constants'; import initFilteredSearch from '~/pages/search/init_filtered_search'; -initBulkUpdateSidebar(ISSUABLE_INDEX.MERGE_REQUEST); +initBulkUpdateSidebar('merge_request_'); addExtraTokensForMergeRequests(IssuableFilteredSearchTokenKeys); IssuableFilteredSearchTokenKeys.removeTokensForKeys('iteration'); diff --git a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue index 6e7c85053dc..6edd6530bc5 100644 --- a/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue +++ b/app/assets/javascripts/projects/settings/branch_rules/components/view/index.vue @@ -71,7 +71,7 @@ export default { }, computed: { forcePushAttributes() { - const { allowForcePush } = this.branchProtection; + const { allowForcePush } = this.branchProtection || {}; const icon = allowForcePush ? REQUIRED_ICON : NOT_REQUIRED_ICON; const iconClass = allowForcePush ? REQUIRED_ICON_CLASS : NOT_REQUIRED_ICON_CLASS; const title = allowForcePush @@ -81,7 +81,7 @@ export default { return { icon, iconClass, title }; }, codeOwnersApprovalAttributes() { - const { codeOwnerApprovalRequired } = this.branchProtection; + const { codeOwnerApprovalRequired } = this.branchProtection || {}; const icon = codeOwnerApprovalRequired ? REQUIRED_ICON : NOT_REQUIRED_ICON; const iconClass = codeOwnerApprovalRequired ? REQUIRED_ICON_CLASS : NOT_REQUIRED_ICON_CLASS; const title = codeOwnerApprovalRequired diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue index e7d028e8d23..270d7f0d182 100644 --- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue +++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue @@ -1,7 +1,7 @@ <script> import { GlToast, GlTooltipDirective, GlModal } from '@gitlab/ui'; import Vue from 'vue'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { BV_SHOW_MODAL, BV_HIDE_MODAL } from '~/lib/utils/constants'; import { s__ } from '~/locale'; import { updateUserStatus } from '~/rest_api'; diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue index f7526bcff3d..3038cec03eb 100644 --- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue +++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_form.vue @@ -1,6 +1,6 @@ <script> import { GlSprintf, GlButton } from '@gitlab/ui'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; import { confidentialityQueries } from '../../constants'; diff --git a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue index c2f239b56c7..9177baec246 100644 --- a/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue +++ b/app/assets/javascripts/sidebar/components/confidential/sidebar_confidentiality_widget.vue @@ -1,7 +1,7 @@ <script> import produce from 'immer'; import Vue from 'vue'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { __, sprintf } from '~/locale'; import { confidentialityQueries, Tracking } from '../../constants'; import SidebarEditableItem from '../sidebar_editable_item.vue'; diff --git a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue index 891eaf07ac9..190b8c1de62 100644 --- a/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue +++ b/app/assets/javascripts/sidebar/components/date/sidebar_date_widget.vue @@ -1,6 +1,6 @@ <script> import { GlIcon, GlDatepicker, GlTooltipDirective, GlLink, GlPopover } from '@gitlab/ui'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { TYPE_ISSUE } from '~/issues/constants'; import { dateInWords, formatDate, parsePikadayDate } from '~/lib/utils/datetime_utility'; import { __, sprintf } from '~/locale'; diff --git a/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue b/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue index f7daad63f45..6db332a82da 100644 --- a/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue +++ b/app/assets/javascripts/sidebar/components/incidents/sidebar_escalation_status.vue @@ -1,6 +1,6 @@ <script> import { GlIcon, GlTooltipDirective } from '@gitlab/ui'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { logError } from '~/lib/logger'; import EscalationStatus from 'ee_else_ce/sidebar/components/incidents/escalation_status.vue'; import { diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js index 2dab97826b9..06030003f3c 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_vue/store/actions.js @@ -1,4 +1,4 @@ -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { __ } from '~/locale'; import * as types from './mutation_types'; diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue index 36a40369d95..21bcb51f7b1 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_create_view.vue @@ -8,7 +8,7 @@ import { GlLoadingIcon, } from '@gitlab/ui'; import produce from 'immer'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { WORKSPACE_GROUP } from '~/issues/constants'; import { __ } from '~/locale'; import { workspaceLabelsQueries } from '../../../constants'; diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue index c1939dc7785..e664d6b4bd6 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/dropdown_contents_labels_view.vue @@ -1,7 +1,7 @@ <script> import { GlDropdownForm, GlDropdownItem, GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui'; import fuzzaldrinPlus from 'fuzzaldrin-plus'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { __ } from '~/locale'; import { workspaceLabelsQueries } from '../../../constants'; diff --git a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue index d7e094ad340..3aa4215443e 100644 --- a/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue +++ b/app/assets/javascripts/sidebar/components/labels/labels_select_widget/labels_select_root.vue @@ -2,7 +2,7 @@ import { debounce } from 'lodash'; import issuableLabelsSubscription from 'ee_else_ce/sidebar/queries/issuable_labels.subscription.graphql'; import { MutationOperationMode, getIdFromGraphQLId } from '~/graphql_shared/utils'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST, TYPE_TEST_CASE } from '~/issues/constants'; diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue index df03af346c0..606d374158b 100644 --- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue +++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue @@ -2,7 +2,7 @@ import { GlButton } from '@gitlab/ui'; import $ from 'jquery'; import { mapActions } from 'vuex'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { __, sprintf } from '~/locale'; import eventHub from '../../event_hub'; @@ -49,11 +49,11 @@ export default { fullPath: this.fullPath, }) .catch(() => { - const flashMessage = __( + const alertMessage = __( 'Something went wrong trying to change the locked state of this %{issuableDisplayName}', ); createAlert({ - message: sprintf(flashMessage, { issuableDisplayName: this.issuableDisplayName }), + message: sprintf(alertMessage, { issuableDisplayName: this.issuableDisplayName }), }); }) .finally(() => { diff --git a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue index 9d8f1304911..8c2024129e2 100644 --- a/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue +++ b/app/assets/javascripts/sidebar/components/lock/issuable_lock_form.vue @@ -4,7 +4,7 @@ import { mapGetters, mapActions } from 'vuex'; import { TYPE_ISSUE } from '~/issues/constants'; import { __, sprintf } from '~/locale'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import toast from '~/vue_shared/plugins/global_toast'; import eventHub from '../../event_hub'; import EditForm from './edit_form.vue'; @@ -92,11 +92,11 @@ export default { } }) .catch(() => { - const flashMessage = __( + const alertMessage = __( 'Something went wrong trying to change the locked state of this %{issuableDisplayName}', ); createAlert({ - message: sprintf(flashMessage, { issuableDisplayName: this.issuableDisplayName }), + message: sprintf(alertMessage, { issuableDisplayName: this.issuableDisplayName }), }); }) .finally(() => { diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue index 7068ba98966..50b4284cde0 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown.vue @@ -27,7 +27,7 @@ import { LocalizedIssuableAttributeType, noAttributeId, } from 'ee_else_ce/sidebar/constants'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { PathIdSeparator } from '~/related_issues/constants'; export default { diff --git a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue index 660e7b98155..19e72da65f2 100644 --- a/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue +++ b/app/assets/javascripts/sidebar/components/sidebar_dropdown_widget.vue @@ -1,7 +1,7 @@ <script> import { GlButton, GlIcon, GlLink, GlPopover, GlTooltipDirective } from '@gitlab/ui'; import { kebabCase, snakeCase } from 'lodash'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { TYPE_EPIC, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants'; import { timeFor } from '~/lib/utils/datetime_utility'; diff --git a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue index 226785d859c..4a5ec124e5d 100644 --- a/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue +++ b/app/assets/javascripts/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue @@ -1,6 +1,6 @@ <script> import { GlDropdownForm, GlIcon, GlLoadingIcon, GlToggle, GlTooltipDirective } from '@gitlab/ui'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { TYPE_EPIC, TYPE_MERGE_REQUEST } from '~/issues/constants'; import { isLoggedIn } from '~/lib/utils/common_utils'; import { __, sprintf } from '~/locale'; diff --git a/app/assets/javascripts/snippets/components/edit.vue b/app/assets/javascripts/snippets/components/edit.vue index 4a7528d9c8e..151c38d01dc 100644 --- a/app/assets/javascripts/snippets/components/edit.vue +++ b/app/assets/javascripts/snippets/components/edit.vue @@ -2,7 +2,7 @@ import { GlButton, GlLoadingIcon, GlFormInput, GlFormGroup } from '@gitlab/ui'; import eventHub from '~/blob/components/eventhub'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import { redirectTo, joinPaths } from '~/lib/utils/url_utility'; import { __, sprintf } from '~/locale'; import { @@ -141,7 +141,7 @@ export default { Object.assign(e, { returnValue }); return returnValue; }, - flashAPIFailure(err) { + alertAPIFailure(err) { const defaultErrorMsg = this.newSnippet ? SNIPPET_CREATE_MUTATION_ERROR : SNIPPET_UPDATE_MUTATION_ERROR; @@ -190,7 +190,7 @@ export default { const errors = baseObj?.errors; if (errors?.length) { - this.flashAPIFailure(errors[0]); + this.alertAPIFailure(errors[0]); } else { redirectTo(baseObj.snippet.webUrl); } @@ -199,7 +199,7 @@ export default { // eslint-disable-next-line no-console console.error('[gitlab] unexpected error while updating snippet', e); - this.flashAPIFailure(getErrorMessage(e)); + this.alertAPIFailure(getErrorMessage(e)); }); }, updateActions(actions) { diff --git a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue index 7e80928cbea..021bd23781e 100644 --- a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue +++ b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue @@ -1,7 +1,7 @@ <script> import { GlLoadingIcon } from '@gitlab/ui'; import BlobHeaderEdit from '~/blob/components/blob_edit_header.vue'; -import { createAlert } from '~/flash'; +import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { getBaseURL, joinPaths } from '~/lib/utils/url_utility'; import { sprintf } from '~/locale'; @@ -60,9 +60,9 @@ export default { .then((res) => { this.notifyAboutUpdates({ content: res.data }); }) - .catch((e) => this.flashAPIFailure(e)); + .catch((e) => this.alertAPIFailure(e)); }, - flashAPIFailure(err) { + alertAPIFailure(err) { createAlert({ message: sprintf(SNIPPET_BLOB_CONTENT_FETCH_ERROR, { err }) }); }, }, diff --git a/app/assets/javascripts/snippets/components/snippet_header.vue b/app/assets/javascripts/snippets/components/snippet_header.vue index 231eaff41b5..881e06113d9 100644 --- a/app/assets/javascripts/snippets/components/snippet_header.vue +++ b/app/assets/javascripts/snippets/components/snippet_header.vue @@ -19,7 +19,7 @@ import axios from '~/lib/utils/axios_utils'; import { joinPaths } from '~/lib/utils/url_utility'; import { __, s__, sprintf } from '~/locale'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; -import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/flash'; +import { createAlert, VARIANT_DANGER, VARIANT_SUCCESS } from '~/alert'; import DeleteSnippetMutation from '../mutations/delete_snippet.mutation.graphql'; diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js index 134c2858849..1aa3baca165 100644 --- a/app/assets/javascripts/zen_mode.js +++ b/app/assets/javascripts/zen_mode.js @@ -5,6 +5,7 @@ /*= provides zen_mode:enter */ /*= provides zen_mode:leave */ +import autosize from 'autosize'; import Dropzone from 'dropzone'; import $ from 'jquery'; import Mousetrap from 'mousetrap'; @@ -39,6 +40,7 @@ export default class ZenMode { constructor() { this.active_backdrop = null; this.active_textarea = null; + this.storedStyle = null; $(document).on('click', '.js-zen-enter', (e) => { e.preventDefault(); return $(e.currentTarget).trigger('zen_mode:enter'); @@ -68,6 +70,7 @@ export default class ZenMode { this.active_backdrop.addClass('fullscreen'); this.active_textarea = this.active_backdrop.find('textarea'); // Prevent a user-resized textarea from persisting to fullscreen + this.storedStyle = this.active_textarea.attr('style'); this.active_textarea.removeAttr('style'); this.active_textarea.focus(); } @@ -77,6 +80,11 @@ export default class ZenMode { Mousetrap.unpause(); this.active_textarea.closest('.zen-backdrop').removeClass('fullscreen'); scrollToElement(this.active_textarea, { duration: 0, offset: -100 }); + this.active_textarea.attr('style', this.storedStyle); + + autosize(this.active_textarea); + autosize.update(this.active_textarea); + this.active_textarea = null; this.active_backdrop = null; diff --git a/app/assets/stylesheets/page_bundles/wiki.scss b/app/assets/stylesheets/page_bundles/wiki.scss index 55628603570..d7d454bde45 100644 --- a/app/assets/stylesheets/page_bundles/wiki.scss +++ b/app/assets/stylesheets/page_bundles/wiki.scss @@ -195,3 +195,20 @@ ul.wiki-pages-list.content-list { display: none; } } + +.drawio-editor { + position: fixed; + top: calc(var(--header-height, 48px)); + left: 0; + bottom: 0; + width: 100%; + height: calc(100% - var(--header-height, 48px)); + 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/graphql/types/packages/package_details_type.rb b/app/graphql/types/packages/package_details_type.rb index f63b41b3c92..e00d6eac72f 100644 --- a/app/graphql/types/packages/package_details_type.rb +++ b/app/graphql/types/packages/package_details_type.rb @@ -63,11 +63,11 @@ module Types end def pypi_url - pypi_registry_url(object.project.id) + pypi_registry_url(object.project) end def public_package - object.project.public? || object.project.project_feature.package_registry_access_level == ProjectFeature::PUBLIC + object.project.project_feature.public_packages? end end end diff --git a/app/helpers/packages_helper.rb b/app/helpers/packages_helper.rb index f9ec20bdd01..dec1943db54 100644 --- a/app/helpers/packages_helper.rb +++ b/app/helpers/packages_helper.rb @@ -27,9 +27,14 @@ module PackagesHelper presenter.detail_view.to_json end - def pypi_registry_url(project_id) - full_url = expose_url(api_v4_projects_packages_pypi_simple_package_name_path({ id: project_id, package_name: '' }, true)) - full_url.sub!('://', '://__token__:<your_personal_token>@') + def pypi_registry_url(project) + full_url = expose_url(api_v4_projects_packages_pypi_simple_package_name_path({ id: project.id, package_name: '' }, true)) + + if project.project_feature.public_packages? + full_url + else + full_url.sub!('://', '://__token__:<your_personal_token>@') + end end def composer_registry_url(group_id) diff --git a/app/models/dependency_proxy/registry.rb b/app/models/dependency_proxy/registry.rb index 6492acf325a..3073dd59c7b 100644 --- a/app/models/dependency_proxy/registry.rb +++ b/app/models/dependency_proxy/registry.rb @@ -33,3 +33,5 @@ class DependencyProxy::Registry end end end + +::DependencyProxy::Registry.prepend_mod diff --git a/app/models/error_tracking/project_error_tracking_setting.rb b/app/models/error_tracking/project_error_tracking_setting.rb index 1c7a8d93e6e..c52f8a58c00 100644 --- a/app/models/error_tracking/project_error_tracking_setting.rb +++ b/app/models/error_tracking/project_error_tracking_setting.rb @@ -145,7 +145,7 @@ module ErrorTracking ensure_issue_belongs_to_project!(issue_to_be_updated.project_id) handle_exceptions do - { updated: sentry_client.update_issue(opts) } + { updated: sentry_client.update_issue(**opts) } end end diff --git a/app/models/project_feature.rb b/app/models/project_feature.rb index 168646bbe41..053ccfac050 100644 --- a/app/models/project_feature.rb +++ b/app/models/project_feature.rb @@ -162,6 +162,12 @@ class ProjectFeature < ApplicationRecord end end + def public_packages? + return false unless Gitlab.config.packages.enabled + + package_registry_access_level == PUBLIC || project.public? + end + private def set_pages_access_level diff --git a/app/views/projects/issues/service_desk/_nav_btns.html.haml b/app/views/projects/issues/service_desk/_nav_btns.html.haml index 8d16c3d978f..818de77dc89 100644 --- a/app/views/projects/issues/service_desk/_nav_btns.html.haml +++ b/app/views/projects/issues/service_desk/_nav_btns.html.haml @@ -1,7 +1,7 @@ - show_feed_buttons = local_assigns.fetch(:show_feed_buttons, true) - show_import_button = local_assigns.fetch(:show_import_button, true) && can?(current_user, :import_issues, @project) - show_export_button = local_assigns.fetch(:show_export_button, true) -- issuable_type = 'issues' +- issuable_type = 'issue' - can_edit = can?(current_user, :admin_project, @project) - notification_email = @current_user.present? ? @current_user.notification_email_or_default : nil diff --git a/app/views/projects/merge_requests/_nav_btns.html.haml b/app/views/projects/merge_requests/_nav_btns.html.haml index 1efea6a1d37..beb6de4698c 100644 --- a/app/views/projects/merge_requests/_nav_btns.html.haml +++ b/app/views/projects/merge_requests/_nav_btns.html.haml @@ -1,4 +1,4 @@ -- issuable_type = 'merge-requests' +- issuable_type = 'merge_request' - notification_email = @current_user.present? ? @current_user.notification_email_or_default : nil = render 'shared/issuable/feed_buttons', show_calendar_button: false diff --git a/app/views/shared/empty_states/_issues.html.haml b/app/views/shared/empty_states/_issues.html.haml index 37f7fbc0de5..ad6e5578878 100644 --- a/app/views/shared/empty_states/_issues.html.haml +++ b/app/views/shared/empty_states/_issues.html.haml @@ -4,7 +4,6 @@ - opened_issues_count = issuables_count_for_state(:issues, :opened) - is_opened_state = params[:state] == 'opened' - is_closed_state = params[:state] == 'closed' -- issuable_type = 'issues' - can_edit = can?(current_user, :admin_project, @project) .row.empty-state @@ -43,7 +42,7 @@ = link_to _('New issue'), button_path, class: 'gl-button btn btn-confirm', id: 'new_issue_link' - if show_import_button - .js-csv-import-export-buttons{ data: { show_import_button: 'true', issuable_type: issuable_type, import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), container_class: 'gl-w-full gl-sm-w-auto gl-sm-mr-3 gl-display-inline-flex gl-vertical-align-middle', show_label: 'true' } } + .js-csv-import-export-buttons{ data: { show_import_button: 'true', issuable_type: 'issue', import_csv_issues_path: import_csv_namespace_project_issues_path, can_edit: can_edit.to_s, project_import_jira_path: project_import_jira_path(@project), max_attachment_size: number_to_human_size(Gitlab::CurrentSettings.max_attachment_size.megabytes), container_class: 'gl-w-full gl-sm-w-auto gl-sm-mr-3 gl-display-inline-flex gl-vertical-align-middle', show_label: 'true' } } %hr %p.gl-text-center.gl-mb-0 %strong |