diff options
Diffstat (limited to 'app/assets')
76 files changed, 732 insertions, 182 deletions
diff --git a/app/assets/javascripts/badges/components/badge.vue b/app/assets/javascripts/badges/components/badge.vue index 97232d7f783..8512bf9dd7b 100644 --- a/app/assets/javascripts/badges/components/badge.vue +++ b/app/assets/javascripts/badges/components/badge.vue @@ -1,12 +1,14 @@ <script> import Icon from '~/vue_shared/components/icon.vue'; import Tooltip from '~/vue_shared/directives/tooltip'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { name: 'Badge', components: { Icon, Tooltip, + GlLoadingIcon, }, directives: { Tooltip, diff --git a/app/assets/javascripts/badges/components/badge_form.vue b/app/assets/javascripts/badges/components/badge_form.vue index aff7c4180e3..47e6e618219 100644 --- a/app/assets/javascripts/badges/components/badge_form.vue +++ b/app/assets/javascripts/badges/components/badge_form.vue @@ -4,6 +4,7 @@ import { mapActions, mapState } from 'vuex'; import createFlash from '~/flash'; import { s__, sprintf } from '~/locale'; import LoadingButton from '~/vue_shared/components/loading_button.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import createEmptyBadge from '../empty_badge'; import Badge from './badge.vue'; @@ -14,6 +15,7 @@ export default { components: { Badge, LoadingButton, + GlLoadingIcon, }, props: { isEditing: { diff --git a/app/assets/javascripts/badges/components/badge_list.vue b/app/assets/javascripts/badges/components/badge_list.vue index 359d3e10380..ab518820378 100644 --- a/app/assets/javascripts/badges/components/badge_list.vue +++ b/app/assets/javascripts/badges/components/badge_list.vue @@ -1,5 +1,6 @@ <script> import { mapState } from 'vuex'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import BadgeListRow from './badge_list_row.vue'; import { GROUP_BADGE } from '../constants'; @@ -7,6 +8,7 @@ export default { name: 'BadgeList', components: { BadgeListRow, + GlLoadingIcon, }, computed: { ...mapState(['badges', 'isLoading', 'kind']), diff --git a/app/assets/javascripts/badges/components/badge_list_row.vue b/app/assets/javascripts/badges/components/badge_list_row.vue index 5d16ba3ce6d..f28eff18f03 100644 --- a/app/assets/javascripts/badges/components/badge_list_row.vue +++ b/app/assets/javascripts/badges/components/badge_list_row.vue @@ -2,6 +2,7 @@ import { mapActions, mapState } from 'vuex'; import { s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import { PROJECT_BADGE } from '../constants'; import Badge from './badge.vue'; @@ -10,6 +11,7 @@ export default { components: { Badge, Icon, + GlLoadingIcon, }, props: { badge: { diff --git a/app/assets/javascripts/boards/components/board_list.vue b/app/assets/javascripts/boards/components/board_list.vue index 4dc56c670f0..5e28fc396ab 100644 --- a/app/assets/javascripts/boards/components/board_list.vue +++ b/app/assets/javascripts/boards/components/board_list.vue @@ -1,5 +1,6 @@ <script> import Sortable from 'sortablejs'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import boardNewIssue from './board_new_issue.vue'; import boardCard from './board_card.vue'; import eventHub from '../eventhub'; @@ -11,6 +12,7 @@ export default { components: { boardCard, boardNewIssue, + GlLoadingIcon, }, props: { groupId: { diff --git a/app/assets/javascripts/boards/components/modal/index.vue b/app/assets/javascripts/boards/components/modal/index.vue index 40949cc0656..fdd1346d4c7 100644 --- a/app/assets/javascripts/boards/components/modal/index.vue +++ b/app/assets/javascripts/boards/components/modal/index.vue @@ -6,6 +6,7 @@ import ModalList from './list.vue'; import ModalFooter from './footer.vue'; import EmptyState from './empty_state.vue'; import ModalStore from '../../stores/modal_store'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { components: { @@ -13,6 +14,7 @@ export default { ModalHeader, ModalList, ModalFooter, + GlLoadingIcon, }, props: { newIssuePath: { diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index 0f01a2a6c09..503417644fa 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -2,6 +2,7 @@ import $ from 'jquery'; import _ from 'underscore'; import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import eventHub from '../eventhub'; import Api from '../../api'; @@ -9,6 +10,7 @@ export default { name: 'BoardProjectSelect', components: { Icon, + GlLoadingIcon, }, props: { groupId: { diff --git a/app/assets/javascripts/commons/gitlab_ui.js b/app/assets/javascripts/commons/gitlab_ui.js deleted file mode 100644 index 6c18a0fd390..00000000000 --- a/app/assets/javascripts/commons/gitlab_ui.js +++ /dev/null @@ -1,4 +0,0 @@ -import Vue from 'vue'; -import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; - -Vue.component('gl-loading-icon', GlLoadingIcon); diff --git a/app/assets/javascripts/commons/index.js b/app/assets/javascripts/commons/index.js index ea945cd3fa5..0d2fe2925d8 100644 --- a/app/assets/javascripts/commons/index.js +++ b/app/assets/javascripts/commons/index.js @@ -3,5 +3,4 @@ import './polyfills'; import './jquery'; import './bootstrap'; import './vue'; -import './gitlab_ui'; import '../lib/utils/axios_utils'; diff --git a/app/assets/javascripts/deploy_keys/components/action_btn.vue b/app/assets/javascripts/deploy_keys/components/action_btn.vue index 10548da8ec5..ea74fd27ff6 100644 --- a/app/assets/javascripts/deploy_keys/components/action_btn.vue +++ b/app/assets/javascripts/deploy_keys/components/action_btn.vue @@ -1,7 +1,11 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import eventHub from '../eventhub'; export default { + components: { + GlLoadingIcon, + }, props: { deployKey: { type: Object, diff --git a/app/assets/javascripts/deploy_keys/components/app.vue b/app/assets/javascripts/deploy_keys/components/app.vue index 3589599986d..631a9673b3e 100644 --- a/app/assets/javascripts/deploy_keys/components/app.vue +++ b/app/assets/javascripts/deploy_keys/components/app.vue @@ -6,11 +6,13 @@ import eventHub from '../eventhub'; import DeployKeysService from '../service'; import DeployKeysStore from '../store'; import KeysPanel from './keys_panel.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { components: { KeysPanel, NavigationTabs, + GlLoadingIcon, }, props: { endpoint: { diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue index 59680959bb1..7c60fb3da42 100644 --- a/app/assets/javascripts/diffs/components/app.vue +++ b/app/assets/javascripts/diffs/components/app.vue @@ -3,6 +3,7 @@ import { mapState, mapGetters, mapActions } from 'vuex'; import Icon from '~/vue_shared/components/icon.vue'; import { __ } from '~/locale'; import createFlash from '~/flash'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import eventHub from '../../notes/event_hub'; import CompareVersions from './compare_versions.vue'; import DiffFile from './diff_file.vue'; @@ -21,6 +22,7 @@ export default { HiddenFilesWarning, CommitWidget, TreeList, + GlLoadingIcon, }, props: { endpoint: { @@ -223,7 +225,10 @@ export default { :commit="commit" /> - <div class="files d-flex prepend-top-default"> + <div + :data-can-create-note="getNoteableData.current_user.can_create_note" + class="files d-flex prepend-top-default" + > <div v-show="showTreeList" class="diff-tree-list" diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index fb5556e3cd7..547742a5ff4 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -1,15 +1,22 @@ <script> -import { mapGetters, mapState } from 'vuex'; +import { mapActions, mapGetters, mapState } from 'vuex'; import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; -import { diffModes } from '~/ide/constants'; import InlineDiffView from './inline_diff_view.vue'; import ParallelDiffView from './parallel_diff_view.vue'; +import NoteForm from '../../notes/components/note_form.vue'; +import ImageDiffOverlay from './image_diff_overlay.vue'; +import DiffDiscussions from './diff_discussions.vue'; +import { IMAGE_DIFF_POSITION_TYPE } from '../constants'; +import { getDiffMode } from '../store/utils'; export default { components: { InlineDiffView, ParallelDiffView, DiffViewer, + NoteForm, + DiffDiscussions, + ImageDiffOverlay, }, props: { diffFile: { @@ -23,13 +30,38 @@ export default { endpoint: state => state.diffs.endpoint, }), ...mapGetters('diffs', ['isInlineView', 'isParallelView']), + ...mapGetters('diffs', ['getCommentFormForDiffFile']), + ...mapGetters(['getNoteableData', 'noteableType']), diffMode() { - const diffModeKey = Object.keys(diffModes).find(key => this.diffFile[`${key}File`]); - return diffModes[diffModeKey] || diffModes.replaced; + return getDiffMode(this.diffFile); }, isTextFile() { return this.diffFile.viewer.name === 'text'; }, + diffFileCommentForm() { + return this.getCommentFormForDiffFile(this.diffFile.fileHash); + }, + showNotesContainer() { + return this.diffFile.discussions.length || this.diffFileCommentForm; + }, + }, + methods: { + ...mapActions('diffs', ['saveDiffDiscussion', 'closeDiffFileCommentForm']), + handleSaveNote(note) { + this.saveDiffDiscussion({ + note, + formData: { + noteableData: this.getNoteableData, + noteableType: this.noteableType, + diffFile: this.diffFile, + positionType: IMAGE_DIFF_POSITION_TYPE, + x: this.diffFileCommentForm.x, + y: this.diffFileCommentForm.y, + width: this.diffFileCommentForm.width, + height: this.diffFileCommentForm.height, + }, + }); + }, }, }; </script> @@ -56,7 +88,37 @@ export default { :new-sha="diffFile.diffRefs.headSha" :old-path="diffFile.oldPath" :old-sha="diffFile.diffRefs.baseSha" - :project-path="projectPath"/> + :file-hash="diffFile.fileHash" + :project-path="projectPath" + > + <image-diff-overlay + slot="image-overlay" + :discussions="diffFile.discussions" + :file-hash="diffFile.fileHash" + :can-comment="getNoteableData.current_user.can_create_note" + /> + <div + v-if="showNotesContainer" + class="note-container" + > + <diff-discussions + v-if="diffFile.discussions.length" + class="diff-file-discussions" + :discussions="diffFile.discussions" + :should-collapse-discussions="true" + :render-avatar-badge="true" + /> + <note-form + v-if="diffFileCommentForm" + ref="noteForm" + :is-editing="false" + :save-button-title="__('Comment')" + class="diff-comment-form new-note discussion-form discussion-form-container" + @handleFormUpdate="handleSaveNote" + @cancelForm="closeDiffFileCommentForm(diffFile.fileHash)" + /> + </div> + </diff-viewer> </div> </div> </template> diff --git a/app/assets/javascripts/diffs/components/diff_discussions.vue b/app/assets/javascripts/diffs/components/diff_discussions.vue index cddbe554fbd..e19207bdc95 100644 --- a/app/assets/javascripts/diffs/components/diff_discussions.vue +++ b/app/assets/javascripts/diffs/components/diff_discussions.vue @@ -1,24 +1,40 @@ <script> import { mapActions } from 'vuex'; +import Icon from '~/vue_shared/components/icon.vue'; import noteableDiscussion from '../../notes/components/noteable_discussion.vue'; export default { components: { noteableDiscussion, + Icon, }, props: { discussions: { type: Array, required: true, }, + shouldCollapseDiscussions: { + type: Boolean, + required: false, + default: false, + }, + renderAvatarBadge: { + type: Boolean, + required: false, + default: false, + }, }, methods: { + ...mapActions(['toggleDiscussion']), ...mapActions('diffs', ['removeDiscussionsFromDiff']), deleteNoteHandler(discussion) { if (discussion.notes.length <= 1) { this.removeDiscussionsFromDiff(discussion); } }, + isExpanded(discussion) { + return this.shouldCollapseDiscussions ? discussion.expanded : true; + }, }, }; </script> @@ -26,22 +42,54 @@ export default { <template> <div> <div - v-for="discussion in discussions" + v-for="(discussion, index) in discussions" :key="discussion.id" - class="discussion-notes diff-discussions" + :class="{ + collapsed: !isExpanded(discussion) + }" + class="discussion-notes diff-discussions position-relative" > <ul :data-discussion-id="discussion.id" class="notes" > + <template v-if="shouldCollapseDiscussions"> + <button + :class="{ + 'diff-notes-collapse': discussion.expanded, + 'btn-transparent badge badge-pill': !discussion.expanded + }" + type="button" + class="js-diff-notes-toggle" + @click="toggleDiscussion({ discussionId: discussion.id })" + > + <icon + v-if="discussion.expanded" + name="collapse" + class="collapse-icon" + /> + <template v-else> + {{ index + 1 }} + </template> + </button> + </template> <noteable-discussion + v-show="isExpanded(discussion)" :discussion="discussion" :render-header="false" :render-diff-file="false" :always-expanded="true" :discussions-by-diff-order="true" @noteDeleted="deleteNoteHandler" - /> + > + <span + v-if="renderAvatarBadge" + slot="avatar-badge" + class="badge badge-pill" + > + {{ index + 1 }} + </span> + </noteable-discussion> </ul> </div> </div> diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 958e57c5652..e76c7afd863 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -3,6 +3,7 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import _ from 'underscore'; import { __, sprintf } from '~/locale'; import createFlash from '~/flash'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import DiffFileHeader from './diff_file_header.vue'; import DiffContent from './diff_content.vue'; @@ -10,6 +11,7 @@ export default { components: { DiffFileHeader, DiffContent, + GlLoadingIcon, }, props: { file: { diff --git a/app/assets/javascripts/diffs/components/image_diff_overlay.vue b/app/assets/javascripts/diffs/components/image_diff_overlay.vue new file mode 100644 index 00000000000..ae1b0a52901 --- /dev/null +++ b/app/assets/javascripts/diffs/components/image_diff_overlay.vue @@ -0,0 +1,139 @@ +<script> +import { mapActions, mapGetters } from 'vuex'; +import _ from 'underscore'; +import Icon from '~/vue_shared/components/icon.vue'; + +export default { + name: 'ImageDiffOverlay', + components: { + Icon, + }, + props: { + discussions: { + type: [Array, Object], + required: true, + }, + fileHash: { + type: String, + required: true, + }, + canComment: { + type: Boolean, + required: false, + default: false, + }, + showCommentIcon: { + type: Boolean, + required: false, + default: false, + }, + badgeClass: { + type: String, + required: false, + default: 'badge badge-pill', + }, + shouldToggleDiscussion: { + type: Boolean, + required: false, + default: true, + }, + }, + computed: { + ...mapGetters('diffs', ['getDiffFileByHash', 'getCommentFormForDiffFile']), + currentCommentForm() { + return this.getCommentFormForDiffFile(this.fileHash); + }, + allDiscussions() { + return _.isArray(this.discussions) ? this.discussions : [this.discussions]; + }, + }, + methods: { + ...mapActions(['toggleDiscussion']), + ...mapActions('diffs', ['openDiffFileCommentForm']), + getImageDimensions() { + return { + width: this.$parent.width, + height: this.$parent.height, + }; + }, + getPositionForObject(meta) { + const { x, y, width, height } = meta; + const imageWidth = this.getImageDimensions().width; + const imageHeight = this.getImageDimensions().height; + const widthRatio = imageWidth / width; + const heightRatio = imageHeight / height; + + return { + x: Math.round(x * widthRatio), + y: Math.round(y * heightRatio), + }; + }, + getPosition(discussion) { + const { x, y } = this.getPositionForObject(discussion.position); + + return { + left: `${x}px`, + top: `${y}px`, + }; + }, + clickedImage(x, y) { + const { width, height } = this.getImageDimensions(); + + this.openDiffFileCommentForm({ + fileHash: this.fileHash, + width, + height, + x, + y, + }); + }, + }, +}; +</script> + +<template> + <div class="position-absolute w-100 h-100 image-diff-overlay"> + <button + v-if="canComment" + type="button" + class="btn-transparent position-absolute image-diff-overlay-add-comment w-100 h-100 js-add-image-diff-note-button" + @click="clickedImage($event.offsetX, $event.offsetY)" + > + <span class="sr-only"> + {{ __('Add image comment') }} + </span> + </button> + <button + v-for="(discussion, index) in allDiscussions" + :key="discussion.id" + :style="getPosition(discussion)" + :class="badgeClass" + :disabled="!shouldToggleDiscussion" + class="js-image-badge" + type="button" + @click="toggleDiscussion({ discussionId: discussion.id })" + > + <icon + v-if="showCommentIcon" + name="image-comment-dark" + /> + <template v-else> + {{ index + 1 }} + </template> + </button> + <button + v-if="currentCommentForm" + :style="{ + left: `${currentCommentForm.x}px`, + top: `${currentCommentForm.y}px` + }" + :aria-label="__('Comment form position')" + class="btn-transparent comment-indicator" + type="button" + > + <icon + name="image-comment-dark" + /> + </button> + </div> +</template> diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js index 6a50d2c1426..78a39baa4cb 100644 --- a/app/assets/javascripts/diffs/constants.js +++ b/app/assets/javascripts/diffs/constants.js @@ -12,6 +12,7 @@ export const NOTE_TYPE = 'Note'; export const NEW_LINE_TYPE = 'new'; export const OLD_LINE_TYPE = 'old'; export const TEXT_DIFF_POSITION_TYPE = 'text'; +export const IMAGE_DIFF_POSITION_TYPE = 'image'; export const LINE_POSITION_LEFT = 'left'; export const LINE_POSITION_RIGHT = 'right'; diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index ca8ae605cb4..d3e9c7c88f0 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -50,8 +50,8 @@ export const assignDiscussionsToDiff = ( }; export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => { - const { fileHash, line_code } = removeDiscussion; - commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash, lineCode: line_code }); + const { fileHash, line_code, id } = removeDiscussion; + commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash, lineCode: line_code, id }); }; export const startRenderDiffsQueue = ({ state, commit }) => { @@ -189,6 +189,7 @@ export const saveDiffDiscussion = ({ dispatch }, { note, formData }) => { return dispatch('saveNote', postData, { root: true }) .then(result => dispatch('updateDiscussion', result.discussion, { root: true })) .then(discussion => dispatch('assignDiscussionsToDiff', [discussion])) + .then(() => dispatch('closeDiffFileCommentForm', formData.diffFile.fileHash)) .catch(() => createFlash(s__('MergeRequests|Saving the comment failed'))); }; @@ -210,5 +211,19 @@ export const toggleShowTreeList = ({ commit, state }) => { localStorage.setItem(MR_TREE_SHOW_KEY, state.showTreeList); }; +export const openDiffFileCommentForm = ({ commit, getters }, formData) => { + const form = getters.getCommentFormForDiffFile(formData.fileHash); + + if (form) { + commit(types.UPDATE_DIFF_FILE_COMMENT_FORM, formData); + } else { + commit(types.OPEN_DIFF_FILE_COMMENT_FORM, formData); + } +}; + +export const closeDiffFileCommentForm = ({ commit }, fileHash) => { + commit(types.CLOSE_DIFF_FILE_COMMENT_FORM, fileHash); +}; + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/diffs/store/getters.js b/app/assets/javascripts/diffs/store/getters.js index d4c205882ff..2bf0ad99c22 100644 --- a/app/assets/javascripts/diffs/store/getters.js +++ b/app/assets/javascripts/diffs/store/getters.js @@ -114,5 +114,8 @@ export const allBlobs = state => Object.values(state.treeEntries).filter(f => f. export const diffFilesLength = state => state.diffFiles.length; +export const getCommentFormForDiffFile = state => fileHash => + state.commentForms.find(form => form.fileHash === fileHash); + // prevent babel-plugin-rewire from generating an invalid default during karma tests export default () => {}; diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index 1c5c35071de..085e255f1d3 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -24,4 +24,6 @@ export default () => ({ showTreeList: storedTreeShow === null ? bp.getBreakpointSize() !== 'xs' : storedTreeShow === 'true', currentDiffFileId: '', + projectPath: '', + commentForms: [], }); diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js index 6474ee628e2..e011031e72c 100644 --- a/app/assets/javascripts/diffs/store/mutation_types.js +++ b/app/assets/javascripts/diffs/store/mutation_types.js @@ -14,3 +14,7 @@ export const REMOVE_LINE_DISCUSSIONS_FOR_FILE = 'REMOVE_LINE_DISCUSSIONS_FOR_FIL export const TOGGLE_FOLDER_OPEN = 'TOGGLE_FOLDER_OPEN'; export const TOGGLE_SHOW_TREE_LIST = 'TOGGLE_SHOW_TREE_LIST'; export const UPDATE_CURRENT_DIFF_FILE_ID = 'UPDATE_CURRENT_DIFF_FILE_ID'; + +export const OPEN_DIFF_FILE_COMMENT_FORM = 'OPEN_DIFF_FILE_COMMENT_FORM'; +export const UPDATE_DIFF_FILE_COMMENT_FORM = 'UPDATE_DIFF_FILE_COMMENT_FORM'; +export const CLOSE_DIFF_FILE_COMMENT_FORM = 'CLOSE_DIFF_FILE_COMMENT_FORM'; diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 38a65f111a2..a7eea2c1449 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -153,20 +153,22 @@ export default { }); }, - [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) { + [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode, id }) { const selectedFile = state.diffFiles.find(f => f.fileHash === fileHash); if (selectedFile) { - const targetLine = selectedFile.parallelDiffLines.find( - line => - (line.left && line.left.lineCode === lineCode) || - (line.right && line.right.lineCode === lineCode), - ); - if (targetLine) { - const side = targetLine.left && targetLine.left.lineCode === lineCode ? 'left' : 'right'; - - Object.assign(targetLine[side], { - discussions: [], - }); + if (selectedFile.parallelDiffLines) { + const targetLine = selectedFile.parallelDiffLines.find( + line => + (line.left && line.left.lineCode === lineCode) || + (line.right && line.right.lineCode === lineCode), + ); + if (targetLine) { + const side = targetLine.left && targetLine.left.lineCode === lineCode ? 'left' : 'right'; + + Object.assign(targetLine[side], { + discussions: [], + }); + } } if (selectedFile.highlightedDiffLines) { @@ -180,6 +182,12 @@ export default { }); } } + + if (selectedFile.discussions && selectedFile.discussions.length) { + selectedFile.discussions = selectedFile.discussions.filter( + discussion => discussion.id !== id, + ); + } } }, [types.TOGGLE_FOLDER_OPEN](state, path) { @@ -191,4 +199,25 @@ export default { [types.UPDATE_CURRENT_DIFF_FILE_ID](state, fileId) { state.currentDiffFileId = fileId; }, + [types.OPEN_DIFF_FILE_COMMENT_FORM](state, formData) { + state.commentForms.push({ + ...formData, + }); + }, + [types.UPDATE_DIFF_FILE_COMMENT_FORM](state, formData) { + const { fileHash } = formData; + + state.commentForms = state.commentForms.map(form => { + if (form.fileHash === fileHash) { + return { + ...formData, + }; + } + + return form; + }); + }, + [types.CLOSE_DIFF_FILE_COMMENT_FORM](state, fileHash) { + state.commentForms = state.commentForms.filter(form => form.fileHash !== fileHash); + }, }; diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index a482a2b82c0..a935b9b1ffa 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -1,5 +1,6 @@ import _ from 'underscore'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; +import { diffModes } from '~/ide/constants'; import { LINE_POSITION_LEFT, LINE_POSITION_RIGHT, @@ -34,6 +35,7 @@ export function getFormData(params) { noteTargetLine, diffViewType, linePosition, + positionType, } = params; const position = JSON.stringify({ @@ -42,9 +44,13 @@ export function getFormData(params) { head_sha: diffFile.diffRefs.headSha, old_path: diffFile.oldPath, new_path: diffFile.newPath, - position_type: TEXT_DIFF_POSITION_TYPE, - old_line: noteTargetLine.oldLine, - new_line: noteTargetLine.newLine, + position_type: positionType || TEXT_DIFF_POSITION_TYPE, + old_line: noteTargetLine ? noteTargetLine.oldLine : null, + new_line: noteTargetLine ? noteTargetLine.newLine : null, + x: params.x, + y: params.y, + width: params.width, + height: params.height, }); const postData = { @@ -66,7 +72,7 @@ export function getFormData(params) { diffFile.diffRefs.startSha && diffFile.diffRefs.headSha ? DIFF_NOTE_TYPE : LEGACY_DIFF_NOTE_TYPE, - line_code: noteTargetLine.lineCode, + line_code: noteTargetLine ? noteTargetLine.lineCode : null, }, }; @@ -225,6 +231,7 @@ export function prepareDiffData(diffData) { Object.assign(file, { renderIt: showingLines < LINES_TO_BE_RENDERED_DIRECTLY, collapsed: file.text && showingLines > MAX_LINES_TO_BE_RENDERED, + discussions: [], }); } } @@ -320,3 +327,8 @@ export const generateTreeList = files => }, { treeEntries: {}, tree: [] }, ); + +export const getDiffMode = diffFile => { + const diffModeKey = Object.keys(diffModes).find(key => diffFile[`${key}File`]); + return diffModes[diffModeKey] || diffModes.replaced; +}; diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue index 00d197d294f..a48f5fcb7d6 100644 --- a/app/assets/javascripts/environments/components/container.vue +++ b/app/assets/javascripts/environments/components/container.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import tablePagination from '../../vue_shared/components/table_pagination.vue'; import environmentTable from '../components/environments_table.vue'; @@ -6,6 +7,7 @@ export default { components: { environmentTable, tablePagination, + GlLoadingIcon, }, props: { isLoading: { diff --git a/app/assets/javascripts/environments/components/environment_actions.vue b/app/assets/javascripts/environments/components/environment_actions.vue index 0a3ae384afa..03c3ad0401f 100644 --- a/app/assets/javascripts/environments/components/environment_actions.vue +++ b/app/assets/javascripts/environments/components/environment_actions.vue @@ -4,6 +4,7 @@ import { formatTime } from '~/lib/utils/datetime_utility'; import Icon from '~/vue_shared/components/icon.vue'; import eventHub from '../event_hub'; import tooltip from '../../vue_shared/directives/tooltip'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { directives: { @@ -11,6 +12,7 @@ export default { }, components: { Icon, + GlLoadingIcon, }, props: { actions: { diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue index 9e137f79dcc..69856abc2d5 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.vue +++ b/app/assets/javascripts/environments/components/environment_rollback.vue @@ -9,10 +9,12 @@ import { s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; import eventHub from '../event_hub'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { components: { Icon, + GlLoadingIcon, }, directives: { diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue index 16abafebbc0..c03d4f29ff9 100644 --- a/app/assets/javascripts/environments/components/environments_table.vue +++ b/app/assets/javascripts/environments/components/environments_table.vue @@ -2,11 +2,13 @@ /** * Render environments table. */ +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import environmentItem from './environment_item.vue'; export default { components: { environmentItem, + GlLoadingIcon, }, props: { diff --git a/app/assets/javascripts/frequent_items/components/app.vue b/app/assets/javascripts/frequent_items/components/app.vue index 70a8838b772..159c0bdc992 100644 --- a/app/assets/javascripts/frequent_items/components/app.vue +++ b/app/assets/javascripts/frequent_items/components/app.vue @@ -1,6 +1,7 @@ <script> import { mapState, mapActions, mapGetters } from 'vuex'; import AccessorUtilities from '~/lib/utils/accessor'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import eventHub from '../event_hub'; import store from '../store/'; import { FREQUENT_ITEMS, STORAGE_KEY } from '../constants'; @@ -14,6 +15,7 @@ export default { components: { FrequentItemsSearchInput, FrequentItemsList, + GlLoadingIcon, }, mixins: [frequentItemsMixin], props: { diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue index a032f291546..2a4a39436e7 100644 --- a/app/assets/javascripts/groups/components/app.vue +++ b/app/assets/javascripts/groups/components/app.vue @@ -8,6 +8,7 @@ import { HIDDEN_CLASS } from '~/lib/utils/constants'; import { getParameterByName } from '~/lib/utils/common_utils'; import { mergeUrlParams } from '~/lib/utils/url_utility'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import eventHub from '../event_hub'; import { COMMON_STR, CONTENT_LIST_CLASS } from '../constants'; import groupsComponent from './groups.vue'; @@ -16,6 +17,7 @@ export default { components: { DeprecatedModal, groupsComponent, + GlLoadingIcon, }, props: { action: { diff --git a/app/assets/javascripts/ide/components/branches/search_list.vue b/app/assets/javascripts/ide/components/branches/search_list.vue index 52ccc537c9d..358f1153de2 100644 --- a/app/assets/javascripts/ide/components/branches/search_list.vue +++ b/app/assets/javascripts/ide/components/branches/search_list.vue @@ -2,12 +2,14 @@ import { mapActions, mapState } from 'vuex'; import _ from 'underscore'; import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import Item from './item.vue'; export default { components: { Item, Icon, + GlLoadingIcon, }, data() { return { diff --git a/app/assets/javascripts/ide/components/error_message.vue b/app/assets/javascripts/ide/components/error_message.vue index a20dc0a7006..2d9bd99e82a 100644 --- a/app/assets/javascripts/ide/components/error_message.vue +++ b/app/assets/javascripts/ide/components/error_message.vue @@ -1,7 +1,11 @@ <script> import { mapActions } from 'vuex'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { + components: { + GlLoadingIcon, + }, props: { message: { type: Object, diff --git a/app/assets/javascripts/ide/components/file_templates/dropdown.vue b/app/assets/javascripts/ide/components/file_templates/dropdown.vue index 94222c08e91..891f7d48b4c 100644 --- a/app/assets/javascripts/ide/components/file_templates/dropdown.vue +++ b/app/assets/javascripts/ide/components/file_templates/dropdown.vue @@ -2,10 +2,12 @@ import $ from 'jquery'; import { mapActions, mapState } from 'vuex'; import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { components: { DropdownButton, + GlLoadingIcon, }, props: { data: { diff --git a/app/assets/javascripts/ide/components/jobs/list.vue b/app/assets/javascripts/ide/components/jobs/list.vue index acd37605d16..57da8b4e2cb 100644 --- a/app/assets/javascripts/ide/components/jobs/list.vue +++ b/app/assets/javascripts/ide/components/jobs/list.vue @@ -1,10 +1,12 @@ <script> import { mapActions } from 'vuex'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import Stage from './stage.vue'; export default { components: { Stage, + GlLoadingIcon, }, props: { stages: { diff --git a/app/assets/javascripts/ide/components/jobs/stage.vue b/app/assets/javascripts/ide/components/jobs/stage.vue index ec168d36b9e..5644759d2f9 100644 --- a/app/assets/javascripts/ide/components/jobs/stage.vue +++ b/app/assets/javascripts/ide/components/jobs/stage.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import tooltip from '../../../vue_shared/directives/tooltip'; import Icon from '../../../vue_shared/components/icon.vue'; import CiIcon from '../../../vue_shared/components/ci_icon.vue'; @@ -12,6 +13,7 @@ export default { Icon, CiIcon, Item, + GlLoadingIcon, }, props: { stage: { diff --git a/app/assets/javascripts/ide/components/merge_requests/list.vue b/app/assets/javascripts/ide/components/merge_requests/list.vue index f5e42e87f1b..e4000f588bd 100644 --- a/app/assets/javascripts/ide/components/merge_requests/list.vue +++ b/app/assets/javascripts/ide/components/merge_requests/list.vue @@ -3,6 +3,7 @@ import { mapActions, mapState } from 'vuex'; import _ from 'underscore'; import { __ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import Item from './item.vue'; import TokenedInput from '../shared/tokened_input.vue'; @@ -16,6 +17,7 @@ export default { TokenedInput, Item, Icon, + GlLoadingIcon, }, data() { return { diff --git a/app/assets/javascripts/ide/components/pipelines/list.vue b/app/assets/javascripts/ide/components/pipelines/list.vue index b670b0355b7..16aec1decd6 100644 --- a/app/assets/javascripts/ide/components/pipelines/list.vue +++ b/app/assets/javascripts/ide/components/pipelines/list.vue @@ -1,6 +1,7 @@ <script> import { mapActions, mapGetters, mapState } from 'vuex'; import _ from 'underscore'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import { sprintf, __ } from '../../../locale'; import Icon from '../../../vue_shared/components/icon.vue'; import CiIcon from '../../../vue_shared/components/ci_icon.vue'; @@ -17,6 +18,7 @@ export default { Tab, JobsList, EmptyState, + GlLoadingIcon, }, computed: { ...mapState(['pipelinesEmptyStateSvgPath', 'links']), diff --git a/app/assets/javascripts/ide/components/preview/clientside.vue b/app/assets/javascripts/ide/components/preview/clientside.vue index 37a8ad36507..0bd56ff6e9b 100644 --- a/app/assets/javascripts/ide/components/preview/clientside.vue +++ b/app/assets/javascripts/ide/components/preview/clientside.vue @@ -3,6 +3,7 @@ import { mapActions, mapGetters, mapState } from 'vuex'; import _ from 'underscore'; import { Manager } from 'smooshpack'; import { listen } from 'codesandbox-api'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import Navigator from './navigator.vue'; import { packageJsonPath } from '../../constants'; import { createPathWithExt } from '../../utils'; @@ -10,6 +11,7 @@ import { createPathWithExt } from '../../utils'; export default { components: { Navigator, + GlLoadingIcon, }, data() { return { diff --git a/app/assets/javascripts/ide/components/preview/navigator.vue b/app/assets/javascripts/ide/components/preview/navigator.vue index 42f23801692..af8959186f9 100644 --- a/app/assets/javascripts/ide/components/preview/navigator.vue +++ b/app/assets/javascripts/ide/components/preview/navigator.vue @@ -1,10 +1,12 @@ <script> import { listen } from 'codesandbox-api'; import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { components: { Icon, + GlLoadingIcon, }, props: { manager: { diff --git a/app/assets/javascripts/jobs/components/job_app.vue b/app/assets/javascripts/jobs/components/job_app.vue index 716bfa6d5fe..35104c80694 100644 --- a/app/assets/javascripts/jobs/components/job_app.vue +++ b/app/assets/javascripts/jobs/components/job_app.vue @@ -3,9 +3,11 @@ import _ from 'underscore'; import { mapGetters, mapState, mapActions } from 'vuex'; import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import { isScrolledToBottom } from '~/lib/utils/scroll_utils'; +import { polyfillSticky } from '~/lib/utils/sticky'; import bp from '~/breakpoints'; import CiHeader from '~/vue_shared/components/header_ci_component.vue'; import Callout from '~/vue_shared/components/callout.vue'; +import Icon from '~/vue_shared/components/icon.vue'; import createStore from '../store'; import EmptyState from './empty_state.vue'; import EnvironmentsBlock from './environments_block.vue'; @@ -26,11 +28,12 @@ export default { EmptyState, EnvironmentsBlock, ErasedBlock, - GlLoadingIcon, + Icon, Log, LogTopBar, StuckBlock, Sidebar, + GlLoadingIcon, }, mixins: [delayedJobMixin], props: { @@ -111,6 +114,14 @@ export default { if (_.isEmpty(oldVal) && !_.isEmpty(newVal.pipeline)) { this.fetchStages(); } + + if (newVal.archived) { + this.$nextTick(() => { + if (this.$refs.sticky) { + polyfillSticky(this.$refs.sticky); + } + }); + } }, }, created() { @@ -128,16 +139,13 @@ export default { window.addEventListener('resize', this.onResize); window.addEventListener('scroll', this.updateScroll); }, - mounted() { this.updateSidebar(); }, - destroyed() { window.removeEventListener('resize', this.onResize); window.removeEventListener('scroll', this.updateScroll); }, - methods: { ...mapActions([ 'setJobEndpoint', @@ -232,14 +240,28 @@ export default { :erased-at="job.erased_at" /> + <div + v-if="job.archived" + ref="sticky" + class="js-archived-job prepend-top-default archived-sticky sticky-top" + > + <icon + name="lock" + class="align-text-bottom" + /> + + {{ __('This job is archived. Only the complete pipeline can be retried.') }} + </div> <!--job log --> <div v-if="hasTrace" - class="build-trace-container prepend-top-default"> + class="build-trace-container" + > <log-top-bar :class="{ 'sidebar-expanded': isSidebarOpen, - 'sidebar-collapsed': !isSidebarOpen + 'sidebar-collapsed': !isSidebarOpen, + 'has-archived-block': job.archived }" :erase-path="job.erase_path" :size="traceSize" diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue index eeefa33264f..8b506b124ec 100644 --- a/app/assets/javascripts/jobs/components/job_log_controllers.vue +++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue @@ -69,7 +69,7 @@ export default { }; </script> <template> - <div class="top-bar affix"> + <div class="top-bar"> <!-- truncate information --> <div class="js-truncated-info truncated-info d-none d-sm-block float-left"> <template v-if="isTraceSizeVisible"> diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js index 2950c2299ab..d8255181574 100644 --- a/app/assets/javascripts/merge_request_tabs.js +++ b/app/assets/javascripts/merge_request_tabs.js @@ -11,7 +11,6 @@ import bp from './breakpoints'; import { parseUrlPathname, handleLocationHash, isMetaClick } from './lib/utils/common_utils'; import { isInVueNoteablePage } from './lib/utils/dom_utils'; import { getLocationHash } from './lib/utils/url_utility'; -import initDiscussionTab from './image_diff/init_discussion_tab'; import Diff from './diff'; import { localTimeAgo } from './lib/utils/datetime_utility'; import syntaxHighlight from './syntax_highlight'; @@ -207,8 +206,6 @@ export default class MergeRequestTabs { } this.resetViewContainer(); this.destroyPipelinesView(); - - initDiscussionTab(); } if (this.setUrl) { this.setCurrentAction(action); diff --git a/app/assets/javascripts/notes/components/diff_with_note.vue b/app/assets/javascripts/notes/components/diff_with_note.vue index eaa0cded224..b209f736c3f 100644 --- a/app/assets/javascripts/notes/components/diff_with_note.vue +++ b/app/assets/javascripts/notes/components/diff_with_note.vue @@ -1,15 +1,18 @@ <script> import { mapState, mapActions } from 'vuex'; -import imageDiffHelper from '~/image_diff/helpers/index'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import DiffFileHeader from '~/diffs/components/diff_file_header.vue'; +import DiffViewer from '~/vue_shared/components/diff_viewer/diff_viewer.vue'; +import ImageDiffOverlay from '~/diffs/components/image_diff_overlay.vue'; import { GlSkeletonLoading } from '@gitlab-org/gitlab-ui'; -import { trimFirstCharOfLineContent } from '~/diffs/store/utils'; +import { trimFirstCharOfLineContent, getDiffMode } from '~/diffs/store/utils'; export default { components: { DiffFileHeader, GlSkeletonLoading, + DiffViewer, + ImageDiffOverlay, }, props: { discussion: { @@ -25,7 +28,11 @@ export default { computed: { ...mapState({ noteableData: state => state.notes.noteableData, + projectPath: state => state.diffs.projectPath, }), + diffMode() { + return getDiffMode(this.diffFile); + }, hasTruncatedDiffLines() { return this.discussion.truncatedDiffLines && this.discussion.truncatedDiffLines.length !== 0; }, @@ -62,11 +69,7 @@ export default { }, }, mounted() { - if (this.isImageDiff) { - const canCreateNote = false; - const renderCommentBadge = true; - imageDiffHelper.initImageDiff(this.$refs.fileHolder, canCreateNote, renderCommentBadge); - } else if (!this.hasTruncatedDiffLines) { + if (!this.hasTruncatedDiffLines) { this.fetchDiff(); } }, @@ -160,7 +163,24 @@ export default { <div v-else > - <div v-html="imageDiffHtml"></div> + <diff-viewer + :diff-mode="diffMode" + :new-path="diffFile.newPath" + :new-sha="diffFile.diffRefs.headSha" + :old-path="diffFile.oldPath" + :old-sha="diffFile.diffRefs.baseSha" + :file-hash="diffFile.fileHash" + :project-path="projectPath" + > + <image-diff-overlay + slot="image-overlay" + :discussions="discussion" + :file-hash="diffFile.fileHash" + :show-comment-icon="true" + :should-toggle-discussion="false" + badge-class="image-comment-badge" + /> + </diff-viewer> <slot></slot> </div> </div> diff --git a/app/assets/javascripts/notes/components/note_actions.vue b/app/assets/javascripts/notes/components/note_actions.vue index e075f94b82b..dbd394ee6f2 100644 --- a/app/assets/javascripts/notes/components/note_actions.vue +++ b/app/assets/javascripts/notes/components/note_actions.vue @@ -9,11 +9,13 @@ import resolvedDiscussionSvg from 'icons/_icon_status_success_solid.svg'; import ellipsisSvg from 'icons/_ellipsis_v.svg'; import Icon from '~/vue_shared/components/icon.vue'; import tooltip from '~/vue_shared/directives/tooltip'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { name: 'NoteActions', components: { Icon, + GlLoadingIcon, }, directives: { tooltip, diff --git a/app/assets/javascripts/notes/components/noteable_discussion.vue b/app/assets/javascripts/notes/components/noteable_discussion.vue index 6293dd5b7e1..07115ca07c4 100644 --- a/app/assets/javascripts/notes/components/noteable_discussion.vue +++ b/app/assets/javascripts/notes/components/noteable_discussion.vue @@ -350,11 +350,18 @@ Please check your network connection and try again.`; <ul class="notes"> <component :is="componentName(note)" - v-for="note in discussion.notes" + v-for="(note, index) in discussion.notes" :key="note.id" :note="componentData(note)" @handleDeleteNote="deleteNoteHandler" - /> + > + <slot + v-if="index === 0" + slot="avatar-badge" + name="avatar-badge" + > + </slot> + </component> </ul> <div :class="{ 'is-replying': isReplying }" diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue index f391ed848a4..40222ac4a80 100644 --- a/app/assets/javascripts/notes/components/noteable_note.vue +++ b/app/assets/javascripts/notes/components/noteable_note.vue @@ -182,7 +182,13 @@ export default { :img-src="author.avatar_url" :img-alt="author.name" :img-size="40" - /> + > + <slot + slot="avatar-badge" + name="avatar-badge" + > + </slot> + </user-avatar-link> </div> <div class="timeline-content"> <div class="note-header"> diff --git a/app/assets/javascripts/pipelines/components/graph/graph_component.vue b/app/assets/javascripts/pipelines/components/graph/graph_component.vue index 23c0be7742e..4de8b3401e8 100644 --- a/app/assets/javascripts/pipelines/components/graph/graph_component.vue +++ b/app/assets/javascripts/pipelines/components/graph/graph_component.vue @@ -1,10 +1,12 @@ <script> import _ from 'underscore'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import StageColumnComponent from './stage_column_component.vue'; export default { components: { StageColumnComponent, + GlLoadingIcon, }, props: { isLoading: { diff --git a/app/assets/javascripts/pipelines/components/header_component.vue b/app/assets/javascripts/pipelines/components/header_component.vue index 1f9187c3d65..8f004b491c8 100644 --- a/app/assets/javascripts/pipelines/components/header_component.vue +++ b/app/assets/javascripts/pipelines/components/header_component.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import ciHeader from '../../vue_shared/components/header_ci_component.vue'; import eventHub from '../event_hub'; @@ -6,6 +7,7 @@ export default { name: 'PipelineHeaderSection', components: { ciHeader, + GlLoadingIcon, }, props: { pipeline: { diff --git a/app/assets/javascripts/pipelines/components/pipelines_actions.vue b/app/assets/javascripts/pipelines/components/pipelines_actions.vue index 07a4af3e61e..cb47704ca26 100644 --- a/app/assets/javascripts/pipelines/components/pipelines_actions.vue +++ b/app/assets/javascripts/pipelines/components/pipelines_actions.vue @@ -4,6 +4,7 @@ import eventHub from '../event_hub'; import Icon from '../../vue_shared/components/icon.vue'; import tooltip from '../../vue_shared/directives/tooltip'; import GlCountdown from '~/vue_shared/components/gl_countdown.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { directives: { @@ -12,6 +13,7 @@ export default { components: { Icon, GlCountdown, + GlLoadingIcon, }, props: { actions: { diff --git a/app/assets/javascripts/pipelines/components/stage.vue b/app/assets/javascripts/pipelines/components/stage.vue index 7ec55792850..3df8f7a6da6 100644 --- a/app/assets/javascripts/pipelines/components/stage.vue +++ b/app/assets/javascripts/pipelines/components/stage.vue @@ -13,6 +13,7 @@ */ import $ from 'jquery'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import { __ } from '../../locale'; import Flash from '../../flash'; import axios from '../../lib/utils/axios_utils'; @@ -26,6 +27,7 @@ export default { components: { Icon, JobItem, + GlLoadingIcon, }, directives: { diff --git a/app/assets/javascripts/pipelines/mixins/pipelines.js b/app/assets/javascripts/pipelines/mixins/pipelines.js index 85781f548c6..41bc5dcce5c 100644 --- a/app/assets/javascripts/pipelines/mixins/pipelines.js +++ b/app/assets/javascripts/pipelines/mixins/pipelines.js @@ -1,4 +1,5 @@ import Visibility from 'visibilityjs'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import { __ } from '../../locale'; import Flash from '../../flash'; import Poll from '../../lib/utils/poll'; @@ -13,6 +14,7 @@ export default { PipelinesTableComponent, SvgBlankState, EmptyState, + GlLoadingIcon, }, data() { return { diff --git a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js index d5266544307..f5dae5ad808 100644 --- a/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js +++ b/app/assets/javascripts/projects/gke_cluster_dropdowns/components/gke_dropdown_mixin.js @@ -2,6 +2,7 @@ import _ from 'underscore'; import DropdownSearchInput from '~/vue_shared/components/dropdown/dropdown_search_input.vue'; import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import store from '../store'; @@ -11,6 +12,7 @@ export default { DropdownButton, DropdownSearchInput, DropdownHiddenInput, + GlLoadingIcon, }, props: { fieldId: { diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue index 120b4fc2f2b..9a729ca9b91 100644 --- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue +++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue @@ -5,6 +5,7 @@ import Poll from '~/lib/utils/poll'; import Flash from '~/flash'; import { s__, sprintf } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import CommitPipelineService from '../services/commit_pipeline_service'; export default { @@ -13,6 +14,7 @@ export default { }, components: { ciIcon, + GlLoadingIcon, }, props: { endpoint: { diff --git a/app/assets/javascripts/registry/components/app.vue b/app/assets/javascripts/registry/components/app.vue index 9dd1c87a87d..0a906f40f5a 100644 --- a/app/assets/javascripts/registry/components/app.vue +++ b/app/assets/javascripts/registry/components/app.vue @@ -1,5 +1,6 @@ <script> import { mapGetters, mapActions } from 'vuex'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import Flash from '../../flash'; import store from '../stores'; import collapsibleContainer from './collapsible_container.vue'; @@ -9,6 +10,7 @@ export default { name: 'RegistryListApp', components: { collapsibleContainer, + GlLoadingIcon, }, props: { endpoint: { diff --git a/app/assets/javascripts/registry/components/collapsible_container.vue b/app/assets/javascripts/registry/components/collapsible_container.vue index 501b2625ae5..be9816a55c4 100644 --- a/app/assets/javascripts/registry/components/collapsible_container.vue +++ b/app/assets/javascripts/registry/components/collapsible_container.vue @@ -1,5 +1,6 @@ <script> import { mapActions } from 'vuex'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import Flash from '../../flash'; import clipboardButton from '../../vue_shared/components/clipboard_button.vue'; import tooltip from '../../vue_shared/directives/tooltip'; @@ -12,6 +13,7 @@ export default { components: { clipboardButton, tableRegistry, + GlLoadingIcon, }, directives: { tooltip, diff --git a/app/assets/javascripts/reports/components/summary_row.vue b/app/assets/javascripts/reports/components/summary_row.vue index 51188981bed..a44ba833b63 100644 --- a/app/assets/javascripts/reports/components/summary_row.vue +++ b/app/assets/javascripts/reports/components/summary_row.vue @@ -1,6 +1,7 @@ <script> import CiIcon from '~/vue_shared/components/ci_icon.vue'; import Popover from '~/vue_shared/components/help_popover.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; /** * Renders the summary row for each report @@ -15,6 +16,7 @@ export default { components: { CiIcon, Popover, + GlLoadingIcon, }, props: { summary: { diff --git a/app/assets/javascripts/sidebar/components/participants/participants.vue b/app/assets/javascripts/sidebar/components/participants/participants.vue index 11b5dbe5f8e..fe73f6a0cef 100644 --- a/app/assets/javascripts/sidebar/components/participants/participants.vue +++ b/app/assets/javascripts/sidebar/components/participants/participants.vue @@ -2,6 +2,7 @@ import { __, n__, sprintf } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { directives: { @@ -9,6 +10,7 @@ export default { }, components: { userAvatarImage, + GlLoadingIcon, }, props: { loading: { diff --git a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue index bc59774f0a8..913a616d9f1 100644 --- a/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue +++ b/app/assets/javascripts/sidebar/components/todo_toggle/todo.vue @@ -1,6 +1,7 @@ <script> import { __ } from '~/locale'; import tooltip from '~/vue_shared/directives/tooltip'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import Icon from '~/vue_shared/components/icon.vue'; @@ -13,6 +14,7 @@ export default { }, components: { Icon, + GlLoadingIcon, }, props: { issuableId: { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue index ba6a1687e51..b3340290ed3 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_widget_status_icon.vue @@ -1,9 +1,11 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import ciIcon from '../../vue_shared/components/ci_icon.vue'; export default { components: { ciIcon, + GlLoadingIcon, }, props: { status: { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue index 4f8b07484c0..4bfbdcf1404 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import eventHub from '../../event_hub'; import statusIcon from '../mr_widget_status_icon.vue'; @@ -6,6 +7,7 @@ export default { name: 'MRWidgetAutoMergeFailed', components: { statusIcon, + GlLoadingIcon, }, props: { mr: { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue index 656c3b5c47e..7e33021e4b4 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_merged.vue @@ -6,6 +6,7 @@ import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import MrWidgetAuthorTime from '../../components/mr_widget_author_time.vue'; import statusIcon from '../mr_widget_status_icon.vue'; import eventHub from '../../event_hub'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { name: 'MRWidgetMerged', @@ -16,6 +17,7 @@ export default { MrWidgetAuthorTime, statusIcon, ClipboardButton, + GlLoadingIcon, }, props: { mr: { diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue index 041fa13a8f5..0e714cc2aa1 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_rebase.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import simplePoll from '../../../lib/utils/simple_poll'; import eventHub from '../../event_hub'; import statusIcon from '../mr_widget_status_icon.vue'; @@ -8,6 +9,7 @@ export default { name: 'MRWidgetRebase', components: { statusIcon, + GlLoadingIcon, }, props: { mr: { diff --git a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue index 8163947cd0c..6f2f0f98690 100644 --- a/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/content_viewer/viewers/image_viewer.vue @@ -17,19 +17,37 @@ export default { type: Boolean, default: true, }, + innerCssClasses: { + type: [Array, Object, String], + required: false, + default: '', + }, }, data() { return { width: 0, height: 0, - isZoomable: false, - isZoomed: false, + isLoaded: false, }; }, computed: { fileSizeReadable() { return numberToHumanSize(this.fileSize); }, + dimensionStyles() { + if (!this.isLoaded) return {}; + + return { + width: `${this.width}px`, + height: `${this.height}px`, + }; + }, + hasFileSize() { + return this.fileSize > 0; + }, + hasDimensions() { + return this.width && this.height; + }, }, beforeDestroy() { window.removeEventListener('resize', this.resizeThrottled, false); @@ -48,51 +66,52 @@ export default { const { contentImg } = this.$refs; if (contentImg) { - this.isZoomable = - contentImg.naturalWidth > contentImg.width || - contentImg.naturalHeight > contentImg.height; - this.width = contentImg.naturalWidth; this.height = contentImg.naturalHeight; - this.$emit('imgLoaded', { - width: this.width, - height: this.height, - renderedWidth: contentImg.clientWidth, - renderedHeight: contentImg.clientHeight, + this.$nextTick(() => { + this.isLoaded = true; + + this.$emit('imgLoaded', { + width: this.width, + height: this.height, + renderedWidth: contentImg.clientWidth, + renderedHeight: contentImg.clientHeight, + }); }); } }, - onImgClick() { - if (this.isZoomable) this.isZoomed = !this.isZoomed; - }, }, }; </script> <template> - <div class="file-container"> - <div class="file-content image_file"> + <div> + <div + :class="innerCssClasses" + :style="dimensionStyles" + class="position-relative" + > <img ref="contentImg" - :class="{ 'is-zoomable': isZoomable, 'is-zoomed': isZoomed }" :src="path" - :alt="path" @load="onImgLoad" - @click="onImgClick"/> - <p - v-if="renderInfo" - class="file-info prepend-top-10"> - <template v-if="fileSize>0"> - {{ fileSizeReadable }} - </template> - <template v-if="fileSize>0 && width && height"> - | - </template> - <template v-if="width && height"> - W: {{ width }} | H: {{ height }} - </template> - </p> + /> + <slot name="image-overlay"></slot> </div> + <p + v-if="renderInfo" + class="image-info" + > + <template v-if="hasFileSize"> + {{ fileSizeReadable }} + </template> + <template v-if="hasFileSize && hasDimensions"> + | + </template> + <template v-if="hasDimensions"> + <strong>W</strong>: {{ width }} | <strong>H</strong>: {{ height }} + </template> + </p> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue index cfc5343217c..9c3f3e7f7a9 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/diff_viewer.vue @@ -69,6 +69,13 @@ export default { :new-path="fullNewPath" :old-path="fullOldPath" :project-path="projectPath" - /> + > + <slot + slot="image-overlay" + name="image-overlay" + > + </slot> + </component> + <slot></slot> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue index 38e881d17a2..cd0c1e850af 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/onion_skin_viewer.vue @@ -15,11 +15,6 @@ export default { type: String, required: true, }, - projectPath: { - type: String, - required: false, - default: '', - }, }, data() { return { @@ -120,7 +115,6 @@ export default { key="onionOldImg" :render-info="false" :path="oldPath" - :project-path="projectPath" @imgLoaded="onionOldImgLoaded" /> </div> @@ -136,9 +130,14 @@ export default { key="onionNewImg" :render-info="false" :path="newPath" - :project-path="projectPath" @imgLoaded="onionNewImgLoaded" - /> + > + <slot + slot="image-overlay" + name="image-overlay" + > + </slot> + </image-viewer> </div> <div class="controls"> <div class="transparent"></div> diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue index 86366c799a2..c3cfe54eb4d 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/swipe_viewer.vue @@ -16,11 +16,6 @@ export default { type: String, required: true, }, - projectPath: { - type: String, - required: false, - default: '', - }, }, data() { return { @@ -117,16 +112,14 @@ export default { 'height': swipeMaxPixelHeight, }" class="swipe-frame"> - <div class="frame deleted"> - <image-viewer - key="swipeOldImg" - ref="swipeOldImg" - :render-info="false" - :path="oldPath" - :project-path="projectPath" - @imgLoaded="swipeOldImgLoaded" - /> - </div> + <image-viewer + key="swipeOldImg" + ref="swipeOldImg" + :render-info="false" + :path="oldPath" + class="frame deleted" + @imgLoaded="swipeOldImgLoaded" + /> <div ref="swipeWrap" :style="{ @@ -134,15 +127,19 @@ export default { 'height': swipeMaxPixelHeight, }" class="swipe-wrap"> - <div class="frame added"> - <image-viewer - key="swipeNewImg" - :render-info="false" - :path="newPath" - :project-path="projectPath" - @imgLoaded="swipeNewImgLoaded" - /> - </div> + <image-viewer + key="swipeNewImg" + :render-info="false" + :path="newPath" + class="frame added" + @imgLoaded="swipeNewImgLoaded" + > + <slot + slot="image-overlay" + name="image-overlay" + > + </slot> + </image-viewer> </div> <span ref="swipeBar" diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue index 9c19266ecdf..9806d65e940 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff/two_up_viewer.vue @@ -14,28 +14,29 @@ export default { type: String, required: true, }, - projectPath: { - type: String, - required: false, - default: '', - }, }, }; </script> <template> - <div class="two-up view row"> - <div class="col-sm-6 frame deleted"> - <image-viewer - :path="oldPath" - :project-path="projectPath" - /> - </div> - <div class="col-sm-6 frame added"> - <image-viewer - :path="newPath" - :project-path="projectPath" - /> - </div> + <div class="two-up view"> + <image-viewer + :path="oldPath" + :render-info="true" + inner-css-classes="frame deleted" + class="wrap" + /> + <image-viewer + :path="newPath" + :render-info="true" + :inner-css-classes="['frame', 'added']" + class="wrap" + > + <slot + slot="image-overlay" + name="image-overlay" + > + </slot> + </image-viewer> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue index 1af85283277..e68a2aa73fa 100644 --- a/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/image_diff_viewer.vue @@ -8,9 +8,6 @@ import { diffModes, imageViewMode } from '../constants'; export default { components: { ImageViewer, - TwoUpViewer, - SwipeViewer, - OnionSkinViewer, }, props: { diffMode: { @@ -25,17 +22,32 @@ export default { type: String, required: true, }, - projectPath: { - type: String, - required: false, - default: '', - }, }, data() { return { mode: imageViewMode.twoup, }; }, + computed: { + imageViewComponent() { + switch (this.mode) { + case imageViewMode.twoup: + return TwoUpViewer; + case imageViewMode.swipe: + return SwipeViewer; + case imageViewMode.onion: + return OnionSkinViewer; + default: + return undefined; + } + }, + isNew() { + return this.diffMode === diffModes.new; + }, + imagePath() { + return this.isNew ? this.newPath : this.oldPath; + }, + }, methods: { changeMode(newMode) { this.mode = newMode; @@ -52,15 +64,16 @@ export default { v-if="diffMode === $options.diffModes.replaced" class="diff-viewer"> <div class="image js-replaced-image"> - <two-up-viewer - v-if="mode === $options.imageViewMode.twoup" - v-bind="$props"/> - <swipe-viewer - v-else-if="mode === $options.imageViewMode.swipe" - v-bind="$props"/> - <onion-skin-viewer - v-else-if="mode === $options.imageViewMode.onion" - v-bind="$props"/> + <component + :is="imageViewComponent" + v-bind="$props" + > + <slot + slot="image-overlay" + name="image-overlay" + > + </slot> + </component> </div> <div class="view-modes"> <ul class="view-modes-menu"> @@ -87,23 +100,27 @@ export default { </li> </ul> </div> - <div class="note-container"></div> - </div> - <div - v-else-if="diffMode === $options.diffModes.new" - class="diff-viewer added"> - <image-viewer - :path="newPath" - :project-path="projectPath" - /> </div> <div v-else - class="diff-viewer deleted"> - <image-viewer - :path="oldPath" - :project-path="projectPath" - /> + class="diff-viewer" + > + <div class="image"> + <image-viewer + :path="imagePath" + :inner-css-classes="['frame', { + 'added': isNew, + 'deleted': diffMode === $options.diffModes.deleted + }]" + > + <slot + v-if="isNew" + slot="image-overlay" + name="image-overlay" + > + </slot> + </image-viewer> + </div> </div> </div> </template> diff --git a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue index 31087017968..0e194eaaed5 100644 --- a/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue +++ b/app/assets/javascripts/vue_shared/components/dropdown/dropdown_button.vue @@ -1,7 +1,11 @@ <script> import { __ } from '~/locale'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; export default { + components: { + GlLoadingIcon, + }, props: { isDisabled: { type: Boolean, diff --git a/app/assets/javascripts/vue_shared/components/file_icon.vue b/app/assets/javascripts/vue_shared/components/file_icon.vue index 408f7d7965f..03818be6a69 100644 --- a/app/assets/javascripts/vue_shared/components/file_icon.vue +++ b/app/assets/javascripts/vue_shared/components/file_icon.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import getIconForFile from './file_icon/file_icon_map'; import icon from '../../vue_shared/components/icon.vue'; @@ -17,6 +18,7 @@ import icon from '../../vue_shared/components/icon.vue'; export default { components: { icon, + GlLoadingIcon, }, props: { fileName: { diff --git a/app/assets/javascripts/vue_shared/components/loading_button.vue b/app/assets/javascripts/vue_shared/components/loading_button.vue index f9b7fd5b1f9..69d7e5c46f5 100644 --- a/app/assets/javascripts/vue_shared/components/loading_button.vue +++ b/app/assets/javascripts/vue_shared/components/loading_button.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; /* eslint-disable vue/require-default-prop */ /* This is a re-usable vue component for rendering a button that will probably be sending off ajax requests and need @@ -18,6 +19,9 @@ */ export default { + components: { + GlLoadingIcon, + }, props: { loading: { type: Boolean, diff --git a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue index 500586302cf..5b12bb6b59e 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/date_picker.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import datePicker from '../pikaday.vue'; import toggleSidebar from './toggle_sidebar.vue'; import collapsedCalendarIcon from './collapsed_calendar_icon.vue'; @@ -10,6 +11,7 @@ export default { datePicker, toggleSidebar, collapsedCalendarIcon, + GlLoadingIcon, }, props: { blockClass: { diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue index 3df286de129..e50d612ce36 100644 --- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue +++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/base.vue @@ -4,6 +4,7 @@ import { __ } from '~/locale'; import LabelsSelect from '~/labels_select'; import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue'; +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import DropdownTitle from './dropdown_title.vue'; import DropdownValue from './dropdown_value.vue'; import DropdownValueCollapsed from './dropdown_value_collapsed.vue'; @@ -24,6 +25,7 @@ export default { DropdownSearchInput, DropdownFooter, DropdownCreateLabel, + GlLoadingIcon, }, props: { showCreate: { diff --git a/app/assets/javascripts/vue_shared/components/toggle_button.vue b/app/assets/javascripts/vue_shared/components/toggle_button.vue index 4e9289cbed8..e7cb5cfac12 100644 --- a/app/assets/javascripts/vue_shared/components/toggle_button.vue +++ b/app/assets/javascripts/vue_shared/components/toggle_button.vue @@ -1,4 +1,5 @@ <script> +import { GlLoadingIcon } from '@gitlab-org/gitlab-ui'; import { s__ } from '../../locale'; import icon from './icon.vue'; @@ -10,6 +11,7 @@ const LABEL_OFF = s__('ToggleButton|Toggle Status: OFF'); export default { components: { icon, + GlLoadingIcon, }, model: { diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue index 86c7498a092..dd6f96e2609 100644 --- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue +++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue @@ -99,6 +99,6 @@ export default { v-tooltip :title="tooltipText" :tooltip-placement="tooltipPlacement" - >{{ username }}</span> + >{{ username }}</span><slot name="avatar-badge"></slot> </gl-link> </template> diff --git a/app/assets/stylesheets/pages/builds.scss b/app/assets/stylesheets/pages/builds.scss index 1449723de52..81cb519883b 100644 --- a/app/assets/stylesheets/pages/builds.scss +++ b/app/assets/stylesheets/pages/builds.scss @@ -55,9 +55,29 @@ @include build-trace(); } + .archived-sticky { + top: $header-height; + border-radius: 2px 2px 0 0; + color: $orange-600; + background-color: $orange-100; + border: 1px solid $border-gray-normal; + border-bottom: 0; + padding: 3px 12px; + margin: auto; + align-items: center; + + .with-performance-bar & { + top: $header-height + $performance-bar-height; + } + } + .top-bar { @include build-trace-top-bar(35px); + &.has-archived-block { + top: $header-height + $performance-bar-height + 28px; + } + &.affix { top: $header-height; diff --git a/app/assets/stylesheets/pages/diff.scss b/app/assets/stylesheets/pages/diff.scss index 52c91266ff4..19bc4262e21 100644 --- a/app/assets/stylesheets/pages/diff.scss +++ b/app/assets/stylesheets/pages/diff.scss @@ -421,21 +421,13 @@ .diff-file-container { .frame.deleted { - border: 0; + border: 1px solid $deleted; background-color: inherit; - - .image_file img { - border: 1px solid $deleted; - } } .frame.added { - border: 0; + border: 1px solid $added; background-color: inherit; - - .image_file img { - border: 1px solid $added; - } } .swipe.view, @@ -481,6 +473,11 @@ bottom: -25px; } } + + .discussion-notes .discussion-notes { + margin-left: 0; + border-left: 0; + } } .file-content .diff-file { @@ -804,7 +801,7 @@ // double jagged line divider .discussion-notes + .discussion-notes::before, - .discussion-notes + .discussion-form::before { + .diff-file-discussions + .discussion-form::before { content: ''; position: relative; display: block; @@ -844,6 +841,13 @@ background-repeat: repeat; } + .diff-file-discussions + .discussion-form::before { + width: auto; + margin-left: -16px; + margin-right: -16px; + margin-bottom: 16px; + } + .notes { position: relative; } @@ -870,11 +874,13 @@ } } -.files:not([data-can-create-note]) .frame { +.files:not([data-can-create-note="true"]) .frame { cursor: auto; } -.frame.click-to-comment { +.frame, +.frame.click-to-comment, +.btn-transparent.image-diff-overlay-add-comment { position: relative; cursor: image-url('illustrations/image_comment_light_cursor.svg') $image-comment-cursor-left-offset $image-comment-cursor-top-offset, @@ -910,6 +916,7 @@ .frame .badge.badge-pill, .image-diff-avatar-link .badge.badge-pill, +.user-avatar-link .badge.badge-pill, .notes > .badge.badge-pill { position: absolute; background-color: $blue-400; @@ -944,7 +951,8 @@ } } -.image-diff-avatar-link { +.image-diff-avatar-link, +.user-avatar-link { position: relative; .badge.badge-pill, @@ -1073,3 +1081,14 @@ top: 0; } } + +.image-diff-overlay, +.image-diff-overlay-add-comment { + top: 0; + left: 0; + + &:active, + &:focus { + outline: 0; + } +} |