Commit 565fba25 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch 'ph/optimizeMRJSBundle' into 'master'

Improves merge request JS bundle

See merge request gitlab-org/gitlab!67967
parents 5d90d345 1bdfa789
...@@ -10,7 +10,6 @@ export default { ...@@ -10,7 +10,6 @@ export default {
}, },
computed: { computed: {
...mapGetters(['isNotesFetched']), ...mapGetters(['isNotesFetched']),
...mapGetters('batchComments', ['draftsCount']),
}, },
watch: { watch: {
isNotesFetched() { isNotesFetched() {
...@@ -25,7 +24,7 @@ export default { ...@@ -25,7 +24,7 @@ export default {
}; };
</script> </script>
<template> <template>
<div v-show="draftsCount > 0"> <div>
<nav class="review-bar-component" data-testid="review_bar_component"> <nav class="review-bar-component" data-testid="review_bar_component">
<div <div
class="review-bar-content d-flex gl-justify-content-end" class="review-bar-content d-flex gl-justify-content-end"
......
import Vue from 'vue'; import Vue from 'vue';
import { mapActions } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import store from '~/mr_notes/stores'; import store from '~/mr_notes/stores';
import ReviewBar from './components/review_bar.vue';
export const initReviewBar = () => { export const initReviewBar = () => {
const el = document.getElementById('js-review-bar'); const el = document.getElementById('js-review-bar');
...@@ -10,6 +9,12 @@ export const initReviewBar = () => { ...@@ -10,6 +9,12 @@ export const initReviewBar = () => {
new Vue({ new Vue({
el, el,
store, store,
components: {
ReviewBar: () => import('./components/review_bar.vue'),
},
computed: {
...mapGetters('batchComments', ['draftsCount']),
},
mounted() { mounted() {
this.fetchDrafts(); this.fetchDrafts();
}, },
...@@ -17,7 +22,9 @@ export const initReviewBar = () => { ...@@ -17,7 +22,9 @@ export const initReviewBar = () => {
...mapActions('batchComments', ['fetchDrafts']), ...mapActions('batchComments', ['fetchDrafts']),
}, },
render(createElement) { render(createElement) {
return createElement(ReviewBar); if (this.draftsCount === 0) return null;
return createElement('review-bar');
}, },
}); });
}; };
import Vue from 'vue'; import Vue from 'vue';
import { initPipelineCountListener } from './utils';
/** /**
* Used in: * Used in:
...@@ -12,13 +13,7 @@ export default () => { ...@@ -12,13 +13,7 @@ export default () => {
if (pipelineTableViewEl) { if (pipelineTableViewEl) {
// Update MR and Commits tabs // Update MR and Commits tabs
pipelineTableViewEl.addEventListener('update-pipelines-count', (event) => { initPipelineCountListener(pipelineTableViewEl);
if (event.detail.pipelineCount) {
const badge = document.querySelector('.js-pipelines-mr-count');
badge.textContent = event.detail.pipelineCount;
}
});
if (pipelineTableViewEl.dataset.disableInitialization === undefined) { if (pipelineTableViewEl.dataset.disableInitialization === undefined) {
const table = new Vue({ const table = new Vue({
......
export function initPipelineCountListener(el) {
if (!el) return;
el.addEventListener('update-pipelines-count', (event) => {
if (event.detail.pipelineCount) {
const badge = document.querySelector('.js-pipelines-mr-count');
badge.textContent = event.detail.pipelineCount;
}
});
}
...@@ -17,7 +17,6 @@ export default { ...@@ -17,7 +17,6 @@ export default {
}, },
mounted() { mounted() {
this.width = this.$el.parentNode.offsetWidth; this.width = this.$el.parentNode.offsetWidth;
window.test = this;
this.$_itemsWithSizeWatcher = this.$watch('vscrollParent.itemsWithSize', async () => { this.$_itemsWithSizeWatcher = this.$watch('vscrollParent.itemsWithSize', async () => {
await this.$nextTick(); await this.$nextTick();
......
...@@ -3,7 +3,6 @@ import Vue from 'vue'; ...@@ -3,7 +3,6 @@ import Vue from 'vue';
import { mapActions, mapState, mapGetters } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import { getParameterValues } from '~/lib/utils/url_utility'; import { getParameterValues } from '~/lib/utils/url_utility';
import FindFile from '~/vue_shared/components/file_finder/index.vue';
import eventHub from '../notes/event_hub'; import eventHub from '../notes/event_hub';
import diffsApp from './components/app.vue'; import diffsApp from './components/app.vue';
...@@ -12,51 +11,7 @@ import { getReviewsForMergeRequest } from './utils/file_reviews'; ...@@ -12,51 +11,7 @@ import { getReviewsForMergeRequest } from './utils/file_reviews';
import { getDerivedMergeRequestInformation } from './utils/merge_request'; import { getDerivedMergeRequestInformation } from './utils/merge_request';
export default function initDiffsApp(store) { export default function initDiffsApp(store) {
const fileFinderEl = document.getElementById('js-diff-file-finder'); const vm = new Vue({
if (fileFinderEl) {
// eslint-disable-next-line no-new
new Vue({
el: fileFinderEl,
store,
computed: {
...mapState('diffs', ['fileFinderVisible', 'isLoading']),
...mapGetters('diffs', ['flatBlobsList']),
},
watch: {
fileFinderVisible(newVal, oldVal) {
if (newVal && !oldVal && !this.flatBlobsList.length) {
eventHub.$emit('fetchDiffData');
}
},
},
methods: {
...mapActions('diffs', ['toggleFileFinder', 'scrollToFile']),
openFile(file) {
window.mrTabs.tabShown('diffs');
this.scrollToFile(file.path);
},
},
render(createElement) {
return createElement(FindFile, {
props: {
files: this.flatBlobsList,
visible: this.fileFinderVisible,
loading: this.isLoading,
showDiffStats: true,
clearSearchOnClose: false,
},
on: {
toggle: this.toggleFileFinder,
click: this.openFile,
},
class: ['diff-file-finder'],
});
},
});
}
return new Vue({
el: '#js-diffs-app', el: '#js-diffs-app',
name: 'MergeRequestDiffs', name: 'MergeRequestDiffs',
components: { components: {
...@@ -157,4 +112,53 @@ export default function initDiffsApp(store) { ...@@ -157,4 +112,53 @@ export default function initDiffsApp(store) {
}); });
}, },
}); });
const fileFinderEl = document.getElementById('js-diff-file-finder');
if (fileFinderEl) {
// eslint-disable-next-line no-new
new Vue({
el: fileFinderEl,
store,
components: {
FindFile: () => import('~/vue_shared/components/file_finder/index.vue'),
},
computed: {
...mapState('diffs', ['fileFinderVisible', 'isLoading']),
...mapGetters('diffs', ['flatBlobsList']),
},
watch: {
fileFinderVisible(newVal, oldVal) {
if (newVal && !oldVal && !this.flatBlobsList.length) {
eventHub.$emit('fetchDiffData');
}
},
},
methods: {
...mapActions('diffs', ['toggleFileFinder', 'scrollToFile']),
openFile(file) {
window.mrTabs.tabShown('diffs');
this.scrollToFile(file.path);
},
},
render(createElement) {
return createElement('find-file', {
props: {
files: this.flatBlobsList,
visible: this.fileFinderVisible,
loading: this.isLoading,
showDiffStats: true,
clearSearchOnClose: false,
},
on: {
toggle: this.toggleFileFinder,
click: this.openFile,
},
class: ['diff-file-finder'],
});
},
});
}
return vm;
} }
/* eslint-disable no-new */ /* eslint-disable no-new */
import { mountSidebarLabels, getSidebarOptions } from '~/sidebar/mount_sidebar'; import { getSidebarOptions } from '~/sidebar/mount_sidebar';
import IssuableContext from './issuable_context'; import IssuableContext from './issuable_context';
import LabelsSelect from './labels_select';
import MilestoneSelect from './milestone_select';
import Sidebar from './right_sidebar'; import Sidebar from './right_sidebar';
export default () => { export default () => {
...@@ -13,12 +11,6 @@ export default () => { ...@@ -13,12 +11,6 @@ export default () => {
const sidebarOptions = getSidebarOptions(sidebarOptEl); const sidebarOptions = getSidebarOptions(sidebarOptEl);
new MilestoneSelect({
full_path: sidebarOptions.fullPath,
});
new LabelsSelect();
new IssuableContext(sidebarOptions.currentUser); new IssuableContext(sidebarOptions.currentUser);
Sidebar.initialize(); Sidebar.initialize();
mountSidebarLabels();
}; };
...@@ -19,11 +19,9 @@ function MergeRequest(opts) { ...@@ -19,11 +19,9 @@ function MergeRequest(opts) {
this.opts = opts != null ? opts : {}; this.opts = opts != null ? opts : {};
this.submitNoteForm = this.submitNoteForm.bind(this); this.submitNoteForm = this.submitNoteForm.bind(this);
this.$el = $('.merge-request'); this.$el = $('.merge-request');
this.$('.show-all-commits').on('click', () => this.showAllCommits());
this.initTabs(); this.initTabs();
this.initMRBtnListeners(); this.initMRBtnListeners();
this.initCommitMessageListeners();
if ($('.description.js-task-list-container').length) { if ($('.description.js-task-list-container').length) {
this.taskList = new TaskList({ this.taskList = new TaskList({
...@@ -59,11 +57,6 @@ MergeRequest.prototype.initTabs = function () { ...@@ -59,11 +57,6 @@ MergeRequest.prototype.initTabs = function () {
window.mrTabs = new MergeRequestTabs(this.opts); window.mrTabs = new MergeRequestTabs(this.opts);
}; };
MergeRequest.prototype.showAllCommits = function () {
this.$('.first-commits').remove();
return this.$('.all-commits').removeClass('hide');
};
MergeRequest.prototype.initMRBtnListeners = function () { MergeRequest.prototype.initMRBtnListeners = function () {
const _this = this; const _this = this;
const draftToggles = document.querySelectorAll('.js-draft-toggle-button'); const draftToggles = document.querySelectorAll('.js-draft-toggle-button');
...@@ -128,26 +121,6 @@ MergeRequest.prototype.submitNoteForm = function (form, $button) { ...@@ -128,26 +121,6 @@ MergeRequest.prototype.submitNoteForm = function (form, $button) {
} }
}; };
MergeRequest.prototype.initCommitMessageListeners = function () {
$(document).on('click', 'a.js-with-description-link', (e) => {
const textarea = $('textarea.js-commit-message');
e.preventDefault();
textarea.val(textarea.data('messageWithDescription'));
$('.js-with-description-hint').hide();
$('.js-without-description-hint').show();
});
$(document).on('click', 'a.js-without-description-link', (e) => {
const textarea = $('textarea.js-commit-message');
e.preventDefault();
textarea.val(textarea.data('messageWithoutDescription'));
$('.js-with-description-hint').show();
$('.js-without-description-hint').hide();
});
};
MergeRequest.decreaseCounter = function (by = 1) { MergeRequest.decreaseCounter = function (by = 1) {
const $el = $('.js-merge-counter'); const $el = $('.js-merge-counter');
const count = Math.max(parseInt($el.text().replace(/[^\d]/, ''), 10) - by, 0); const count = Math.max(parseInt($el.text().replace(/[^\d]/, ''), 10) - by, 0);
......
...@@ -19,6 +19,7 @@ export default function initMrNotes() { ...@@ -19,6 +19,7 @@ export default function initMrNotes() {
action: mrShowNode.dataset.mrAction, action: mrShowNode.dataset.mrAction,
}); });
initDiffsApp(store);
initNotesApp(); initNotesApp();
document.addEventListener('merged:UpdateActions', () => { document.addEventListener('merged:UpdateActions', () => {
...@@ -26,9 +27,13 @@ export default function initMrNotes() { ...@@ -26,9 +27,13 @@ export default function initMrNotes() {
initCherryPickCommitModal(); initCherryPickCommitModal();
}); });
requestIdleCallback(() => {
const el = document.getElementById('js-vue-discussion-counter');
if (el) {
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
el: '#js-vue-discussion-counter', el,
name: 'DiscussionCounter', name: 'DiscussionCounter',
components: { components: {
discussionCounter, discussionCounter,
...@@ -38,8 +43,9 @@ export default function initMrNotes() { ...@@ -38,8 +43,9 @@ export default function initMrNotes() {
return createElement('discussion-counter'); return createElement('discussion-counter');
}, },
}); });
}
initDiscussionFilters(store); initDiscussionFilters(store);
initSortDiscussions(store); initSortDiscussions(store);
initDiffsApp(store); });
} }
import { store } from '~/notes/stores';
import initRelatedIssues from '~/related_issues'; import initRelatedIssues from '~/related_issues';
import initSidebarBundle from '~/sidebar/sidebar_bundle'; import initSidebarBundle from '~/sidebar/sidebar_bundle';
import initShow from '../show'; import initShow from '../show';
initShow(); initShow();
initSidebarBundle(); initSidebarBundle(store);
initRelatedIssues(); initRelatedIssues();
...@@ -2,11 +2,10 @@ import Vue from 'vue'; ...@@ -2,11 +2,10 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import loadAwardsHandler from '~/awards_handler'; import loadAwardsHandler from '~/awards_handler';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable'; import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import initPipelines from '~/commit/pipelines/pipelines_bundle'; import { initPipelineCountListener } from '~/commit/pipelines/utils';
import initIssuableSidebar from '~/init_issuable_sidebar'; import initIssuableSidebar from '~/init_issuable_sidebar';
import StatusBox from '~/issuable/components/status_box.vue'; import StatusBox from '~/issuable/components/status_box.vue';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import { handleLocationHash } from '~/lib/utils/common_utils';
import initSourcegraph from '~/sourcegraph'; import initSourcegraph from '~/sourcegraph';
import ZenMode from '~/zen_mode'; import ZenMode from '~/zen_mode';
import getStateQuery from './queries/get_state.query.graphql'; import getStateQuery from './queries/get_state.query.graphql';
...@@ -15,11 +14,10 @@ export default function initMergeRequestShow() { ...@@ -15,11 +14,10 @@ export default function initMergeRequestShow() {
const awardEmojiEl = document.getElementById('js-vue-awards-block'); const awardEmojiEl = document.getElementById('js-vue-awards-block');
new ZenMode(); // eslint-disable-line no-new new ZenMode(); // eslint-disable-line no-new
initIssuableSidebar(); initPipelineCountListener(document.querySelector('#commit-pipeline-table-view'));
initPipelines();
new ShortcutsIssuable(true); // eslint-disable-line no-new new ShortcutsIssuable(true); // eslint-disable-line no-new
handleLocationHash();
initSourcegraph(); initSourcegraph();
initIssuableSidebar();
if (awardEmojiEl) { if (awardEmojiEl) {
import('~/emoji/awards_app') import('~/emoji/awards_app')
.then((m) => m.default(awardEmojiEl)) .then((m) => m.default(awardEmojiEl))
......
...@@ -5,8 +5,11 @@ import initSidebarBundle from '~/sidebar/sidebar_bundle'; ...@@ -5,8 +5,11 @@ import initSidebarBundle from '~/sidebar/sidebar_bundle';
import initIssuableHeaderWarning from '~/vue_shared/components/issuable/init_issuable_header_warning'; import initIssuableHeaderWarning from '~/vue_shared/components/issuable/init_issuable_header_warning';
import initShow from '../init_merge_request_show'; import initShow from '../init_merge_request_show';
initShow();
initSidebarBundle();
initMrNotes(); initMrNotes();
initReviewBar(); initShow();
initIssuableHeaderWarning(store);
requestIdleCallback(() => {
initSidebarBundle(store);
initReviewBar();
initIssuableHeaderWarning(store);
});
import { memoize } from 'lodash'; import { memoize } from 'lodash';
import { createNodeDict } from '../utils';
import { createSankey } from './dag/drawing_utils'; import { createSankey } from './dag/drawing_utils';
/*
The following functions are the main engine in transforming the data as
received from the endpoint into the format the d3 graph expects.
Input is of the form:
[nodes]
nodes: [{category, name, jobs, size}]
category is the stage name
name is a group name; in the case that the group has one job, it is
also the job name
size is the number of parallel jobs
jobs: [{ name, needs}]
job name is either the same as the group name or group x/y
needs: [job-names]
needs is an array of job-name strings
Output is of the form:
{ nodes: [node], links: [link] }
node: { name, category }, + unused info passed through
link: { source, target, value }, with source & target being node names
and value being a constant
We create nodes in the GraphQL update function, and then here we create the node dictionary,
then create links, and then dedupe the links, so that in the case where
job 4 depends on job 1 and job 2, and job 2 depends on job 1, we show only a single link
from job 1 to job 2 then another from job 2 to job 4.
CREATE LINKS
nodes.name -> target
nodes.name.needs.each -> source (source is the name of the group, not the parallel job)
10 -> value (constant)
*/
export const createNodeDict = (nodes) => {
return nodes.reduce((acc, node) => {
const newNode = {
...node,
needs: node.jobs.map((job) => job.needs || []).flat(),
};
if (node.size > 1) {
node.jobs.forEach((job) => {
acc[job.name] = newNode;
});
}
acc[node.name] = newNode;
return acc;
}, {});
};
/* /*
A peformant alternative to lodash's isEqual. Because findIndex always finds A peformant alternative to lodash's isEqual. Because findIndex always finds
the first instance of a match, if the found index is not the first, we know the first instance of a match, if the found index is not the first, we know
......
import * as Sentry from '@sentry/browser'; import * as Sentry from '@sentry/browser';
import { pickBy } from 'lodash'; import { pickBy } from 'lodash';
import { createNodeDict } from './components/parsing_utils';
import { SUPPORTED_FILTER_PARAMETERS } from './constants'; import { SUPPORTED_FILTER_PARAMETERS } from './constants';
/*
The following functions are the main engine in transforming the data as
received from the endpoint into the format the d3 graph expects.
Input is of the form:
[nodes]
nodes: [{category, name, jobs, size}]
category is the stage name
name is a group name; in the case that the group has one job, it is
also the job name
size is the number of parallel jobs
jobs: [{ name, needs}]
job name is either the same as the group name or group x/y
needs: [job-names]
needs is an array of job-name strings
Output is of the form:
{ nodes: [node], links: [link] }
node: { name, category }, + unused info passed through
link: { source, target, value }, with source & target being node names
and value being a constant
We create nodes in the GraphQL update function, and then here we create the node dictionary,
then create links, and then dedupe the links, so that in the case where
job 4 depends on job 1 and job 2, and job 2 depends on job 1, we show only a single link
from job 1 to job 2 then another from job 2 to job 4.
CREATE LINKS
nodes.name -> target
nodes.name.needs.each -> source (source is the name of the group, not the parallel job)
10 -> value (constant)
*/
export const createNodeDict = (nodes) => {
return nodes.reduce((acc, node) => {
const newNode = {
...node,
needs: node.jobs.map((job) => job.needs || []).flat(),
};
if (node.size > 1) {
node.jobs.forEach((job) => {
acc[job.name] = newNode;
});
}
acc[node.name] = newNode;
return acc;
}, {});
};
export const validateParams = (params) => { export const validateParams = (params) => {
return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val); return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val);
}; };
......
import IssueStatusIcon from '~/reports/components/issue_status_icon.vue'; import IssueStatusIcon from '~/reports/components/issue_status_icon.vue';
import AccessibilityIssueBody from '../accessibility_report/components/accessibility_issue_body.vue';
import CodequalityIssueBody from '../codequality_report/components/codequality_issue_body.vue';
import TestIssueBody from '../grouped_test_report/components/test_issue_body.vue';
export const components = { export const components = {
AccessibilityIssueBody, AccessibilityIssueBody: () =>
CodequalityIssueBody, import('../accessibility_report/components/accessibility_issue_body.vue'),
TestIssueBody, CodequalityIssueBody: () => import('../codequality_report/components/codequality_issue_body.vue'),
TestIssueBody: () => import('../grouped_test_report/components/test_issue_body.vue'),
}; };
export const componentNames = { export const componentNames = {
AccessibilityIssueBody: AccessibilityIssueBody.name, AccessibilityIssueBody: 'AccessibilityIssueBody',
CodequalityIssueBody: CodequalityIssueBody.name, CodequalityIssueBody: 'CodequalityIssueBody',
TestIssueBody: TestIssueBody.name, TestIssueBody: 'TestIssueBody',
}; };
export const iconComponents = { export const iconComponents = {
......
import $ from 'jquery'; import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createFlash from '~/flash';
import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants'; import { TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
import initInviteMembersModal from '~/invite_members/init_invite_members_modal'; import initInviteMembersModal from '~/invite_members/init_invite_members_modal';
...@@ -13,7 +12,6 @@ import { ...@@ -13,7 +12,6 @@ import {
isInIncidentPage, isInIncidentPage,
parseBoolean, parseBoolean,
} from '~/lib/utils/common_utils'; } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assignee_list.vue'; import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assignee_list.vue';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue'; import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue'; import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
...@@ -363,10 +361,10 @@ function mountReferenceComponent() { ...@@ -363,10 +361,10 @@ function mountReferenceComponent() {
}); });
} }
function mountLockComponent() { function mountLockComponent(store) {
const el = document.getElementById('js-lock-entry-point'); const el = document.getElementById('js-lock-entry-point');
if (!el) { if (!el || !store) {
return; return;
} }
...@@ -375,20 +373,7 @@ function mountLockComponent() { ...@@ -375,20 +373,7 @@ function mountLockComponent() {
const dataNode = document.getElementById('js-lock-issue-data'); const dataNode = document.getElementById('js-lock-issue-data');
const initialData = JSON.parse(dataNode.innerHTML); const initialData = JSON.parse(dataNode.innerHTML);
let importStore; // eslint-disable-next-line no-new
if (isInIssuePage() || isInIncidentPage()) {
importStore = import(/* webpackChunkName: 'notesStore' */ '~/notes/stores').then(
({ store }) => store,
);
} else {
importStore = import(/* webpackChunkName: 'mrNotesStore' */ '~/mr_notes/stores').then(
(store) => store.default,
);
}
importStore
.then(
(store) =>
new Vue({ new Vue({
el, el,
store, store,
...@@ -401,10 +386,6 @@ function mountLockComponent() { ...@@ -401,10 +386,6 @@ function mountLockComponent() {
isEditable: initialData.is_editable, isEditable: initialData.is_editable,
}, },
}), }),
}),
)
.catch(() => {
createFlash({ message: __('Failed to load sidebar lock status') });
}); });
} }
...@@ -537,7 +518,7 @@ function mountCopyEmailComponent() { ...@@ -537,7 +518,7 @@ function mountCopyEmailComponent() {
const isAssigneesWidgetShown = const isAssigneesWidgetShown =
(isInIssuePage() || isInDesignPage()) && gon.features.issueAssigneesWidget; (isInIssuePage() || isInDesignPage()) && gon.features.issueAssigneesWidget;
export function mountSidebar(mediator) { export function mountSidebar(mediator, store) {
initInviteMembersModal(); initInviteMembersModal();
initInviteMembersTrigger(); initInviteMembersTrigger();
...@@ -548,11 +529,12 @@ export function mountSidebar(mediator) { ...@@ -548,11 +529,12 @@ export function mountSidebar(mediator) {
mountAssigneesComponentDeprecated(mediator); mountAssigneesComponentDeprecated(mediator);
} }
mountReviewersComponent(mediator); mountReviewersComponent(mediator);
mountSidebarLabels();
mountMilestoneSelect(); mountMilestoneSelect();
mountConfidentialComponent(mediator); mountConfidentialComponent(mediator);
mountDueDateComponent(mediator); mountDueDateComponent(mediator);
mountReferenceComponent(mediator); mountReferenceComponent(mediator);
mountLockComponent(); mountLockComponent(store);
mountParticipantsComponent(); mountParticipantsComponent();
mountSubscriptionsComponent(); mountSubscriptionsComponent();
mountCopyEmailComponent(); mountCopyEmailComponent();
......
import { mountSidebar, getSidebarOptions } from './mount_sidebar'; import { mountSidebar, getSidebarOptions } from 'ee_else_ce/sidebar/mount_sidebar';
import Mediator from './sidebar_mediator'; import Mediator from './sidebar_mediator';
export default () => { export default (store) => {
const mediator = new Mediator(getSidebarOptions()); const mediator = new Mediator(getSidebarOptions());
mediator.fetch(); mediator.fetch();
mountSidebar(mediator); mountSidebar(mediator, store);
}; };
...@@ -7,8 +7,6 @@ import VueApollo from 'vue-apollo'; ...@@ -7,8 +7,6 @@ import VueApollo from 'vue-apollo';
import MrWidgetOptions from 'ee_else_ce/vue_merge_request_widget/mr_widget_options.vue'; import MrWidgetOptions from 'ee_else_ce/vue_merge_request_widget/mr_widget_options.vue';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import Translate from '../vue_shared/translate'; import Translate from '../vue_shared/translate';
import { registerExtension } from './components/extensions';
import issueExtension from './extensions/issues';
Vue.use(Translate); Vue.use(Translate);
Vue.use(VueApollo); Vue.use(VueApollo);
...@@ -28,8 +26,6 @@ export default () => { ...@@ -28,8 +26,6 @@ export default () => {
gl.mrWidgetData.gitlabLogo = gon.gitlab_logo; gl.mrWidgetData.gitlabLogo = gon.gitlab_logo;
gl.mrWidgetData.defaultAvatarUrl = gon.default_avatar_url; gl.mrWidgetData.defaultAvatarUrl = gon.default_avatar_url;
registerExtension(issueExtension);
const vm = new Vue({ const vm = new Vue({
el: '#js-vue-mr-widget', el: '#js-vue-mr-widget',
provide: { provide: {
......
...@@ -12,9 +12,6 @@ import { sprintf, s__, __ } from '~/locale'; ...@@ -12,9 +12,6 @@ import { sprintf, s__, __ } from '~/locale';
import Project from '~/pages/projects/project'; import Project from '~/pages/projects/project';
import SmartInterval from '~/smart_interval'; import SmartInterval from '~/smart_interval';
import { setFaviconOverlay } from '../lib/utils/favicon'; import { setFaviconOverlay } from '../lib/utils/favicon';
import GroupedAccessibilityReportsApp from '../reports/accessibility_report/grouped_accessibility_reports_app.vue';
import GroupedCodequalityReportsApp from '../reports/codequality_report/grouped_codequality_reports_app.vue';
import GroupedTestReportsApp from '../reports/grouped_test_report/grouped_test_reports_app.vue';
import Loading from './components/loading.vue'; import Loading from './components/loading.vue';
import MrWidgetAlertMessage from './components/mr_widget_alert_message.vue'; import MrWidgetAlertMessage from './components/mr_widget_alert_message.vue';
import WidgetHeader from './components/mr_widget_header.vue'; import WidgetHeader from './components/mr_widget_header.vue';
...@@ -42,7 +39,6 @@ import ShaMismatch from './components/states/sha_mismatch.vue'; ...@@ -42,7 +39,6 @@ import ShaMismatch from './components/states/sha_mismatch.vue';
import UnresolvedDiscussionsState from './components/states/unresolved_discussions.vue'; import UnresolvedDiscussionsState from './components/states/unresolved_discussions.vue';
import WorkInProgressState from './components/states/work_in_progress.vue'; import WorkInProgressState from './components/states/work_in_progress.vue';
// import ExtensionsContainer from './components/extensions/container'; // import ExtensionsContainer from './components/extensions/container';
import TerraformPlan from './components/terraform/mr_widget_terraform_container.vue';
import eventHub from './event_hub'; import eventHub from './event_hub';
import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variables'; import mergeRequestQueryVariablesMixin from './mixins/merge_request_query_variables';
import getStateQuery from './queries/get_state.query.graphql'; import getStateQuery from './queries/get_state.query.graphql';
...@@ -84,10 +80,13 @@ export default { ...@@ -84,10 +80,13 @@ export default {
'mr-widget-auto-merge-failed': AutoMergeFailed, 'mr-widget-auto-merge-failed': AutoMergeFailed,
'mr-widget-rebase': RebaseState, 'mr-widget-rebase': RebaseState,
SourceBranchRemovalStatus, SourceBranchRemovalStatus,
GroupedCodequalityReportsApp, GroupedCodequalityReportsApp: () =>
GroupedTestReportsApp, import('../reports/codequality_report/grouped_codequality_reports_app.vue'),
TerraformPlan, GroupedTestReportsApp: () =>
GroupedAccessibilityReportsApp, import('../reports/grouped_test_report/grouped_test_reports_app.vue'),
TerraformPlan: () => import('./components/terraform/mr_widget_terraform_container.vue'),
GroupedAccessibilityReportsApp: () =>
import('../reports/accessibility_report/grouped_accessibility_reports_app.vue'),
MrWidgetApprovals, MrWidgetApprovals,
SecurityReportsApp: () => import('~/vue_shared/security_reports/security_reports_app.vue'), SecurityReportsApp: () => import('~/vue_shared/security_reports/security_reports_app.vue'),
}, },
......
import initRelatedFeatureFlags from 'ee/related_feature_flags'; import initRelatedFeatureFlags from 'ee/related_feature_flags';
import initSidebarBundle from 'ee/sidebar/sidebar_bundle'; import { store } from '~/notes/stores';
import initShow from '~/pages/projects/issues/show'; import initShow from '~/pages/projects/issues/show';
import initRelatedIssues from '~/related_issues'; import initRelatedIssues from '~/related_issues';
import initSidebarBundle from '~/sidebar/sidebar_bundle';
import UserCallout from '~/user_callout'; import UserCallout from '~/user_callout';
initShow(); initShow();
initSidebarBundle(); initSidebarBundle(store);
initRelatedIssues(); initRelatedIssues();
initRelatedFeatureFlags(); initRelatedFeatureFlags();
......
import initSidebarBundle from 'ee/sidebar/sidebar_bundle';
import initMergeConflicts from '~/merge_conflicts/merge_conflicts_bundle'; import initMergeConflicts from '~/merge_conflicts/merge_conflicts_bundle';
import initSidebarBundle from '~/sidebar/sidebar_bundle';
initSidebarBundle(); initSidebarBundle();
initMergeConflicts(); initMergeConflicts();
import initSidebarBundle from 'ee/sidebar/sidebar_bundle';
import { initReviewBar } from '~/batch_comments';
import initMrNotes from '~/mr_notes';
import store from '~/mr_notes/stores';
import initShow from '~/pages/projects/merge_requests/init_merge_request_show';
import initIssuableHeaderWarning from '~/vue_shared/components/issuable/init_issuable_header_warning';
initShow();
initSidebarBundle();
initMrNotes();
initReviewBar();
initIssuableHeaderWarning(store);
import BlockingMergeRequestsBody from 'ee/vue_merge_request_widget/components/blocking_merge_requests/blocking_merge_request_body.vue';
import PerformanceIssueBody from 'ee/vue_merge_request_widget/components/performance_issue_body.vue';
import StatusCheckIssueBody from 'ee/vue_merge_request_widget/components/status_check_issue_body.vue';
import LicenseIssueBody from 'ee/vue_shared/license_compliance/components/license_issue_body.vue';
import LicenseStatusIcon from 'ee/vue_shared/license_compliance/components/license_status_icon.vue'; import LicenseStatusIcon from 'ee/vue_shared/license_compliance/components/license_status_icon.vue';
import MetricsReportsIssueBody from 'ee/vue_shared/metrics_reports/components/metrics_reports_issue_body.vue';
import SecurityIssueBody from 'ee/vue_shared/security_reports/components/security_issue_body.vue';
import { import {
components as componentsCE, components as componentsCE,
componentNames as componentNamesCE, componentNames as componentNamesCE,
...@@ -14,22 +8,30 @@ import { ...@@ -14,22 +8,30 @@ import {
export const components = { export const components = {
...componentsCE, ...componentsCE,
StatusCheckIssueBody, StatusCheckIssueBody: () =>
PerformanceIssueBody, import('ee/vue_merge_request_widget/components/status_check_issue_body.vue'),
LicenseIssueBody, PerformanceIssueBody: () =>
SecurityIssueBody, import('ee/vue_merge_request_widget/components/performance_issue_body.vue'),
MetricsReportsIssueBody, LicenseIssueBody: () =>
BlockingMergeRequestsBody, import('ee/vue_shared/license_compliance/components/license_issue_body.vue'),
SecurityIssueBody: () =>
import('ee/vue_shared/security_reports/components/security_issue_body.vue'),
MetricsReportsIssueBody: () =>
import('ee/vue_shared/metrics_reports/components/metrics_reports_issue_body.vue'),
BlockingMergeRequestsBody: () =>
import(
'ee/vue_merge_request_widget/components/blocking_merge_requests/blocking_merge_request_body.vue'
),
}; };
export const componentNames = { export const componentNames = {
...componentNamesCE, ...componentNamesCE,
StatusCheckIssueBody: StatusCheckIssueBody.name, StatusCheckIssueBody: 'StatusCheckIssueBody',
PerformanceIssueBody: PerformanceIssueBody.name, PerformanceIssueBody: 'PerformanceIssueBody',
LicenseIssueBody: LicenseIssueBody.name, LicenseIssueBody: 'LicenseIssueBody',
SecurityIssueBody: SecurityIssueBody.name, SecurityIssueBody: 'SecurityIssueBody',
MetricsReportsIssueBody: MetricsReportsIssueBody.name, MetricsReportsIssueBody: 'MetricsReportsIssueBody',
BlockingMergeRequestsBody: BlockingMergeRequestsBody.name, BlockingMergeRequestsBody: 'BlockingMergeRequestsBody',
}; };
export const iconComponents = { export const iconComponents = {
......
...@@ -2,7 +2,6 @@ import Vue from 'vue'; ...@@ -2,7 +2,6 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { IssuableType } from '~/issue_show/constants'; import { IssuableType } from '~/issue_show/constants';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import { store } from '~/notes/stores';
import { apolloProvider } from '~/sidebar/graphql'; import { apolloProvider } from '~/sidebar/graphql';
import * as CEMountSidebar from '~/sidebar/mount_sidebar'; import * as CEMountSidebar from '~/sidebar/mount_sidebar';
import CveIdRequest from './components/cve_id_request/cve_id_request_sidebar.vue'; import CveIdRequest from './components/cve_id_request/cve_id_request_sidebar.vue';
...@@ -42,7 +41,7 @@ const mountWeightComponent = () => { ...@@ -42,7 +41,7 @@ const mountWeightComponent = () => {
}); });
}; };
const mountStatusComponent = () => { const mountStatusComponent = (store) => {
const el = document.querySelector('.js-sidebar-status-entry-point'); const el = document.querySelector('.js-sidebar-status-entry-point');
if (!el) { if (!el) {
...@@ -70,7 +69,7 @@ const mountStatusComponent = () => { ...@@ -70,7 +69,7 @@ const mountStatusComponent = () => {
}); });
}; };
function mountCveIdRequestComponent() { function mountCveIdRequestComponent(store) {
const el = document.getElementById('js-sidebar-cve-id-request-entry-point'); const el = document.getElementById('js-sidebar-cve-id-request-entry-point');
if (!el) { if (!el) {
...@@ -153,14 +152,16 @@ function mountIterationSelect() { ...@@ -153,14 +152,16 @@ function mountIterationSelect() {
}); });
} }
export default function mountSidebar(mediator) { export const { getSidebarOptions } = CEMountSidebar;
CEMountSidebar.mountSidebar(mediator);
export function mountSidebar(mediator, store) {
CEMountSidebar.mountSidebar(mediator, store);
mountWeightComponent(); mountWeightComponent();
mountStatusComponent(mediator); mountStatusComponent(store);
mountEpicsSelect(); mountEpicsSelect();
mountIterationSelect(); mountIterationSelect();
if (gon.features.cveIdRequestButton) { if (gon.features.cveIdRequestButton) {
mountCveIdRequestComponent(); mountCveIdRequestComponent(store);
} }
} }
import { getSidebarOptions } from '~/sidebar/mount_sidebar';
import mountSidebar from './mount_sidebar';
import Mediator from './sidebar_mediator';
export default () => {
const sidebarOptEl = document.querySelector('.js-sidebar-options');
if (!sidebarOptEl) return;
const mediator = new Mediator(getSidebarOptions(sidebarOptEl));
mediator.fetch();
mountSidebar(mediator);
};
<script> <script>
import { GlSafeHtmlDirective } from '@gitlab/ui'; import { GlSafeHtmlDirective } from '@gitlab/ui';
import GroupedBrowserPerformanceReportsApp from 'ee/reports/browser_performance_report/grouped_browser_performance_reports_app.vue';
import { componentNames } from 'ee/reports/components/issue_body';
import GroupedLoadPerformanceReportsApp from 'ee/reports/load_performance_report/grouped_load_performance_reports_app.vue';
import StatusChecksReportsApp from 'ee/reports/status_checks_report/status_checks_reports_app.vue';
import MrWidgetLicenses from 'ee/vue_shared/license_compliance/mr_widget_license_report.vue'; import MrWidgetLicenses from 'ee/vue_shared/license_compliance/mr_widget_license_report.vue';
import GroupedMetricsReportsApp from 'ee/vue_shared/metrics_reports/grouped_metrics_reports_app.vue';
import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin'; import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin';
import { s__, __, sprintf } from '~/locale'; import { s__, __, sprintf } from '~/locale';
import ReportSection from '~/reports/components/report_section.vue';
import CEWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue'; import CEWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
import BlockingMergeRequestsReport from './components/blocking_merge_requests/blocking_merge_requests_report.vue';
import MrWidgetJiraAssociationMissing from './components/states/mr_widget_jira_association_missing.vue'; import MrWidgetJiraAssociationMissing from './components/states/mr_widget_jira_association_missing.vue';
import MrWidgetPolicyViolation from './components/states/mr_widget_policy_violation.vue'; import MrWidgetPolicyViolation from './components/states/mr_widget_policy_violation.vue';
import MrWidgetGeoSecondaryNode from './components/states/mr_widget_secondary_geo_node.vue'; import MrWidgetGeoSecondaryNode from './components/states/mr_widget_secondary_geo_node.vue';
...@@ -21,21 +14,25 @@ export default { ...@@ -21,21 +14,25 @@ export default {
MrWidgetGeoSecondaryNode, MrWidgetGeoSecondaryNode,
MrWidgetPolicyViolation, MrWidgetPolicyViolation,
MrWidgetJiraAssociationMissing, MrWidgetJiraAssociationMissing,
StatusChecksReportsApp, StatusChecksReportsApp: () =>
BlockingMergeRequestsReport, import('ee/reports/status_checks_report/status_checks_reports_app.vue'),
BlockingMergeRequestsReport: () =>
import('./components/blocking_merge_requests/blocking_merge_requests_report.vue'),
GroupedSecurityReportsApp: () => GroupedSecurityReportsApp: () =>
import('ee/vue_shared/security_reports/grouped_security_reports_app.vue'), import('ee/vue_shared/security_reports/grouped_security_reports_app.vue'),
GroupedMetricsReportsApp, GroupedMetricsReportsApp: () =>
GroupedBrowserPerformanceReportsApp, import('ee/vue_shared/metrics_reports/grouped_metrics_reports_app.vue'),
GroupedLoadPerformanceReportsApp, GroupedBrowserPerformanceReportsApp: () =>
ReportSection, import('ee/reports/browser_performance_report/grouped_browser_performance_reports_app.vue'),
GroupedLoadPerformanceReportsApp: () =>
import('ee/reports/load_performance_report/grouped_load_performance_reports_app.vue'),
ReportSection: () => import('~/reports/components/report_section.vue'),
}, },
directives: { directives: {
SafeHtml: GlSafeHtmlDirective, SafeHtml: GlSafeHtmlDirective,
}, },
extends: CEWidgetOptions, extends: CEWidgetOptions,
mixins: [reportsMixin], mixins: [reportsMixin],
componentNames,
data() { data() {
return { return {
isLoadingBrowserPerformance: false, isLoadingBrowserPerformance: false,
......
...@@ -2,6 +2,13 @@ import { mount } from '@vue/test-utils'; ...@@ -2,6 +2,13 @@ import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue'; import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
// Force Jest to transpile and cache
// eslint-disable-next-line no-unused-vars
import _GroupedBrowserPerformanceReportsApp from 'ee/reports/browser_performance_report/grouped_browser_performance_reports_app.vue';
// eslint-disable-next-line no-unused-vars
import _GroupedLoadPerformanceReportsApp from 'ee/reports/load_performance_report/grouped_load_performance_reports_app.vue';
import StatusChecksReportsApp from 'ee/reports/status_checks_report/status_checks_reports_app.vue'; import StatusChecksReportsApp from 'ee/reports/status_checks_report/status_checks_reports_app.vue';
import PerformanceIssueBody from 'ee/vue_merge_request_widget/components/performance_issue_body.vue'; import PerformanceIssueBody from 'ee/vue_merge_request_widget/components/performance_issue_body.vue';
import MrWidgetOptions from 'ee/vue_merge_request_widget/mr_widget_options.vue'; import MrWidgetOptions from 'ee/vue_merge_request_widget/mr_widget_options.vue';
...@@ -96,7 +103,6 @@ describe('ee merge request widget options', () => { ...@@ -96,7 +103,6 @@ describe('ee merge request widget options', () => {
}); });
const findBrowserPerformanceWidget = () => wrapper.find('.js-browser-performance-widget'); const findBrowserPerformanceWidget = () => wrapper.find('.js-browser-performance-widget');
const findLoadPerformanceWidget = () => wrapper.find('.js-load-performance-widget');
const findExtendedSecurityWidget = () => wrapper.find('.js-security-widget'); const findExtendedSecurityWidget = () => wrapper.find('.js-security-widget');
const findBaseSecurityWidget = () => wrapper.find('[data-testid="security-mr-widget"]'); const findBaseSecurityWidget = () => wrapper.find('[data-testid="security-mr-widget"]');
const findStatusChecksReport = () => wrapper.findComponent(StatusChecksReportsApp); const findStatusChecksReport = () => wrapper.findComponent(StatusChecksReportsApp);
...@@ -336,29 +342,13 @@ describe('ee merge request widget options', () => { ...@@ -336,29 +342,13 @@ describe('ee merge request widget options', () => {
}; };
}); });
describe('when it is loading', () => {
it('should render loading indicator', (done) => {
mock.onGet('head.json').reply(200, headBrowserPerformance);
mock.onGet('base.json').reply(200, baseBrowserPerformance);
createComponent({ propsData: { mrData: gl.mrWidgetData } });
wrapper.vm.mr.browserPerformance = { ...DEFAULT_BROWSER_PERFORMANCE };
nextTick(() => {
expect(trimText(findBrowserPerformanceWidget().text())).toContain(
'Loading browser-performance report',
);
done();
});
});
});
describe('with successful request', () => { describe('with successful request', () => {
beforeEach(() => { beforeEach(async () => {
mock.onGet(DEFAULT_BROWSER_PERFORMANCE.head_path).reply(200, headBrowserPerformance); mock.onGet(DEFAULT_BROWSER_PERFORMANCE.head_path).reply(200, headBrowserPerformance);
mock.onGet(DEFAULT_BROWSER_PERFORMANCE.base_path).reply(200, baseBrowserPerformance); mock.onGet(DEFAULT_BROWSER_PERFORMANCE.base_path).reply(200, baseBrowserPerformance);
createComponent({ propsData: { mrData: gl.mrWidgetData } }); createComponent({ propsData: { mrData: gl.mrWidgetData } });
await waitForPromises();
}); });
describe('default', () => { describe('default', () => {
...@@ -500,29 +490,13 @@ describe('ee merge request widget options', () => { ...@@ -500,29 +490,13 @@ describe('ee merge request widget options', () => {
}; };
}); });
describe('when it is loading', () => {
it('should render loading indicator', (done) => {
mock.onGet(DEFAULT_LOAD_PERFORMANCE.head_path).reply(200, headLoadPerformance);
mock.onGet(DEFAULT_LOAD_PERFORMANCE.base_path).reply(200, baseLoadPerformance);
createComponent({ propsData: { mrData: gl.mrWidgetData } });
wrapper.vm.mr.loadPerformance = { ...DEFAULT_LOAD_PERFORMANCE };
nextTick(() => {
expect(trimText(findLoadPerformanceWidget().text())).toContain(
'Loading load-performance report',
);
done();
});
});
});
describe('with successful request', () => { describe('with successful request', () => {
beforeEach(() => { beforeEach(async () => {
mock.onGet(DEFAULT_LOAD_PERFORMANCE.head_path).reply(200, headLoadPerformance); mock.onGet(DEFAULT_LOAD_PERFORMANCE.head_path).reply(200, headLoadPerformance);
mock.onGet(DEFAULT_LOAD_PERFORMANCE.base_path).reply(200, baseLoadPerformance); mock.onGet(DEFAULT_LOAD_PERFORMANCE.base_path).reply(200, baseLoadPerformance);
createComponent({ propsData: { mrData: gl.mrWidgetData } }); createComponent({ propsData: { mrData: gl.mrWidgetData } });
await waitForPromises();
}); });
describe('default', () => { describe('default', () => {
......
import { mount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import { componentNames } from 'ee/reports/components/issue_body'; import { componentNames } from 'ee/reports/components/issue_body';
import SecurityIssueBody from 'ee/vue_shared/security_reports/components/security_issue_body.vue';
import store from 'ee/vue_shared/security_reports/store'; import store from 'ee/vue_shared/security_reports/store';
import { codequalityParsedIssues } from 'ee_jest/vue_mr_widget/mock_data'; import { codequalityParsedIssues } from 'ee_jest/vue_mr_widget/mock_data';
import { import {
...@@ -14,6 +16,7 @@ import { STATUS_FAILED, STATUS_SUCCESS } from '~/reports/constants'; ...@@ -14,6 +16,7 @@ import { STATUS_FAILED, STATUS_SUCCESS } from '~/reports/constants';
describe('Report issues', () => { describe('Report issues', () => {
let vm; let vm;
let wrapper;
let ReportIssues; let ReportIssues;
beforeEach(() => { beforeEach(() => {
...@@ -21,7 +24,9 @@ describe('Report issues', () => { ...@@ -21,7 +24,9 @@ describe('Report issues', () => {
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); if (vm?.$destroy) vm.$destroy();
if (wrapper) wrapper.destroy();
}); });
describe('for codequality issues', () => { describe('for codequality issues', () => {
...@@ -59,14 +64,19 @@ describe('Report issues', () => { ...@@ -59,14 +64,19 @@ describe('Report issues', () => {
describe('with location', () => { describe('with location', () => {
it('should render location', () => { it('should render location', () => {
vm = mountComponent(ReportIssues, { vm = mount(ReportIssues, {
propsData: {
issue: sastParsedIssues[0], issue: sastParsedIssues[0],
component: componentNames.SecurityIssueBody, component: componentNames.SecurityIssueBody,
status: STATUS_FAILED, status: STATUS_FAILED,
},
stubs: {
SecurityIssueBody,
},
}); });
expect(vm.$el.textContent).toContain('in'); expect(vm.text()).toContain('in');
expect(vm.$el.querySelector('.report-block-list-issue a').getAttribute('href')).toEqual( expect(vm.find('.report-block-list-issue a').attributes('href')).toEqual(
sastParsedIssues[0].urlPath, sastParsedIssues[0].urlPath,
); );
}); });
......
import { shallowMount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import { componentNames, iconComponentNames } from 'ee/reports/components/issue_body'; import { componentNames, iconComponentNames } from 'ee/reports/components/issue_body';
import LicenseIssueBody from 'ee/vue_shared/license_compliance/components/license_issue_body.vue'; import LicenseIssueBody from 'ee/vue_shared/license_compliance/components/license_issue_body.vue';
import LicenseStatusIcon from 'ee/vue_shared/license_compliance/components/license_status_icon.vue'; import LicenseStatusIcon from 'ee/vue_shared/license_compliance/components/license_status_icon.vue';
import SecurityIssueBody from 'ee/vue_shared/security_reports/components/security_issue_body.vue';
import store from 'ee/vue_shared/security_reports/store'; import store from 'ee/vue_shared/security_reports/store';
import { codequalityParsedIssues } from 'ee_jest/vue_mr_widget/mock_data'; import { codequalityParsedIssues } from 'ee_jest/vue_mr_widget/mock_data';
import { import {
...@@ -26,7 +27,9 @@ describe('Report issue', () => { ...@@ -26,7 +27,9 @@ describe('Report issue', () => {
}); });
afterEach(() => { afterEach(() => {
vm.$destroy(); if (vm?.$destroy) vm.$destroy();
if (wrapper) wrapper.destroy();
}); });
describe('for codequality issue', () => { describe('for codequality issue', () => {
...@@ -64,31 +67,39 @@ describe('Report issue', () => { ...@@ -64,31 +67,39 @@ describe('Report issue', () => {
describe('with location', () => { describe('with location', () => {
it('should render location', () => { it('should render location', () => {
vm = mountComponent(ReportIssue, { vm = mount(ReportIssue, {
propsData: {
issue: sastParsedIssues[0], issue: sastParsedIssues[0],
component: componentNames.SecurityIssueBody, component: componentNames.SecurityIssueBody,
status: STATUS_FAILED, status: STATUS_FAILED,
},
stubs: {
SecurityIssueBody,
},
}); });
expect(vm.$el.textContent).toContain('in'); expect(vm.text()).toContain('in');
expect(vm.$el.querySelector('li a').getAttribute('href')).toEqual( expect(vm.find('li a').attributes('href')).toEqual(sastParsedIssues[0].urlPath);
sastParsedIssues[0].urlPath,
);
}); });
}); });
describe('without location', () => { describe('without location', () => {
it('should not render location', () => { it('should not render location', () => {
vm = mountComponent(ReportIssue, { vm = mount(ReportIssue, {
propsData: {
issue: { issue: {
title: 'foo', title: 'foo',
}, },
component: componentNames.SecurityIssueBody, component: componentNames.SecurityIssueBody,
status: STATUS_SUCCESS, status: STATUS_SUCCESS,
},
stubs: {
SecurityIssueBody,
},
}); });
expect(vm.$el.textContent).not.toContain('in'); expect(vm.text()).not.toContain('in');
expect(vm.$el.querySelector('a')).toEqual(null); expect(vm.find('a').exists()).toBe(false);
}); });
}); });
...@@ -156,13 +167,17 @@ describe('Report issue', () => { ...@@ -156,13 +167,17 @@ describe('Report issue', () => {
describe('for license compliance issue', () => { describe('for license compliance issue', () => {
it('renders LicenseIssueBody & LicenseStatusIcon', () => { it('renders LicenseIssueBody & LicenseStatusIcon', () => {
wrapper = shallowMount(ReportIssue, { wrapper = mount(ReportIssue, {
propsData: { propsData: {
issue: licenseComplianceParsedIssues[0], issue: licenseComplianceParsedIssues[0],
component: componentNames.LicenseIssueBody, component: componentNames.LicenseIssueBody,
iconComponent: iconComponentNames.LicenseStatusIcon, iconComponent: iconComponentNames.LicenseStatusIcon,
status: STATUS_NEUTRAL, status: STATUS_NEUTRAL,
}, },
stubs: {
LicenseIssueBody,
LicenseStatusIcon,
},
}); });
expect(wrapper.findComponent(LicenseIssueBody).exists()).toBe(true); expect(wrapper.findComponent(LicenseIssueBody).exists()).toBe(true);
......
...@@ -13938,9 +13938,6 @@ msgstr "" ...@@ -13938,9 +13938,6 @@ msgstr ""
msgid "Failed to load related branches" msgid "Failed to load related branches"
msgstr "" msgstr ""
msgid "Failed to load sidebar lock status"
msgstr ""
msgid "Failed to load stacktrace." msgid "Failed to load stacktrace."
msgstr "" msgstr ""
......
...@@ -25,10 +25,6 @@ RSpec.describe 'Merge request > Batch comments', :js do ...@@ -25,10 +25,6 @@ RSpec.describe 'Merge request > Batch comments', :js do
visit_diffs visit_diffs
end end
it 'has review bar' do
expect(page).to have_selector('[data-testid="review_bar_component"]', visible: false)
end
it 'adds draft note' do it 'adds draft note' do
write_diff_comment write_diff_comment
......
import { createSankey } from '~/pipelines/components/dag/drawing_utils'; import { createSankey } from '~/pipelines/components/dag/drawing_utils';
import { import {
createNodeDict,
makeLinksFromNodes, makeLinksFromNodes,
filterByAncestors, filterByAncestors,
generateColumnsFromLayersListBare, generateColumnsFromLayersListBare,
...@@ -9,6 +8,7 @@ import { ...@@ -9,6 +8,7 @@ import {
removeOrphanNodes, removeOrphanNodes,
getMaxNodes, getMaxNodes,
} from '~/pipelines/components/parsing_utils'; } from '~/pipelines/components/parsing_utils';
import { createNodeDict } from '~/pipelines/utils';
import { mockParsedGraphQLNodes, missingJob } from './components/dag/mock_data'; import { mockParsedGraphQLNodes, missingJob } from './components/dag/mock_data';
import { generateResponse, mockPipelineResponse } from './graph/mock_data'; import { generateResponse, mockPipelineResponse } from './graph/mock_data';
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment