diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 4660431723260ec07e076d37300fdc8a97132459..4ae319d64d7f5248e4b3edf361f489856b6f1bcb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -488,7 +488,6 @@ danger-review: <<: *pull-cache image: registry.gitlab.com/gitlab-org/gitlab-build-images:danger stage: test - allow_failure: true dependencies: [] before_script: [] only: @@ -555,7 +554,8 @@ docs lint: # Build HTML from Markdown - bundle exec nanoc # Check the internal links - - bundle exec nanoc check internal_links + # Disabled until https://gitlab.com/gitlab-com/gitlab-docs/issues/305 is resolved + # - bundle exec nanoc check internal_links downtime_check: <<: *rake-exec diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS.disabled similarity index 91% rename from .gitlab/CODEOWNERS rename to .gitlab/CODEOWNERS.disabled index a4b773b15a9d2d91fa9927306e3c9d8bd8114229..82e914a502fe7e60523972d52f56f5cccff39a30 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS.disabled @@ -6,8 +6,8 @@ /doc/ @axil @marcia # Frontend maintainers should see everything in `app/assets/` -app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann -*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann +app/assets/ @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya +*.scss @annabeldunstone @ClemMakesApps @fatihacet @filipa @iamphill @mikegreiling @timzallmann @kushalpandya # Someone from the database team should review changes in `db/` db/ @abrandl @NikolayS diff --git a/.gitlab/issue_templates/Feature proposal.md b/.gitlab/issue_templates/Feature proposal.md index c4065d3c4eae4ae772f2e90b635f3adc35ef51e5..ad517f0457d0fd634366c0b53325f35d9f5309e1 100644 --- a/.gitlab/issue_templates/Feature proposal.md +++ b/.gitlab/issue_templates/Feature proposal.md @@ -1,14 +1,22 @@ ### Problem to solve + + +### Target audience + + + ### Further details -(Include use cases, benefits, and/or goals) + ### Proposal + + ### What does success look like, and how can we measure that? -(If no way to measure success, link to an issue that will implement a way to measure this) + ### Links / references diff --git a/GITLAB_WORKHORSE_VERSION b/GITLAB_WORKHORSE_VERSION index 18bb4182dd01428f1d4c3c2145501ee5d40455a3..93c8ddab9fef3d606dcbc0d562545592cdc40dce 100644 --- a/GITLAB_WORKHORSE_VERSION +++ b/GITLAB_WORKHORSE_VERSION @@ -1 +1 @@ -7.5.0 +7.6.0 diff --git a/Gemfile.lock b/Gemfile.lock index 608d1814127266722e0a0339f1ad46ff2fef788f..430025c7bdeb56342bb2b4a8f446d79aa21f7210 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -807,7 +807,7 @@ GEM selenium-webdriver (3.12.0) childprocess (~> 0.5) rubyzip (~> 1.2) - sentry-raven (2.7.2) + sentry-raven (2.7.4) faraday (>= 0.7.6, < 1.0) settingslogic (2.0.9) sexp_processor (4.11.0) diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index de003e70e610a1a98dac45b2f6a6c323fe526b16..7607c4b3b796f15da1d3593378af1074a09b6066 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -21,8 +21,11 @@ const Api = { projectTemplatePath: '/api/:version/projects/:id/templates/:type/:key', projectTemplatesPath: '/api/:version/projects/:id/templates/:type', usersPath: '/api/:version/users.json', - userStatusPath: '/api/:version/user/status', + userPath: '/api/:version/users/:id', + userStatusPath: '/api/:version/users/:id/status', + userPostStatusPath: '/api/:version/user/status', commitPath: '/api/:version/projects/:id/repository/commits', + applySuggestionPath: '/api/:version/suggestions/:id/apply', commitPipelinesPath: '/:project_id/commit/:sha/pipelines', branchSinglePath: '/api/:version/projects/:id/repository/branches/:branch', createBranchPath: '/api/:version/projects/:id/repository/branches', @@ -183,6 +186,12 @@ const Api = { }); }, + applySuggestion(id) { + const url = Api.buildUrl(Api.applySuggestionPath).replace(':id', encodeURIComponent(id)); + + return axios.put(url); + }, + commitPipelines(projectId, sha) { const encodedProjectId = projectId .split('/') @@ -254,6 +263,20 @@ const Api = { }); }, + user(id, options) { + const url = Api.buildUrl(this.userPath).replace(':id', encodeURIComponent(id)); + return axios.get(url, { + params: options, + }); + }, + + userStatus(id, options) { + const url = Api.buildUrl(this.userStatusPath).replace(':id', encodeURIComponent(id)); + return axios.get(url, { + params: options, + }); + }, + branches(id, query = '', options = {}) { const url = Api.buildUrl(this.createBranchPath).replace(':id', encodeURIComponent(id)); @@ -276,7 +299,7 @@ const Api = { }, postUserStatus({ emoji, message }) { - const url = Api.buildUrl(this.userStatusPath); + const url = Api.buildUrl(this.userPostStatusPath); return axios.put(url, { emoji, diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js index a2d4331b6d1b4ce03e3094a702387f016e4e74c7..fc9286d15e6d904bfbb481595f1f0ff12e5a8885 100644 --- a/app/assets/javascripts/behaviors/markdown/render_gfm.js +++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js @@ -3,6 +3,7 @@ import syntaxHighlight from '~/syntax_highlight'; import renderMath from './render_math'; import renderMermaid from './render_mermaid'; import highlightCurrentUser from './highlight_current_user'; +import initUserPopovers from '../../user_popovers'; // Render GitLab flavoured Markdown // @@ -13,6 +14,7 @@ $.fn.renderGFM = function renderGFM() { renderMath(this.find('.js-render-math')); renderMermaid(this.find('.js-render-mermaid')); highlightCurrentUser(this.find('.gfm-project_member').get()); + initUserPopovers(this.find('.gfm-project_member').get()); return this; }; diff --git a/app/assets/javascripts/boards/components/issue_due_date.vue b/app/assets/javascripts/boards/components/issue_due_date.vue index 15937b1091ae10981b1f7f4ff305b465d41307dd..e038198e6f04cec75d6b72ef74f14d69d2512ea3 100644 --- a/app/assets/javascripts/boards/components/issue_due_date.vue +++ b/app/assets/javascripts/boards/components/issue_due_date.vue @@ -15,6 +15,16 @@ export default { type: String, required: true, }, + cssClass: { + type: String, + required: false, + default: '', + }, + tooltipPlacement: { + type: String, + required: false, + default: 'bottom', + }, }, computed: { title() { @@ -66,15 +76,13 @@ export default { diff --git a/app/assets/javascripts/diffs/components/diff_content.vue b/app/assets/javascripts/diffs/components/diff_content.vue index 11cc4c09fedb8d589c6cca767de6ca51cc4451ac..ac963f2971e224c4d2bff728774ad1200cd25b88 100644 --- a/app/assets/javascripts/diffs/components/diff_content.vue +++ b/app/assets/javascripts/diffs/components/diff_content.vue @@ -23,6 +23,11 @@ export default { type: Object, required: true, }, + helpPagePath: { + type: String, + required: false, + default: '', + }, }, computed: { ...mapState({ @@ -74,11 +79,13 @@ export default { v-if="isInlineView" :diff-file="diffFile" :diff-lines="diffFile.highlighted_diff_lines || []" + :help-page-path="helpPagePath" /> diff --git a/app/assets/javascripts/diffs/components/diff_file.vue b/app/assets/javascripts/diffs/components/diff_file.vue index 3b2a0d156cae8d5976c5954c2b3a0f324add51b8..449f70070775f76563af5a3aad0916035415c27a 100644 --- a/app/assets/javascripts/diffs/components/diff_file.vue +++ b/app/assets/javascripts/diffs/components/diff_file.vue @@ -4,6 +4,7 @@ import _ from 'underscore'; import { __, sprintf } from '~/locale'; import createFlash from '~/flash'; import { GlLoadingIcon } from '@gitlab/ui'; +import eventHub from '../../notes/event_hub'; import DiffFileHeader from './diff_file_header.vue'; import DiffContent from './diff_content.vue'; @@ -22,6 +23,11 @@ export default { type: Boolean, required: true, }, + helpPagePath: { + type: String, + required: false, + default: '', + }, }, data() { return { @@ -75,6 +81,9 @@ export default { } }, }, + created() { + eventHub.$on(`loadCollapsedDiff/${this.file.file_hash}`, this.handleLoadCollapsedDiff); + }, methods: { ...mapActions('diffs', ['loadCollapsedDiff', 'assignDiscussionsToDiff']), handleToggle() { @@ -160,6 +169,7 @@ export default { v-if="!isCollapsed && file.renderIt" :class="{ hidden: isCollapsed || file.too_large }" :diff-file="file" + :help-page-path="helpPagePath" />
diff --git a/app/assets/javascripts/diffs/components/diff_line_note_form.vue b/app/assets/javascripts/diffs/components/diff_line_note_form.vue index 9fd02acbd6e0e626164d6e931a0ff7d06df88951..e7569ba7b84d9894606b403d50a645045f3aaa71 100644 --- a/app/assets/javascripts/diffs/components/diff_line_note_form.vue +++ b/app/assets/javascripts/diffs/components/diff_line_note_form.vue @@ -94,6 +94,7 @@ export default { ref="noteForm" :is-editing="true" :line-code="line.line_code" + :line="line" save-button-title="Comment" class="diff-comment-form" @cancelForm="handleCancelCommentForm" diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue index aa40b24950ae23001d6cc4d1cfeb0269286028a8..814ee0b7c02f35b04c7fc386a31b0b817c5de0a2 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue @@ -16,6 +16,11 @@ export default { type: String, required: true, }, + helpPagePath: { + type: String, + required: false, + default: '', + }, }, computed: { className() { @@ -38,7 +43,12 @@ export default {
- + diff --git a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue index b98463d3dd359fcd486ab775c16c31424cd40ecb..a65cf025cdedb8d7cee8bf3352c6b1f20e70ce50 100644 --- a/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/parallel_diff_comment_row.vue @@ -20,6 +20,11 @@ export default { type: Number, required: true, }, + helpPagePath: { + type: String, + required: false, + default: '', + }, }, computed: { hasExpandedDiscussionOnLeft() { @@ -87,6 +92,8 @@ export default {
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index 06ef4207d85c6e381fdcddc3ca15fecd04e6f182..41e6bd8107286b3f31202586a9287e01fa4a98b7 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -16,6 +16,7 @@ export default function initDiffsApp(store) { return { endpoint: dataset.endpoint, projectPath: dataset.projectPath, + helpPagePath: dataset.helpPagePath, currentUser: JSON.parse(dataset.currentUserData) || {}, }; }, @@ -30,6 +31,7 @@ export default function initDiffsApp(store) { endpoint: this.endpoint, currentUser: this.currentUser, projectPath: this.projectPath, + helpPagePath: this.helpPagePath, shouldShow: this.activeTab === 'diffs', }, }); diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index 952963e071186d9787c7bcd76946984b2fc66149..00a4bb6d3a3a80b2ba58f89a248bfcc00ebc0dd7 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -3,8 +3,9 @@ import axios from '~/lib/utils/axios_utils'; import Cookies from 'js-cookie'; import createFlash from '~/flash'; import { s__ } from '~/locale'; -import { handleLocationHash, historyPushState } from '~/lib/utils/common_utils'; +import { handleLocationHash, historyPushState, scrollToElement } from '~/lib/utils/common_utils'; import { mergeUrlParams, getLocationHash } from '~/lib/utils/url_utility'; +import eventHub from '../../notes/event_hub'; import { getDiffPositionByLineCode, getNoteFormData } from './utils'; import * as types from './mutation_types'; import { @@ -53,6 +54,10 @@ export const assignDiscussionsToDiff = ( diffPositionByLineCode, }); }); + + Vue.nextTick(() => { + eventHub.$emit('scrollToDiscussion'); + }); }; export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => { @@ -60,6 +65,27 @@ export const removeDiscussionsFromDiff = ({ commit }, removeDiscussion) => { commit(types.REMOVE_LINE_DISCUSSIONS_FOR_FILE, { fileHash: file_hash, lineCode: line_code, id }); }; +export const renderFileForDiscussionId = ({ commit, rootState, state }, discussionId) => { + const discussion = rootState.notes.discussions.find(d => d.id === discussionId); + + if (discussion) { + const file = state.diffFiles.find(f => f.file_hash === discussion.diff_file.file_hash); + + if (file) { + if (!file.renderIt) { + commit(types.RENDER_FILE, file); + } + + if (file.collapsed) { + eventHub.$emit(`loadCollapsedDiff/${file.file_hash}`); + scrollToElement(document.getElementById(file.file_hash)); + } else { + eventHub.$emit('scrollToDiscussion'); + } + } + } +}; + export const startRenderDiffsQueue = ({ state, commit }) => { const checkItem = () => new Promise(resolve => { diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 331fb052371898965332a1fd13e82f4456eba23a..2ea884d1293b56e97b6023dff3165f203bae1d73 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -123,22 +123,23 @@ export default { diffPosition: diffPositionByLineCode[line.line_code], latestDiff, }); + const mapDiscussions = (line, extraCheck = () => true) => ({ + ...line, + discussions: extraCheck() + ? line.discussions + .filter(() => !line.discussions.some(({ id }) => discussion.id === id)) + .concat(lineCheck(line) ? discussion : line.discussions) + : [], + }); state.diffFiles = state.diffFiles.map(diffFile => { if (diffFile.file_hash === fileHash) { const file = { ...diffFile }; if (file.highlighted_diff_lines) { - file.highlighted_diff_lines = file.highlighted_diff_lines.map(line => { - if (!line.discussions.some(({ id }) => discussion.id === id) && lineCheck(line)) { - return { - ...line, - discussions: line.discussions.concat(discussion), - }; - } - - return line; - }); + file.highlighted_diff_lines = file.highlighted_diff_lines.map(line => + mapDiscussions(line), + ); } if (file.parallel_diff_lines) { @@ -148,20 +149,8 @@ export default { if (left || right) { return { - left: { - ...line.left, - discussions: - left && !line.left.discussions.some(({ id }) => id === discussion.id) - ? line.left.discussions.concat(discussion) - : (line.left && line.left.discussions) || [], - }, - right: { - ...line.right, - discussions: - right && !left && !line.right.discussions.some(({ id }) => id === discussion.id) - ? line.right.discussions.concat(discussion) - : (line.right && line.right.discussions) || [], - }, + left: line.left ? mapDiscussions(line.left) : null, + right: line.right ? mapDiscussions(line.right, () => !left) : null, }; } @@ -170,7 +159,7 @@ export default { } if (!file.parallel_diff_lines || !file.highlighted_diff_lines) { - file.discussions = file.discussions.concat(discussion); + file.discussions = (file.discussions || []).concat(discussion); } return file; @@ -180,7 +169,7 @@ export default { }); }, - [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode, id }) { + [types.REMOVE_LINE_DISCUSSIONS_FOR_FILE](state, { fileHash, lineCode }) { const selectedFile = state.diffFiles.find(f => f.file_hash === fileHash); if (selectedFile) { if (selectedFile.parallel_diff_lines) { @@ -193,7 +182,7 @@ export default { const side = targetLine.left && targetLine.left.line_code === lineCode ? 'left' : 'right'; Object.assign(targetLine[side], { - discussions: [], + discussions: targetLine[side].discussions.filter(discussion => discussion.notes.length), }); } } @@ -205,14 +194,14 @@ export default { if (targetInlineLine) { Object.assign(targetInlineLine, { - discussions: [], + discussions: targetInlineLine.discussions.filter(discussion => discussion.notes.length), }); } } if (selectedFile.discussions && selectedFile.discussions.length) { selectedFile.discussions = selectedFile.discussions.filter( - discussion => discussion.id !== id, + discussion => discussion.notes.length, ); } } diff --git a/app/assets/javascripts/image_diff/helpers/badge_helper.js b/app/assets/javascripts/image_diff/helpers/badge_helper.js index eddaeda9578c81d8c02318620767305aee505cd9..000157efad0d0cae87df25cf33436be14cade440 100644 --- a/app/assets/javascripts/image_diff/helpers/badge_helper.js +++ b/app/assets/javascripts/image_diff/helpers/badge_helper.js @@ -12,7 +12,7 @@ export function createImageBadge(noteId, { x, y }, classNames = []) { } export function addImageBadge(containerEl, { coordinate, badgeText, noteId }) { - const buttonEl = createImageBadge(noteId, coordinate, ['badge']); + const buttonEl = createImageBadge(noteId, coordinate, ['badge', 'badge-pill']); buttonEl.innerText = badgeText; containerEl.appendChild(buttonEl); diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 040d0bc659e6acea42b6a6fa63eec68b00b5d58e..9e22cdc04e9b128c1f33515bbda0ba89f1529cfa 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -192,8 +192,12 @@ export const contentTop = () => { const mrTabsHeight = $('.merge-request-tabs').height() || 0; const headerHeight = $('.navbar-gitlab').height() || 0; const diffFilesChanged = $('.js-diff-files-changed').height() || 0; + const diffFileLargeEnoughScreen = + 'matchMedia' in window ? window.matchMedia('min-width: 768') : true; + const diffFileTitleBar = + (diffFileLargeEnoughScreen && $('.diff-file .file-title-flex-parent:visible').height()) || 0; - return perfBar + mrTabsHeight + headerHeight + diffFilesChanged; + return perfBar + mrTabsHeight + headerHeight + diffFilesChanged + diffFileTitleBar; }; export const scrollToElement = element => { diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index 3618c6af7e2b86e5c3db7269ecaf7547629eb1b1..c095a017866c9d67c4c53cfdb4ee20bafbc7e6ea 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -39,7 +39,14 @@ function blockTagText(text, textArea, blockTag, selected) { } } -function moveCursor({ textArea, tag, positionBetweenTags, removedLastNewLine, select }) { +function moveCursor({ + textArea, + tag, + cursorOffset, + positionBetweenTags, + removedLastNewLine, + select, +}) { var pos; if (!textArea.setSelectionRange) { return; @@ -61,11 +68,24 @@ function moveCursor({ textArea, tag, positionBetweenTags, removedLastNewLine, se pos -= 1; } + if (cursorOffset) { + pos -= cursorOffset; + } + return textArea.setSelectionRange(pos, pos); } } -export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) { +export function insertMarkdownText({ + textArea, + text, + tag, + cursorOffset, + blockTag, + selected, + wrap, + select, +}) { var textToInsert, selectedSplit, startChar, @@ -154,20 +174,30 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr return moveCursor({ textArea, tag: tag.replace(textPlaceholder, selected), + cursorOffset, positionBetweenTags: wrap && selected.length === 0, removedLastNewLine, select, }); } -function updateText({ textArea, tag, blockTag, wrap, select }) { +function updateText({ textArea, tag, cursorOffset, blockTag, wrap, select, tagContent }) { var $textArea, selected, text; $textArea = $(textArea); textArea = $textArea.get(0); text = $textArea.val(); - selected = selectedText(text, textArea); + selected = selectedText(text, textArea) || tagContent; $textArea.focus(); - return insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }); + return insertMarkdownText({ + textArea, + text, + tag, + cursorOffset, + blockTag, + selected, + wrap, + select, + }); } export function addMarkdownListeners(form) { @@ -178,9 +208,11 @@ export function addMarkdownListeners(form) { return updateText({ textArea: $this.closest('.md-area').find('textarea'), tag: $this.data('mdTag'), + cursorOffset: $this.data('mdCursorOffset'), blockTag: $this.data('mdBlock'), wrap: !$this.data('mdPrepend'), select: $this.data('mdSelect'), + tagContent: $this.data('mdTagContent').toString(), }); }); } diff --git a/app/assets/javascripts/lib/utils/users_cache.js b/app/assets/javascripts/lib/utils/users_cache.js index c0d45e017b4683e7917d099c07eab95d37367984..9f980fd48998cd54610132562c1d8353d5941462 100644 --- a/app/assets/javascripts/lib/utils/users_cache.js +++ b/app/assets/javascripts/lib/utils/users_cache.js @@ -22,6 +22,34 @@ class UsersCache extends Cache { }); // missing catch is intentional, error handling depends on use case } + + retrieveById(userId) { + if (this.hasData(userId) && this.get(userId).username) { + return Promise.resolve(this.get(userId)); + } + + return Api.user(userId).then(({ data }) => { + this.internalStorage[userId] = data; + return data; + }); + // missing catch is intentional, error handling depends on use case + } + + retrieveStatusById(userId) { + if (this.hasData(userId) && this.get(userId).status) { + return Promise.resolve(this.get(userId).status); + } + + return Api.userStatus(userId).then(({ data }) => { + if (!this.hasData(userId)) { + this.internalStorage[userId] = {}; + } + this.internalStorage[userId].status = data; + + return data; + }); + // missing catch is intentional, error handling depends on use case + } } export default new UsersCache(); diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index a88b575ad99f9015c4f62d541f3b223874ceb3c2..c866e8d180ac1e34da1a2796b3e9c31cb2f2799b 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -30,6 +30,7 @@ import initUsagePingConsent from './usage_ping_consent'; import initPerformanceBar from './performance_bar'; import initSearchAutocomplete from './search_autocomplete'; import GlFieldErrors from './gl_field_errors'; +import initUserPopovers from './user_popovers'; // expose jQuery as global (TODO: remove these) window.jQuery = jQuery; @@ -78,6 +79,7 @@ document.addEventListener('DOMContentLoaded', () => { initTodoToggle(); initLogoAnimation(); initUsagePingConsent(); + initUserPopovers(); if (document.querySelector('.search')) initSearchAutocomplete(); if (document.querySelector('#js-peek')) initPerformanceBar({ container: '#js-peek' }); diff --git a/app/assets/javascripts/monitoring/components/charts/area.vue b/app/assets/javascripts/monitoring/components/charts/area.vue new file mode 100644 index 0000000000000000000000000000000000000000..12224e36ba2e5646ca2113a76ad92e6ea9bd89b9 --- /dev/null +++ b/app/assets/javascripts/monitoring/components/charts/area.vue @@ -0,0 +1,97 @@ + + + diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 218c508a608f0f2ddb61165f283a4f8f0b79357c..2d9c5050c9b4cc27ba07dfdc8ce20bb4699cf46f 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -4,6 +4,7 @@ import { s__ } from '~/locale'; import Icon from '~/vue_shared/components/icon.vue'; import Flash from '../../flash'; import MonitoringService from '../services/monitoring_service'; +import MonitorAreaChart from './charts/area.vue'; import GraphGroup from './graph_group.vue'; import Graph from './graph.vue'; import EmptyState from './empty_state.vue'; @@ -12,6 +13,7 @@ import eventHub from '../event_hub'; export default { components: { + MonitorAreaChart, Graph, GraphGroup, EmptyState, @@ -102,6 +104,9 @@ export default { }; }, computed: { + graphComponent() { + return gon.features && gon.features.areaChart ? MonitorAreaChart : Graph; + }, forceRedraw() { return this.elWidth; }, @@ -207,7 +212,8 @@ export default { :name="groupData.group" :show-panels="showPanels" > - {{ null }} - + +import { mapActions } from 'vuex'; import $ from 'jquery'; import noteEditedText from './note_edited_text.vue'; import noteAwardsList from './note_awards_list.vue'; import noteAttachment from './note_attachment.vue'; import noteForm from './note_form.vue'; import autosave from '../mixins/autosave'; +import Suggestions from '~/vue_shared/components/markdown/suggestions.vue'; export default { components: { @@ -12,6 +14,7 @@ export default { noteAwardsList, noteAttachment, noteForm, + Suggestions, }, mixins: [autosave], props: { @@ -19,6 +22,11 @@ export default { type: Object, required: true, }, + line: { + type: Object, + required: false, + default: null, + }, canEdit: { type: Boolean, required: true, @@ -28,11 +36,22 @@ export default { required: false, default: false, }, + helpPagePath: { + type: String, + required: false, + default: '', + }, }, computed: { noteBody() { return this.note.note; }, + hasSuggestion() { + return this.note.suggestions && this.note.suggestions.length; + }, + lineType() { + return this.line ? this.line.type : null; + }, }, mounted() { this.renderGFM(); @@ -53,6 +72,7 @@ export default { } }, methods: { + ...mapActions(['submitSuggestion']), renderGFM() { $(this.$refs['note-body']).renderGFM(); }, @@ -62,19 +82,35 @@ export default { formCancelHandler(shouldConfirm, isDirty) { this.$emit('cancelForm', shouldConfirm, isDirty); }, + applySuggestion({ suggestionId, flashContainer, callback }) { + const { discussion_id: discussionId, id: noteId } = this.note; + + this.submitSuggestion({ discussionId, noteId, suggestionId, flashContainer, callback }); + }, }, };