Commit c55bbe06 authored by Stan Hu's avatar Stan Hu

Merge branch 'master' into ce-to-ee-2018-02-26

parents ae1b6ea6 90488d20
<script> <script>
import Sortable from 'vendor/Sortable'; import Sortable from 'vendor/Sortable';
import boardNewIssue from './board_new_issue'; import boardNewIssue from './board_new_issue.vue';
import boardCard from './board_card.vue'; import boardCard from './board_card.vue';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue';
......
/* global ListIssue */ <script>
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import ProjectSelect from './project_select.vue'; import ProjectSelect from 'ee/boards/components/project_select.vue'; // eslint-disable-line import/first
import ListIssue from '../models/issue';
const Store = gl.issueBoards.BoardsStore; const Store = gl.issueBoards.BoardsStore;
export default { export default {
name: 'BoardNewIssue', name: 'BoardNewIssue',
components: {
ProjectSelect,
},
props: { props: {
groupId: { groupId: {
type: Number, type: Number,
...@@ -24,9 +28,6 @@ export default { ...@@ -24,9 +28,6 @@ export default {
selectedProject: {}, selectedProject: {},
}; };
}, },
components: {
'project-select': ProjectSelect,
},
computed: { computed: {
disabled() { disabled() {
if (this.groupId) { if (this.groupId) {
...@@ -35,6 +36,10 @@ export default { ...@@ -35,6 +36,10 @@ export default {
return this.title === ''; return this.title === '';
}, },
}, },
mounted() {
this.$refs.input.focus();
eventHub.$on('setSelectedProject', this.setSelectedProject);
},
methods: { methods: {
submit(e) { submit(e) {
e.preventDefault(); e.preventDefault();
...@@ -81,49 +86,57 @@ export default { ...@@ -81,49 +86,57 @@ export default {
this.selectedProject = selectedProject; this.selectedProject = selectedProject;
}, },
}, },
mounted() { };
this.$refs.input.focus(); </script>
eventHub.$on('setSelectedProject', this.setSelectedProject);
}, <template>
template: ` <div class="board-new-issue-form">
<div class="board-new-issue-form"> <div class="card">
<div class="card"> <form @submit="submit($event)">
<form @submit="submit($event)"> <div
<div class="flash-container" class="flash-container"
v-if="error"> v-if="error"
<div class="flash-alert"> >
An error occurred. Please try again. <div class="flash-alert">
</div> An error occurred. Please try again.
</div>
<label class="label-light"
:for="list.id + '-title'">
Title
</label>
<input class="form-control"
type="text"
v-model="title"
ref="input"
autocomplete="off"
:id="list.id + '-title'" />
<project-select
v-if="groupId"
:groupId="groupId"
/>
<div class="clearfix prepend-top-10">
<button class="btn btn-success pull-left"
type="submit"
:disabled="disabled"
ref="submit-button">
Submit issue
</button>
<button class="btn btn-default pull-right"
type="button"
@click="cancel">
Cancel
</button>
</div> </div>
</form> </div>
</div> <label
class="label-light"
:for="list.id + '-title'"
>
Title
</label>
<input
class="form-control"
type="text"
v-model="title"
ref="input"
autocomplete="off"
:id="list.id + '-title'"
/>
<project-select
v-if="groupId"
:group-id="groupId"
/>
<div class="clearfix prepend-top-10">
<button
class="btn btn-success pull-left"
type="submit"
:disabled="disabled"
ref="submit-button"
>
Submit issue
</button>
<button
class="btn btn-default pull-right"
type="button"
@click="cancel"
>
Cancel
</button>
</div>
</form>
</div> </div>
`, </div>
}; </template>
...@@ -2,16 +2,17 @@ ...@@ -2,16 +2,17 @@
import _ from 'underscore'; import _ from 'underscore';
import Vue from 'vue'; import Vue from 'vue';
import Flash from '../flash';
import { __ } from '../locale'; import Flash from '~/flash';
import { __ } from '~/locale';
import FilteredSearchBoards from './filtered_search_boards'; import FilteredSearchBoards from './filtered_search_boards';
import eventHub from './eventhub'; import eventHub from './eventhub';
import sidebarEventHub from '../sidebar/event_hub'; import sidebarEventHub from '~/sidebar/event_hub'; // eslint-disable-line import/first
import './models/issue'; import './models/issue';
import './models/label'; import './models/label';
import './models/list'; import './models/list';
import './models/milestone'; import './models/milestone';
import './models/project';
import './models/assignee'; import './models/assignee';
import './stores/boards_store'; import './stores/boards_store';
import './stores/modal_store'; import './stores/modal_store';
...@@ -23,16 +24,15 @@ import './components/board'; ...@@ -23,16 +24,15 @@ import './components/board';
import './components/board_sidebar'; import './components/board_sidebar';
import './components/new_list_dropdown'; import './components/new_list_dropdown';
import './components/modal/index'; import './components/modal/index';
import '../vue_shared/vue_resource_interceptor'; import '~/vue_shared/vue_resource_interceptor'; // eslint-disable-line import/first
import 'ee/boards/models/project'; // eslint-disable-line import/first
import 'ee/boards/components/boards_selector'; // eslint-disable-line import/first
import collapseIcon from 'ee/boards/icons/fullscreen_collapse.svg'; // eslint-disable-line import/first
import expandIcon from 'ee/boards/icons/fullscreen_expand.svg'; // eslint-disable-line import/first
import tooltip from '~/vue_shared/directives/tooltip'; // eslint-disable-line import/first
<<<<<<< HEAD:app/assets/javascripts/boards/index.js
import './components/boards_selector';
import collapseIcon from './icons/fullscreen_collapse.svg';
import expandIcon from './icons/fullscreen_expand.svg';
import tooltip from '../vue_shared/directives/tooltip';
=======
>>>>>>> upstream/master:app/assets/javascripts/boards/index.js
export default () => { export default () => {
const $boardApp = document.getElementById('board-app'); const $boardApp = document.getElementById('board-app');
const Store = gl.issueBoards.BoardsStore; const Store = gl.issueBoards.BoardsStore;
......
/* eslint-disable no-unused-vars, no-mixed-operators, comma-dangle */ /* eslint-disable no-unused-vars, no-mixed-operators, comma-dangle */
/* global DocumentTouch */ /* global DocumentTouch */
import sortableConfig from '../../sortable/sortable_config'; import sortableConfig from 'ee/sortable/sortable_config';
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {}; window.gl.issueBoards = window.gl.issueBoards || {};
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* global ListAssignee */ /* global ListAssignee */
import Vue from 'vue'; import Vue from 'vue';
import IssueProject from './project'; import IssueProject from 'ee/boards/models/project';
class ListIssue { class ListIssue {
constructor (obj, defaultAvatar) { constructor (obj, defaultAvatar) {
...@@ -122,3 +122,5 @@ class ListIssue { ...@@ -122,3 +122,5 @@ class ListIssue {
} }
window.ListIssue = ListIssue; window.ListIssue = ListIssue;
export default ListIssue;
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import _ from 'underscore'; import _ from 'underscore';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import boardsStoreEE from 'ee/boards/stores/boards_store_ee'; import boardsStoreEE from 'ee/boards/stores/boards_store_ee';
import { getUrlParamsArray } from '../../lib/utils/common_utils'; import { getUrlParamsArray } from '~/lib/utils/common_utils';
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {}; window.gl.issueBoards = window.gl.issueBoards || {};
......
...@@ -6,177 +6,80 @@ import GlFieldErrors from './gl_field_errors'; ...@@ -6,177 +6,80 @@ import GlFieldErrors from './gl_field_errors';
import Shortcuts from './shortcuts'; import Shortcuts from './shortcuts';
import SearchAutocomplete from './search_autocomplete'; import SearchAutocomplete from './search_autocomplete';
var Dispatcher; function initSearch() {
// Only when search form is present
(function() { if ($('.search').length) {
Dispatcher = (function() { return new SearchAutocomplete();
function Dispatcher() { }
this.initSearch(); }
this.initFieldErrors();
this.initPageScripts();
}
Dispatcher.prototype.initPageScripts = function() {
var path, shortcut_handler;
const page = $('body').attr('data-page');
if (!page) {
return false;
}
const fail = () => Flash('Error loading dynamic module');
const callDefault = m => m.default();
path = page.split(':');
shortcut_handler = null;
$('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
gfm.setup($(el), {
emojis: true,
members: enableGFM,
issues: enableGFM,
milestones: enableGFM,
mergeRequests: enableGFM,
labels: enableGFM,
});
});
const shortcutHandlerPages = [
'projects:activity',
'projects:artifacts:browse',
'projects:artifacts:file',
'projects:blame:show',
'projects:blob:show',
'projects:commit:show',
'projects:commits:show',
'projects:find_file:show',
'projects:issues:edit',
'projects:issues:index',
'projects:issues:new',
'projects:issues:show',
'projects:merge_requests:creations:diffs',
'projects:merge_requests:creations:new',
'projects:merge_requests:edit',
'projects:merge_requests:index',
'projects:merge_requests:show',
'projects:network:show',
'projects:show',
'projects:tree:show',
'groups:show',
];
if (shortcutHandlerPages.indexOf(page) !== -1) { function initFieldErrors() {
shortcut_handler = true; $('.gl-show-field-errors').each((i, form) => {
} new GlFieldErrors(form);
});
}
switch (path[0]) { function initPageShortcuts(page) {
case 'admin': const pagesWithCustomShortcuts = [
switch (path[1]) { 'projects:activity',
case 'broadcast_messages': 'projects:artifacts:browse',
import('./pages/admin/broadcast_messages') 'projects:artifacts:file',
.then(callDefault) 'projects:blame:show',
.catch(fail); 'projects:blob:show',
break; 'projects:commit:show',
case 'cohorts': 'projects:commits:show',
import('./pages/admin/cohorts') 'projects:find_file:show',
.then(callDefault) 'projects:issues:edit',
.catch(fail); 'projects:issues:index',
break; 'projects:issues:new',
case 'groups': 'projects:issues:show',
switch (path[2]) { 'projects:merge_requests:creations:diffs',
case 'show': 'projects:merge_requests:creations:new',
import('./pages/admin/groups/show') 'projects:merge_requests:edit',
.then(callDefault) 'projects:merge_requests:index',
.catch(fail); 'projects:merge_requests:show',
break; 'projects:network:show',
} 'projects:show',
break; 'projects:tree:show',
case 'projects': 'groups:show',
import('./pages/admin/projects') ];
.then(callDefault)
.catch(fail);
break;
case 'labels':
switch (path[2]) {
case 'new':
import('./pages/admin/labels/new')
.then(callDefault)
.catch(fail);
break;
case 'edit':
import('./pages/admin/labels/edit')
.then(callDefault)
.catch(fail);
break;
}
case 'abuse_reports':
import('./pages/admin/abuse_reports')
.then(callDefault)
.catch(fail);
break;
}
break;
case 'profiles':
import('./pages/profiles/index')
.then(callDefault)
.catch(fail);
break;
case 'projects':
import('./pages/projects')
.then(callDefault)
.catch(fail);
shortcut_handler = true;
switch (path[1]) {
case 'compare':
import('./pages/projects/compare')
.then(callDefault)
.catch(fail);
break;
case 'create':
case 'new':
import('./pages/projects/new')
.then(callDefault)
.catch(fail);
break;
case 'wikis':
import('./pages/projects/wikis')
.then(callDefault)
.catch(fail);
shortcut_handler = true;
break;
}
break;
}
// If we haven't installed a custom shortcut handler, install the default one
if (!shortcut_handler) {
new Shortcuts();
}
if (document.querySelector('#peek')) { if (pagesWithCustomShortcuts.indexOf(page) === -1) {
import('./performance_bar') new Shortcuts();
.then(m => new m.default({ container: '#peek' })) // eslint-disable-line new-cap }
.catch(fail); }
}
};
Dispatcher.prototype.initSearch = function() { function initGFMInput() {
// Only when search form is present $('.js-gfm-input:not(.js-vue-textarea)').each((i, el) => {
if ($('.search').length) { const gfm = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
return new SearchAutocomplete(); const enableGFM = convertPermissionToBoolean(el.dataset.supportsAutocomplete);
} gfm.setup($(el), {
}; emojis: true,
members: enableGFM,
issues: enableGFM,
milestones: enableGFM,
mergeRequests: enableGFM,
labels: enableGFM,
});
});
}
Dispatcher.prototype.initFieldErrors = function() { function initPerformanceBar() {
$('.gl-show-field-errors').each((i, form) => { if (document.querySelector('#peek')) {
new GlFieldErrors(form); import('./performance_bar')
}); .then(m => new m.default({ container: '#peek' })) // eslint-disable-line new-cap
}; .catch(() => Flash('Error loading performance bar module'));
}
}
return Dispatcher; export default () => {
})(); initSearch();
})(); initFieldErrors();
export default function initDispatcher() { const page = $('body').attr('data-page');
return new Dispatcher(); if (page) {
} initPageShortcuts(page);
initGFMInput();
initPerformanceBar();
}
};
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
/** /**
* Render environments table. * Render environments table.
*/ */
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import environmentItem from './environment_item.vue'; import environmentItem from './environment_item.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import deployBoard from './deploy_board_component.vue'; import deployBoard from 'ee/environments/components/deploy_board_component.vue'; // eslint-disable-line import/first
export default { export default {
components: { components: {
......
<script> <script>
import { mapState } from 'vuex'; import { mapState } from 'vuex';
import timeAgoMixin from '../../vue_shared/mixins/timeago';
import skeletonLoadingContainer from '../../vue_shared/components/skeleton_loading_container.vue'; import timeAgoMixin from '~/vue_shared/mixins/timeago';
import fileStatusIcon from './repo_file_status_icon.vue'; import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import fileIcon from '~/vue_shared/components/file_icon.vue';
import newDropdown from './new_dropdown/index.vue'; import newDropdown from './new_dropdown/index.vue';
import fileIcon from '../../vue_shared/components/file_icon.vue';
import changedFileIcon from './changed_file_icon.vue'; import fileStatusIcon from 'ee/ide/components/repo_file_status_icon.vue'; // eslint-disable-line import/first
import changedFileIcon from 'ee/ide/components/changed_file_icon.vue'; // eslint-disable-line import/first
export default { export default {
components: { components: {
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import fileStatusIcon from './repo_file_status_icon.vue';
import fileIcon from '../../vue_shared/components/file_icon.vue'; import fileIcon from '~/vue_shared/components/file_icon.vue';
import icon from '../../vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import changedFileIcon from './changed_file_icon.vue';
import fileStatusIcon from 'ee/ide/components/repo_file_status_icon.vue';
import changedFileIcon from 'ee/ide/components/changed_file_icon.vue';
export default { export default {
components: { components: {
......
...@@ -5,7 +5,7 @@ import Disposable from './common/disposable'; ...@@ -5,7 +5,7 @@ import Disposable from './common/disposable';
import ModelManager from './common/model_manager'; import ModelManager from './common/model_manager';
import editorOptions from './editor_options'; import editorOptions from './editor_options';
import gitlabTheme from './themes/gl_theme'; import gitlabTheme from 'ee/ide/lib/themes/gl_theme'; // eslint-disable-line import/first
export default class Editor { export default class Editor {
static create(monaco) { static create(monaco) {
......
import AbuseReports from './abuse_reports'; import AbuseReports from './abuse_reports';
export default () => new AbuseReports(); document.addEventListener('DOMContentLoaded', () => new AbuseReports());
...@@ -3,7 +3,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -3,7 +3,7 @@ import axios from '~/lib/utils/axios_utils';
import flash from '~/flash'; import flash from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
export default function initBroadcastMessagesForm() { export default () => {
$('input#broadcast_message_color').on('input', function onMessageColorInput() { $('input#broadcast_message_color').on('input', function onMessageColorInput() {
const previewColor = $(this).val(); const previewColor = $(this).val();
$('div.broadcast-message-preview').css('background-color', previewColor); $('div.broadcast-message-preview').css('background-color', previewColor);
...@@ -32,4 +32,4 @@ export default function initBroadcastMessagesForm() { ...@@ -32,4 +32,4 @@ export default function initBroadcastMessagesForm() {
.catch(() => flash(__('An error occurred while rendering preview broadcast message'))); .catch(() => flash(__('An error occurred while rendering preview broadcast message')));
} }
}, 250)); }, 250));
} };
import initBroadcastMessagesForm from './broadcast_message'; import initBroadcastMessagesForm from './broadcast_message';
export default () => initBroadcastMessagesForm(); document.addEventListener('DOMContentLoaded', initBroadcastMessagesForm);
import initUsagePing from './usage_ping'; import initUsagePing from './usage_ping';
export default () => initUsagePing(); document.addEventListener('DOMContentLoaded', initUsagePing);
import UsersSelect from '../../../../users_select'; import UsersSelect from '../../../../users_select';
export default () => new UsersSelect(); document.addEventListener('DOMContentLoaded', () => new UsersSelect());
import Labels from '../../../../labels'; import Labels from '../../../../labels';
export default () => new Labels(); document.addEventListener('DOMContentLoaded', () => new Labels());
import Labels from '../../../../labels'; import Labels from '../../../../labels';
export default () => new Labels(); document.addEventListener('DOMContentLoaded', () => new Labels());
import ProjectsList from '../../../projects_list'; import ProjectsList from '../../../projects_list';
import NamespaceSelect from '../../../namespace_select'; import NamespaceSelect from '../../../namespace_select';
export default () => { document.addEventListener('DOMContentLoaded', () => {
new ProjectsList(); // eslint-disable-line no-new new ProjectsList(); // eslint-disable-line no-new
document.querySelectorAll('.js-namespace-select') document.querySelectorAll('.js-namespace-select')
.forEach(dropdown => new NamespaceSelect({ dropdown })); .forEach(dropdown => new NamespaceSelect({ dropdown }));
}; });
import NotificationsForm from '../../../notifications_form'; import NotificationsForm from '../../../notifications_form';
import notificationsDropdown from '../../../notifications_dropdown'; import notificationsDropdown from '../../../notifications_dropdown';
export default () => { document.addEventListener('DOMContentLoaded', () => {
new NotificationsForm(); // eslint-disable-line no-new new NotificationsForm(); // eslint-disable-line no-new
notificationsDropdown(); notificationsDropdown();
}; });
import initCompareAutocomplete from '~/compare_autocomplete'; import initCompareAutocomplete from '~/compare_autocomplete';
export default () => { document.addEventListener('DOMContentLoaded', initCompareAutocomplete);
initCompareAutocomplete();
};
import Project from './project'; import Project from './project';
import ShortcutsNavigation from '../../shortcuts_navigation'; import ShortcutsNavigation from '../../shortcuts_navigation';
export default () => { document.addEventListener('DOMContentLoaded', () => {
new Project(); // eslint-disable-line no-new new Project(); // eslint-disable-line no-new
new ShortcutsNavigation(); // eslint-disable-line no-new new ShortcutsNavigation(); // eslint-disable-line no-new
}; });
...@@ -2,8 +2,8 @@ import ProjectNew from '../shared/project_new'; ...@@ -2,8 +2,8 @@ import ProjectNew from '../shared/project_new';
import initProjectVisibilitySelector from '../../../project_visibility'; import initProjectVisibilitySelector from '../../../project_visibility';
import initProjectNew from '../../../projects/project_new'; import initProjectNew from '../../../projects/project_new';
export default () => { document.addEventListener('DOMContentLoaded', () => {
new ProjectNew(); // eslint-disable-line no-new new ProjectNew(); // eslint-disable-line no-new
initProjectVisibilitySelector(); initProjectVisibilitySelector();
initProjectNew.bindEvents(); initProjectNew.bindEvents();
}; });
...@@ -3,9 +3,9 @@ import ShortcutsWiki from '../../../shortcuts_wiki'; ...@@ -3,9 +3,9 @@ import ShortcutsWiki from '../../../shortcuts_wiki';
import ZenMode from '../../../zen_mode'; import ZenMode from '../../../zen_mode';
import GLForm from '../../../gl_form'; import GLForm from '../../../gl_form';
export default () => { document.addEventListener('DOMContentLoaded', () => {
new Wikis(); // eslint-disable-line no-new new Wikis(); // eslint-disable-line no-new
new ShortcutsWiki(); // eslint-disable-line no-new new ShortcutsWiki(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new new ZenMode(); // eslint-disable-line no-new
new GLForm($('.wiki-form'), true); // eslint-disable-line no-new new GLForm($('.wiki-form'), true); // eslint-disable-line no-new
}; });
<script> <script>
import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import linkedPipelinesColumn from './linked_pipelines_column.vue';
import stageColumnComponent from './stage_column_component.vue'; import stageColumnComponent from './stage_column_component.vue';
import linkedPipelinesColumn from 'ee/pipelines/components/graph/linked_pipelines_column.vue'; // eslint-disable-line import/first
export default { export default {
components: { components: {
linkedPipelinesColumn, linkedPipelinesColumn,
......
<script> <script>
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
import pipelineStage from '../../pipelines/components/stage.vue'; import pipelineStage from '~/pipelines/components/stage.vue';
import ciIcon from '../../vue_shared/components/ci_icon.vue'; import ciIcon from '~/vue_shared/components/ci_icon.vue';
import icon from '../../vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import linkedPipelinesMiniList from '../../vue_shared/components/linked_pipelines_mini_list.vue'; import linkedPipelinesMiniList from 'ee/vue_shared/components/linked_pipelines_mini_list.vue';
export default { export default {
name: 'MRWidgetPipeline', name: 'MRWidgetPipeline',
......
...@@ -39,7 +39,7 @@ class LabelsFinder < UnionFinder ...@@ -39,7 +39,7 @@ class LabelsFinder < UnionFinder
end end
end end
elsif only_group_labels? elsif only_group_labels?
label_ids << Label.where(group_id: group.id) label_ids << Label.where(group_id: group_ids)
else else
label_ids << Label.where(group_id: projects.group_ids) label_ids << Label.where(group_id: projects.group_ids)
label_ids << Label.where(project_id: projects.select(:id)) label_ids << Label.where(project_id: projects.select(:id))
...@@ -59,10 +59,11 @@ class LabelsFinder < UnionFinder ...@@ -59,10 +59,11 @@ class LabelsFinder < UnionFinder
items.where(title: title) items.where(title: title)
end end
def group def group_ids
strong_memoize(:group) do strong_memoize(:group_ids) do
group = Group.find(params[:group_id]) group = Group.find(params[:group_id])
authorized_to_read_labels?(group) && group groups = params[:include_ancestor_groups].present? ? group.self_and_ancestors : [group]
groups_user_can_read_labels(groups).map(&:id)
end end
end end
...@@ -120,4 +121,10 @@ class LabelsFinder < UnionFinder ...@@ -120,4 +121,10 @@ class LabelsFinder < UnionFinder
Ability.allowed?(current_user, :read_label, label_parent) Ability.allowed?(current_user, :read_label, label_parent)
end end
def groups_user_can_read_labels(groups)
DeclarativePolicy.user_scope do
groups.select { |group| authorized_to_read_labels?(group) }
end
end
end end
...@@ -79,8 +79,12 @@ class IssuableBaseService < BaseService ...@@ -79,8 +79,12 @@ class IssuableBaseService < BaseService
return unless labels return unless labels
params[:label_ids] = labels.split(",").map do |label_name| params[:label_ids] = labels.split(",").map do |label_name|
service = Labels::FindOrCreateService.new(current_user, project, title: label_name.strip) label = Labels::FindOrCreateService.new(
label = service.execute current_user,
parent,
title: label_name.strip,
available_labels: available_labels
).execute
label.try(:id) label.try(:id)
end.compact end.compact
...@@ -104,7 +108,7 @@ class IssuableBaseService < BaseService ...@@ -104,7 +108,7 @@ class IssuableBaseService < BaseService
end end
def available_labels def available_labels
LabelsFinder.new(current_user, project_id: @project.id).execute @available_labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute
end end
def merge_quick_actions_into_params!(issuable) def merge_quick_actions_into_params!(issuable)
...@@ -305,4 +309,8 @@ class IssuableBaseService < BaseService ...@@ -305,4 +309,8 @@ class IssuableBaseService < BaseService
def update_project_counter_caches?(issuable) def update_project_counter_caches?(issuable)
issuable.state_changed? issuable.state_changed?
end end
def parent
project
end
end end
module Labels module Labels
class FindOrCreateService class FindOrCreateService
def initialize(current_user, project, params = {}) def initialize(current_user, parent, params = {})
@current_user = current_user @current_user = current_user
@project = project @parent = parent
@available_labels = params.delete(:available_labels)
@params = params.dup.with_indifferent_access @params = params.dup.with_indifferent_access
end end
...@@ -13,12 +14,13 @@ module Labels ...@@ -13,12 +14,13 @@ module Labels
private private
attr_reader :current_user, :project, :params, :skip_authorization attr_reader :current_user, :parent, :params, :skip_authorization
def available_labels def available_labels
@available_labels ||= LabelsFinder.new( @available_labels ||= LabelsFinder.new(
current_user, current_user,
project_id: project.id "#{parent_type}_id".to_sym => parent.id,
only_group_labels: parent_is_group?
).execute(skip_authorization: skip_authorization) ).execute(skip_authorization: skip_authorization)
end end
...@@ -27,8 +29,8 @@ module Labels ...@@ -27,8 +29,8 @@ module Labels
def find_or_create_label def find_or_create_label
new_label = available_labels.find_by(title: title) new_label = available_labels.find_by(title: title)
if new_label.nil? && (skip_authorization || Ability.allowed?(current_user, :admin_label, project)) if new_label.nil? && (skip_authorization || Ability.allowed?(current_user, :admin_label, parent))
new_label = Labels::CreateService.new(params).execute(project: project) new_label = Labels::CreateService.new(params).execute(parent_type.to_sym => parent)
end end
new_label new_label
...@@ -37,5 +39,13 @@ module Labels ...@@ -37,5 +39,13 @@ module Labels
def title def title
params[:title] || params[:name] params[:title] || params[:name]
end end
def parent_type
parent.model_name.param_key
end
def parent_is_group?
parent_type == "group"
end
end end
end end
...@@ -27,6 +27,3 @@ ...@@ -27,6 +27,3 @@
- unless can?(current_user, :push_code, @project) - unless can?(current_user, :push_code, @project)
.inline.prepend-left-10 .inline.prepend-left-10
= commit_in_fork_help = commit_in_fork_help
- content_for :page_specific_javascripts do
= webpack_bundle_tag('blob')
...@@ -25,16 +25,10 @@ var NO_COMPRESSION = process.env.NO_COMPRESSION; ...@@ -25,16 +25,10 @@ var NO_COMPRESSION = process.env.NO_COMPRESSION;
var autoEntries = {}; var autoEntries = {};
var pageEntries = glob.sync('pages/**/index.js', { cwd: path.join(ROOT_PATH, 'app/assets/javascripts') }); var pageEntries = glob.sync('pages/**/index.js', { cwd: path.join(ROOT_PATH, 'app/assets/javascripts') });
// filter out entries currently imported dynamically in dispatcher.js
var dispatcher = fs.readFileSync(path.join(ROOT_PATH, 'app/assets/javascripts/dispatcher.js')).toString();
var dispatcherChunks = dispatcher.match(/(?!import\(')\.\/pages\/[^']+/g);
function generateAutoEntries(path, prefix = '.') { function generateAutoEntries(path, prefix = '.') {
const chunkPath = path.replace(/\/index\.js$/, ''); const chunkPath = path.replace(/\/index\.js$/, '');
if (!dispatcherChunks.includes(`${prefix}/${chunkPath}`)) { const chunkName = chunkPath.replace(/\//g, '.');
const chunkName = chunkPath.replace(/\//g, '.'); autoEntries[chunkName] = `${prefix}/${path}`;
autoEntries[chunkName] = `${prefix}/${path}`;
}
} }
pageEntries.forEach(( path ) => generateAutoEntries(path)); pageEntries.forEach(( path ) => generateAutoEntries(path));
...@@ -98,19 +92,19 @@ var config = { ...@@ -98,19 +92,19 @@ var config = {
webpack_runtime: './webpack.js', webpack_runtime: './webpack.js',
// EE-only // EE-only
add_gitlab_slack_application: './add_gitlab_slack_application/index.js', add_gitlab_slack_application: 'ee/add_gitlab_slack_application/index.js',
burndown_chart: './burndown_chart/index.js', burndown_chart: 'ee/burndown_chart/index.js',
epic_show: 'ee/epics/epic_show/epic_show_bundle.js', epic_show: 'ee/epics/epic_show/epic_show_bundle.js',
new_epic: 'ee/epics/new_epic/new_epic_bundle.js', new_epic: 'ee/epics/new_epic/new_epic_bundle.js',
geo_nodes: 'ee/geo_nodes', geo_nodes: 'ee/geo_nodes',
issuable: './issuable/issuable_bundle.js', issuable: 'ee/issuable/issuable_bundle.js',
issues: './issues/issues_bundle.js', issues: 'ee/issues/issues_bundle.js',
ldap_group_links: './groups/ldap_group_links.js', ldap_group_links: 'ee/groups/ldap_group_links.js',
mirrors: './mirrors', mirrors: 'ee/mirrors',
ee_protected_branches: 'ee/protected_branches', ee_protected_branches: 'ee/protected_branches',
ee_protected_tags: 'ee/protected_tags', ee_protected_tags: 'ee/protected_tags',
service_desk: './projects/settings_service_desk/service_desk_bundle.js', service_desk: 'ee/projects/settings_service_desk/service_desk_bundle.js',
service_desk_issues: './service_desk_issues/index.js', service_desk_issues: 'ee/service_desk_issues/index.js',
roadmap: 'ee/roadmap', roadmap: 'ee/roadmap',
ee_sidebar: 'ee/sidebar/sidebar_bundle.js', ee_sidebar: 'ee/sidebar/sidebar_bundle.js',
}, },
...@@ -331,6 +325,7 @@ var config = { ...@@ -331,6 +325,7 @@ var config = {
'images': path.join(ROOT_PATH, 'app/assets/images'), 'images': path.join(ROOT_PATH, 'app/assets/images'),
'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'), 'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'),
'vue$': 'vue/dist/vue.esm.js', 'vue$': 'vue/dist/vue.esm.js',
'spec': path.join(ROOT_PATH, 'spec/javascripts'),
// EE-only // EE-only
'ee': path.join(ROOT_PATH, 'ee/app/assets/javascripts'), 'ee': path.join(ROOT_PATH, 'ee/app/assets/javascripts'),
......
...@@ -17,12 +17,14 @@ Gets all epics of the requested group and its subgroups. ...@@ -17,12 +17,14 @@ Gets all epics of the requested group and its subgroups.
``` ```
GET /groups/:id/-/epics GET /groups/:id/-/epics
GET /groups/:id/-/epics?author_id=5 GET /groups/:id/-/epics?author_id=5
GET /groups/:id/-/epics?labels=bug,reproduced
``` ```
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------| | ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `author_id` | integer | no | Return epics created by the given user `id` | | `author_id` | integer | no | Return epics created by the given user `id` |
| `labels` | string | no | Return epics matching a comma separated list of labels names. Label names from the epic group or a parent group can be used |
| `order_by` | string | no | Return epics ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `order_by` | string | no | Return epics ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return epics sorted in `asc` or `desc` order. Default is `desc` | | `sort` | string | no | Return epics sorted in `asc` or `desc` order. Default is `desc` |
| `search` | string | no | Search epics against their `title` and `description` | | `search` | string | no | Search epics against their `title` and `description` |
...@@ -49,6 +51,7 @@ Example response: ...@@ -49,6 +51,7 @@ Example response:
"avatar_url": "http://www.gravatar.com/avatar/018729e129a6f31c80a6327a30196823?s=80&d=identicon", "avatar_url": "http://www.gravatar.com/avatar/018729e129a6f31c80a6327a30196823?s=80&d=identicon",
"web_url": "http://localhost:3001/kam" "web_url": "http://localhost:3001/kam"
}, },
"labels": [],
"start_date": null, "start_date": null,
"end_date": null, "end_date": null,
"created_at": "2018-01-21T06:21:13.165Z", "created_at": "2018-01-21T06:21:13.165Z",
...@@ -110,6 +113,7 @@ POST /groups/:id/-/epics ...@@ -110,6 +113,7 @@ POST /groups/:id/-/epics
| ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------| | ------------------- | ---------------- | ---------- | ---------------------------------------------------------------------------------------|
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) owned by the authenticated user |
| `title` | string | yes | The title of the epic | | `title` | string | yes | The title of the epic |
| `labels` | string | no | The comma separated list of labels |
| `description` | string | no | The description of the epic | | `description` | string | no | The description of the epic |
| `start_date` | string | no | The start date of the epic | | `start_date` | string | no | The start date of the epic |
| `end_date` | string. | no | The end date of the epic | | `end_date` | string. | no | The end date of the epic |
...@@ -135,6 +139,7 @@ Example response: ...@@ -135,6 +139,7 @@ Example response:
"id" : 18, "id" : 18,
"username" : "eileen.lowe" "username" : "eileen.lowe"
}, },
"labels": [],
"start_date": null, "start_date": null,
"end_date": null, "end_date": null,
"created_at": "2018-01-21T06:21:13.165Z", "created_at": "2018-01-21T06:21:13.165Z",
...@@ -156,6 +161,7 @@ PUT /groups/:id/-/epics/:epic_iid ...@@ -156,6 +161,7 @@ PUT /groups/:id/-/epics/:epic_iid
| `epic_iid` | integer/string | yes | The internal ID of the epic | | `epic_iid` | integer/string | yes | The internal ID of the epic |
| `title` | string | no | The title of an epic | | `title` | string | no | The title of an epic |
| `description` | string | no | The description of an epic | | `description` | string | no | The description of an epic |
| `labels` | string | no | The comma separated list of labels |
| `start_date` | string | no | The start date of an epic | | `start_date` | string | no | The start date of an epic |
| `end_date` | string. | no | The end date of an epic | | `end_date` | string. | no | The end date of an epic |
...@@ -180,6 +186,7 @@ Example response: ...@@ -180,6 +186,7 @@ Example response:
"id" : 18, "id" : 18,
"username" : "eileen.lowe" "username" : "eileen.lowe"
}, },
"labels": [],
"start_date": null, "start_date": null,
"end_date": null, "end_date": null,
"created_at": "2018-01-21T06:21:13.165Z", "created_at": "2018-01-21T06:21:13.165Z",
......
<script> <script>
import Flash from '~/flash'; import Flash from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility';
import GitlabSlackService from '../services/gitlab_slack_service'; import GitlabSlackService from '../services/gitlab_slack_service';
import { redirectTo } from '../../lib/utils/url_utility';
export default { export default {
props: { props: {
......
import axios from '../../lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
export default { export default {
addToSlack(url, projectId) { addToSlack(url, projectId) {
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
/* global BoardService */ /* global BoardService */
import Flash from '~/flash'; import Flash from '~/flash';
import modal from '../../vue_shared/components/modal.vue'; import modal from '~/vue_shared/components/modal.vue';
import { visitUrl } from '../../lib/utils/url_utility'; import { visitUrl } from '~/lib/utils/url_utility';
import BoardMilestoneSelect from './milestone_select.vue'; import BoardMilestoneSelect from './milestone_select.vue';
import BoardWeightSelect from './weight_select.vue'; import BoardWeightSelect from './weight_select.vue';
import BoardLabelsSelect from './labels_select.vue'; import BoardLabelsSelect from './labels_select.vue';
......
<script> <script>
/* global ListIssue */ /* global ListIssue */
import _ from 'underscore'; import _ from 'underscore';
import eventHub from '../eventhub'; import eventHub from '~/boards/eventhub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue'; import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import Api from '../../api'; import Api from '~/api';
export default { export default {
name: 'BoardProjectSelect', name: 'BoardProjectSelect',
......
...@@ -9,10 +9,10 @@ ...@@ -9,10 +9,10 @@
* [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png) * [Mockup](https://gitlab.com/gitlab-org/gitlab-ce/uploads/2f655655c0eadf655d0ae7467b53002a/environments__deploy-graphic.png)
*/ */
import _ from 'underscore'; import _ from 'underscore';
import { n__ } from '~/locale';
import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import deployBoardSvg from 'ee_empty_states/icons/_deploy_board.svg'; import deployBoardSvg from 'ee_empty_states/icons/_deploy_board.svg';
import { n__ } from '../../locale';
import instanceComponent from './deploy_board_instance_component.vue'; import instanceComponent from './deploy_board_instance_component.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
export default { export default {
components: { components: {
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* this information in the tooltip and the colors. * this information in the tooltip and the colors.
* Mockup is https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1551#note_26595150 * Mockup is https://gitlab.com/gitlab-org/gitlab-ee/merge_requests/1551#note_26595150
*/ */
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
......
<script> <script>
/* eslint-disable vue/require-default-prop */ /* eslint-disable vue/require-default-prop */
import issuableApp from '~/issue_show/components/app.vue'; import issuableApp from '~/issue_show/components/app.vue';
import relatedIssuesRoot from '~/issuable/related_issues/components/related_issues_root.vue'; import relatedIssuesRoot from 'ee/issuable/related_issues/components/related_issues_root.vue';
import issuableAppEventHub from '~/issue_show/event_hub'; import issuableAppEventHub from '~/issue_show/event_hub';
import epicHeader from './epic_header.vue'; import epicHeader from './epic_header.vue';
import epicSidebar from '../../sidebar/components/sidebar_app.vue'; import epicSidebar from '../../sidebar/components/sidebar_app.vue';
......
<script> <script>
import icon from '../../vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
export default { export default {
components: { components: {
......
<script> <script>
import icon from '../../vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import tooltip from '../../vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import '../../lib/utils/datetime_utility'; import '~/lib/utils/datetime_utility';
export default { export default {
components: { components: {
......
import Vue from 'vue'; import Vue from 'vue';
import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
import RelatedIssuesRoot from './related_issues/components/related_issues_root.vue'; import RelatedIssuesRoot from './related_issues/components/related_issues_root.vue';
import { convertPermissionToBoolean } from '../lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const relatedIssuesRootElement = document.querySelector('.js-related-issues-root'); const relatedIssuesRootElement = document.querySelector('.js-related-issues-root');
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
import Sortable from 'vendor/Sortable'; import Sortable from 'vendor/Sortable';
import loadingIcon from '~/vue_shared/components/loading_icon.vue'; import loadingIcon from '~/vue_shared/components/loading_icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import sortableConfig from '~/sortable/sortable_config'; import sortableConfig from 'ee/sortable/sortable_config';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import issueItem from './issue_item.vue'; import issueItem from './issue_item.vue';
import addIssuableForm from './add_issuable_form.vue'; import addIssuableForm from './add_issuable_form.vue';
......
...@@ -24,7 +24,7 @@ Your caret can stop touching a `rawReference` can happen in a variety of ways: ...@@ -24,7 +24,7 @@ Your caret can stop touching a `rawReference` can happen in a variety of ways:
*/ */
import _ from 'underscore'; import _ from 'underscore';
import Flash from '../../../flash'; import Flash from '~/flash';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import RelatedIssuesBlock from './related_issues_block.vue'; import RelatedIssuesBlock from './related_issues_block.vue';
import RelatedIssuesStore from '../stores/related_issues_store'; import RelatedIssuesStore from '../stores/related_issues_store';
......
import tooltip from '../../../vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import icon from '../../../vue_shared/components/icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
const mixins = { const mixins = {
......
import _ from 'underscore'; import _ from 'underscore';
import { __ } from '~/locale'; import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import Flash from '../flash'; import Flash from '~/flash';
import { backOff } from '~/lib/utils/common_utils';
import AUTH_METHOD from './constants'; import AUTH_METHOD from './constants';
import { backOff } from '../lib/utils/common_utils';
export default class MirrorPull { export default class MirrorPull {
constructor(formSelector) { constructor(formSelector) {
......
<script> <script>
import ciStatus from '../../../vue_shared/components/ci_icon.vue'; import ciStatus from '~/vue_shared/components/ci_icon.vue';
import tooltip from '../../../vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
......
<script> <script>
import Flash from '../../../flash'; import Flash from '~/flash';
import serviceDeskSetting from './service_desk_setting.vue'; import serviceDeskSetting from './service_desk_setting.vue';
import ServiceDeskStore from '../stores/service_desk_store'; import ServiceDeskStore from '../stores/service_desk_store';
import ServiceDeskService from '../services/service_desk_service'; import ServiceDeskService from '../services/service_desk_service';
......
<script> <script>
import tooltip from '~/vue_shared/directives/tooltip';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import tooltip from '../../../vue_shared/directives/tooltip';
export default { export default {
name: 'ServiceDeskSetting', name: 'ServiceDeskSetting',
......
import Vue from 'vue'; import Vue from 'vue';
import { convertPermissionToBoolean } from '~/lib/utils/common_utils';
import serviceDeskRoot from './components/service_desk_root.vue'; import serviceDeskRoot from './components/service_desk_root.vue';
import { convertPermissionToBoolean } from '../../lib/utils/common_utils';
document.addEventListener('DOMContentLoaded', () => { document.addEventListener('DOMContentLoaded', () => {
const serviceDeskRootElement = document.querySelector('.js-service-desk-setting-root'); const serviceDeskRootElement = document.querySelector('.js-service-desk-setting-root');
......
import Flash from '~/flash'; import Flash from '~/flash';
import LinkToMemberAvatar from '~/vue_shared/components/link_to_member_avatar'; import LinkToMemberAvatar from 'ee/vue_shared/components/link_to_member_avatar';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
......
<script> <script>
import arrowSvg from 'ee_icons/_arrow_mini_pipeline_graph.svg'; import arrowSvg from 'ee_icons/_arrow_mini_pipeline_graph.svg';
import icon from './icon.vue'; import icon from '~/vue_shared/components/icon.vue';
import ciStatus from './ci_icon.vue'; import ciStatus from '~/vue_shared/components/ci_icon.vue';
import tooltip from '../directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
export default { export default {
directives: { directives: {
......
...@@ -54,11 +54,12 @@ class Groups::EpicsController < Groups::ApplicationController ...@@ -54,11 +54,12 @@ class Groups::EpicsController < Groups::ApplicationController
end end
def epic_params_attributes def epic_params_attributes
%i[ [
title :title,
description :description,
start_date :start_date,
end_date :end_date,
label_ids: []
] ]
end end
...@@ -67,7 +68,7 @@ class Groups::EpicsController < Groups::ApplicationController ...@@ -67,7 +68,7 @@ class Groups::EpicsController < Groups::ApplicationController
end end
def update_service def update_service
Epics::UpdateService.new(nil, current_user, epic_params) Epics::UpdateService.new(@group, current_user, epic_params)
end end
def finder_type def finder_type
......
...@@ -11,6 +11,7 @@ class EpicsFinder < IssuableFinder ...@@ -11,6 +11,7 @@ class EpicsFinder < IssuableFinder
items = by_search(items) items = by_search(items)
items = by_author(items) items = by_author(items)
items = by_timeframe(items) items = by_timeframe(items)
items = by_label(items)
sort(items) sort(items)
end end
......
...@@ -141,11 +141,25 @@ module Geo ...@@ -141,11 +141,25 @@ module Geo
# @return [ActiveRecord::Relation<Project>] list of projects updated recently # @return [ActiveRecord::Relation<Project>] list of projects updated recently
def legacy_find_projects_updated_recently def legacy_find_projects_updated_recently
legacy_inner_join_registry_ids( registries = Geo::ProjectRegistry.dirty.retry_due.pluck(:project_id, :last_repository_successful_sync_at)
current_node.projects, return Project.none if registries.empty?
Geo::ProjectRegistry.dirty.retry_due.pluck(:project_id),
Project id_and_last_sync_values = registries.map do |id, last_repository_successful_sync_at|
) "(#{id}, #{quote_value(last_repository_successful_sync_at)})"
end
joined_relation = current_node.projects.joins(<<~SQL)
INNER JOIN
(VALUES #{id_and_last_sync_values.join(',')})
project_registry(id, last_repository_successful_sync_at)
ON #{Project.table_name}.id = project_registry.id
SQL
joined_relation
end
def quote_value(value)
::Gitlab::SQL::Glob.q(value)
end end
# @return [ActiveRecord::Relation<Geo::ProjectRegistry>] list of synced projects # @return [ActiveRecord::Relation<Geo::ProjectRegistry>] list of synced projects
......
...@@ -11,4 +11,5 @@ class EpicEntity < IssuableEntity ...@@ -11,4 +11,5 @@ class EpicEntity < IssuableEntity
expose :web_url do |epic| expose :web_url do |epic|
group_epic_path(epic.group, epic) group_epic_path(epic.group, epic)
end end
expose :labels, using: LabelEntity
end end
module Epics
class BaseService < IssuableBaseService
attr_reader :group
def initialize(group, current_user, params)
@group, @current_user, @params = group, current_user, params
end
private
def available_labels
@available_labels ||= LabelsFinder.new(
current_user,
group_id: group.id,
only_group_labels: true,
include_ancestor_groups: true
).execute
end
def parent
group
end
end
end
module Epics module Epics
class CreateService < IssuableBaseService class CreateService < Epics::BaseService
attr_reader :group
def initialize(group, current_user, params)
@group, @current_user, @params = group, current_user, params
end
def execute def execute
@epic = group.epics.new(whitelisted_epic_params) @epic = group.epics.new(whitelisted_epic_params)
create(@epic) create(@epic)
......
module Epics module Epics
class UpdateService < ::IssuableBaseService class UpdateService < Epics::BaseService
def execute(epic) def execute(epic)
update(epic) update(epic)
end end
......
...@@ -65,7 +65,7 @@ module Geo ...@@ -65,7 +65,7 @@ module Geo
def find_project_ids_updated_recently(batch_size:) def find_project_ids_updated_recently(batch_size:)
shard_restriction(finder.find_projects_updated_recently(batch_size: batch_size)) shard_restriction(finder.find_projects_updated_recently(batch_size: batch_size))
.order(Gitlab::Database.nulls_first_order(:last_repository_updated_at, :desc)) .order('project_registry.last_repository_successful_sync_at ASC NULLS FIRST, projects.last_repository_updated_at ASC')
.pluck(:id) .pluck(:id)
end end
......
---
title: Geo - Fix repository synchronization order for projects updated recently
merge_request:
author:
type: fixed
---
title: Allow adding or removing labels from epics and filter epics by labels
merge_request:
author:
type: added
---
title: Move BoardNewIssue vue component
merge_request: 16947
author: George Tsiolis
type: performance
...@@ -32,8 +32,9 @@ module API ...@@ -32,8 +32,9 @@ module API
def find_epics(args = {}) def find_epics(args = {})
args = declared_params.merge(args) args = declared_params.merge(args)
args[:label_name] = args.delete(:labels)
epics = EpicsFinder.new(current_user, args).execute epics = EpicsFinder.new(current_user, args).execute.preload(:labels)
epics.reorder(args[:order_by] => args[:sort]) epics.reorder(args[:order_by] => args[:sort])
end end
...@@ -54,6 +55,7 @@ module API ...@@ -54,6 +55,7 @@ module API
desc: 'Return epics sorted in `asc` or `desc` order.' desc: 'Return epics sorted in `asc` or `desc` order.'
optional :search, type: String, desc: 'Search epics for text present in the title or description' optional :search, type: String, desc: 'Search epics for text present in the title or description'
optional :author_id, type: Integer, desc: 'Return epics which are authored by the user with the given ID' optional :author_id, type: Integer, desc: 'Return epics which are authored by the user with the given ID'
optional :labels, type: String, desc: 'Comma-separated list of label names'
end end
get ':id/-/epics' do get ':id/-/epics' do
present find_epics(group_id: user_group.id), with: Entities::Epic present find_epics(group_id: user_group.id), with: Entities::Epic
...@@ -79,6 +81,7 @@ module API ...@@ -79,6 +81,7 @@ module API
optional :description, type: String, desc: 'The description of an epic' optional :description, type: String, desc: 'The description of an epic'
optional :start_date, type: String, desc: 'The start date of an epic' optional :start_date, type: String, desc: 'The start date of an epic'
optional :end_date, type: String, desc: 'The end date of an epic' optional :end_date, type: String, desc: 'The end date of an epic'
optional :labels, type: String, desc: 'Comma-separated list of label names'
end end
post ':id/-/epics' do post ':id/-/epics' do
authorize_can_create! authorize_can_create!
...@@ -100,14 +103,15 @@ module API ...@@ -100,14 +103,15 @@ module API
optional :description, type: String, desc: 'The description of an epic' optional :description, type: String, desc: 'The description of an epic'
optional :start_date, type: String, desc: 'The start date of an epic' optional :start_date, type: String, desc: 'The start date of an epic'
optional :end_date, type: String, desc: 'The end date of an epic' optional :end_date, type: String, desc: 'The end date of an epic'
at_least_one_of :title, :description, :start_date, :end_date optional :labels, type: String, desc: 'Comma-separated list of label names'
at_least_one_of :title, :description, :start_date, :end_date, :labels
end end
put ':id/-/epics/:epic_iid' do put ':id/-/epics/:epic_iid' do
authorize_can_admin! authorize_can_admin!
update_params = declared_params(include_missing: false) update_params = declared_params(include_missing: false)
update_params.delete(:epic_iid) update_params.delete(:epic_iid)
result = ::Epics::UpdateService.new(nil, current_user, update_params).execute(epic) result = ::Epics::UpdateService.new(user_group, current_user, update_params).execute(epic)
if result.valid? if result.valid?
present result, with: Entities::Epic present result, with: Entities::Epic
......
...@@ -4,6 +4,7 @@ describe Groups::EpicsController do ...@@ -4,6 +4,7 @@ describe Groups::EpicsController do
let(:group) { create(:group, :private) } let(:group) { create(:group, :private) }
let(:epic) { create(:epic, group: group) } let(:epic) { create(:epic, group: group) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:label) { create(:group_label, group: group, title: 'Bug') }
before do before do
sign_in(user) sign_in(user)
...@@ -170,7 +171,7 @@ describe Groups::EpicsController do ...@@ -170,7 +171,7 @@ describe Groups::EpicsController do
describe 'PUT #update' do describe 'PUT #update' do
before do before do
group.add_developer(user) group.add_developer(user)
put :update, group_id: group, id: epic.to_param, epic: { title: 'New title' }, format: :json put :update, group_id: group, id: epic.to_param, epic: { title: 'New title', label_ids: [label.id] }, format: :json
end end
it 'returns status 200' do it 'returns status 200' do
...@@ -178,7 +179,10 @@ describe Groups::EpicsController do ...@@ -178,7 +179,10 @@ describe Groups::EpicsController do
end end
it 'updates the epic correctly' do it 'updates the epic correctly' do
expect(epic.reload.title).to eq('New title') epic.reload
expect(epic.title).to eq('New title')
expect(epic.labels).to eq([label])
end end
end end
...@@ -210,7 +214,7 @@ describe Groups::EpicsController do ...@@ -210,7 +214,7 @@ describe Groups::EpicsController do
describe '#create' do describe '#create' do
subject do subject do
post :create, group_id: group, epic: { title: 'new epic', description: 'some descripition' } post :create, group_id: group, epic: { title: 'new epic', description: 'some descripition', label_ids: [label.id] }
end end
context 'when user has permissions to create an epic' do context 'when user has permissions to create an epic' do
...@@ -229,6 +233,10 @@ describe Groups::EpicsController do ...@@ -229,6 +233,10 @@ describe Groups::EpicsController do
expect { subject }.to change { Epic.count }.from(0).to(1) expect { subject }.to change { Epic.count }.from(0).to(1)
end end
it 'assigns labels to the new epic' do
expect { subject }.to change { LabelLink.count }.from(0).to(1)
end
it 'returns the correct json' do it 'returns the correct json' do
subject subject
......
...@@ -3,5 +3,15 @@ FactoryBot.define do ...@@ -3,5 +3,15 @@ FactoryBot.define do
title { generate(:title) } title { generate(:title) }
group group
author author
factory :labeled_epic do
transient do
labels []
end
after(:create) do |epic, evaluator|
epic.update_attributes(labels: evaluator.labels)
end
end
end end
end end
...@@ -79,6 +79,15 @@ describe EpicsFinder do ...@@ -79,6 +79,15 @@ describe EpicsFinder do
end end
end end
context 'by label' do
let(:label) { create(:label) }
let!(:labeled_epic) { create(:labeled_epic, group: group, labels: [label]) }
it 'returns all epics with given label' do
expect(epics(label_name: label.title)).to contain_exactly(labeled_epic)
end
end
context 'when subgroups are supported', :nested_groups do context 'when subgroups are supported', :nested_groups do
let(:subgroup) { create(:group, :private, parent: group) } let(:subgroup) { create(:group, :private, parent: group) }
let(:subgroup2) { create(:group, :private, parent: subgroup) } let(:subgroup2) { create(:group, :private, parent: subgroup) }
......
...@@ -18,6 +18,12 @@ ...@@ -18,6 +18,12 @@
}, },
"additionalProperties": false "additionalProperties": false
}, },
"labels": {
"type": "array",
"items": {
"type": "string"
}
},
"start_date": { "type": ["string", "null"] }, "start_date": { "type": ["string", "null"] },
"end_date": { "type": ["string", "null"] }, "end_date": { "type": ["string", "null"] },
"created_at": { "type": ["string", "null"] }, "created_at": { "type": ["string", "null"] },
......
...@@ -21,7 +21,13 @@ ...@@ -21,7 +21,13 @@
"start_date": { "type": ["string", "null"] }, "start_date": { "type": ["string", "null"] },
"end_date": { "type": ["string", "null"] }, "end_date": { "type": ["string", "null"] },
"created_at": { "type": ["string", "null"] }, "created_at": { "type": ["string", "null"] },
"updated_at": { "type": ["string", "null"] } "updated_at": { "type": ["string", "null"] },
"labels": {
"type": "array",
"items": {
"type": "string"
}
}
}, },
"additionalProperties": false "additionalProperties": false
}, },
......
...@@ -78,6 +78,8 @@ describe API::Epics do ...@@ -78,6 +78,8 @@ describe API::Epics do
created_at: 2.days.ago, created_at: 2.days.ago,
updated_at: 3.days.ago) updated_at: 3.days.ago)
end end
let!(:label) { create(:group_label, title: 'a-test', group: group) }
let!(:label_link) { create(:label_link, label: label, target: epic2) }
before do before do
stub_licensed_features(epics: true) stub_licensed_features(epics: true)
...@@ -130,6 +132,12 @@ describe API::Epics do ...@@ -130,6 +132,12 @@ describe API::Epics do
expect_array_response([epic2.id, epic.id]) expect_array_response([epic2.id, epic.id])
end end
it 'returns an array of labeled epics' do
get api(url, user), labels: label.title
expect_array_response([epic2.id])
end
end end
end end
...@@ -157,7 +165,7 @@ describe API::Epics do ...@@ -157,7 +165,7 @@ describe API::Epics do
describe 'POST /groups/:id/-/epics' do describe 'POST /groups/:id/-/epics' do
let(:url) { "/groups/#{group.path}/-/epics" } let(:url) { "/groups/#{group.path}/-/epics" }
let(:params) { { title: 'new epic', description: 'epic description' } } let(:params) { { title: 'new epic', description: 'epic description', labels: 'label1' } }
it_behaves_like 'error requests' it_behaves_like 'error requests'
...@@ -196,6 +204,7 @@ describe API::Epics do ...@@ -196,6 +204,7 @@ describe API::Epics do
expect(epic.title).to eq('new epic') expect(epic.title).to eq('new epic')
expect(epic.description).to eq('epic description') expect(epic.description).to eq('epic description')
expect(epic.labels.first.title).to eq('label1')
end end
end end
end end
...@@ -203,7 +212,7 @@ describe API::Epics do ...@@ -203,7 +212,7 @@ describe API::Epics do
describe 'PUT /groups/:id/-/epics/:epic_iid' do describe 'PUT /groups/:id/-/epics/:epic_iid' do
let(:url) { "/groups/#{group.path}/-/epics/#{epic.iid}" } let(:url) { "/groups/#{group.path}/-/epics/#{epic.iid}" }
let(:params) { { title: 'new title', description: 'new description' } } let(:params) { { title: 'new title', description: 'new description', labels: 'label2' } }
it_behaves_like 'error requests' it_behaves_like 'error requests'
...@@ -250,6 +259,7 @@ describe API::Epics do ...@@ -250,6 +259,7 @@ describe API::Epics do
expect(result.title).to eq('new title') expect(result.title).to eq('new title')
expect(result.description).to eq('new description') expect(result.description).to eq('new description')
expect(result.labels.first.title).to eq('label2')
end end
end end
end end
......
...@@ -10,7 +10,7 @@ describe EpicEntity do ...@@ -10,7 +10,7 @@ describe EpicEntity do
subject { described_class.new(resource, request: request).as_json } subject { described_class.new(resource, request: request).as_json }
it 'has Issuable attributes' do it 'has Issuable attributes' do
expect(subject).to include(:id, :iid, :description, :title) expect(subject).to include(:id, :iid, :description, :title, :labels)
end end
it 'has epic specific attributes' do it 'has epic specific attributes' do
......
...@@ -7,7 +7,7 @@ describe Epics::UpdateService do ...@@ -7,7 +7,7 @@ describe Epics::UpdateService do
describe '#execute' do describe '#execute' do
def update_epic(opts) def update_epic(opts)
described_class.new(nil, user, opts).execute(epic) described_class.new(group, user, opts).execute(epic)
end end
context 'multiple values update' do context 'multiple values update' do
......
...@@ -7,12 +7,13 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -7,12 +7,13 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
let!(:primary) { create(:geo_node, :primary) } let!(:primary) { create(:geo_node, :primary) }
let!(:secondary) { create(:geo_node) } let!(:secondary) { create(:geo_node) }
let!(:synced_group) { create(:group) }
let!(:project_in_synced_group) { create(:project, group: synced_group) } let!(:restricted_group) { create(:group) }
let!(:unsynced_project_in_restricted_group) { create(:project, group: restricted_group) }
let!(:unsynced_project) { create(:project) } let!(:unsynced_project) { create(:project) }
let(:shard_name) { Gitlab.config.repositories.storages.keys.first }
subject { described_class.new } let(:shard_name) { Gitlab.config.repositories.storages.keys.first }
before do before do
stub_current_geo_node(secondary) stub_current_geo_node(secondary)
...@@ -37,7 +38,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -37,7 +38,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
end end
it 'performs Geo::ProjectSyncWorker for projects where last attempt to sync failed' do it 'performs Geo::ProjectSyncWorker for projects where last attempt to sync failed' do
create(:geo_project_registry, :sync_failed, project: project_in_synced_group) create(:geo_project_registry, :sync_failed, project: unsynced_project_in_restricted_group)
create(:geo_project_registry, :synced, project: unsynced_project) create(:geo_project_registry, :synced, project: unsynced_project)
expect(Geo::ProjectSyncWorker).to receive(:perform_async).once.and_return(spy) expect(Geo::ProjectSyncWorker).to receive(:perform_async).once.and_return(spy)
...@@ -54,7 +55,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -54,7 +55,7 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
end end
it 'performs Geo::ProjectSyncWorker for synced projects updated recently' do it 'performs Geo::ProjectSyncWorker for synced projects updated recently' do
create(:geo_project_registry, :synced, :repository_dirty, project: project_in_synced_group) create(:geo_project_registry, :synced, :repository_dirty, project: unsynced_project_in_restricted_group)
create(:geo_project_registry, :synced, project: unsynced_project) create(:geo_project_registry, :synced, project: unsynced_project)
create(:geo_project_registry, :synced, :wiki_dirty) create(:geo_project_registry, :synced, :wiki_dirty)
...@@ -104,12 +105,12 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -104,12 +105,12 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
context 'when node has namespace restrictions' do context 'when node has namespace restrictions' do
before do before do
secondary.update!(selective_sync_type: 'namespaces', namespaces: [synced_group]) secondary.update!(selective_sync_type: 'namespaces', namespaces: [restricted_group])
end end
it 'does not perform Geo::ProjectSyncWorker for projects that do not belong to selected namespaces to replicate' do it 'does not perform Geo::ProjectSyncWorker for projects that do not belong to selected namespaces to replicate' do
expect(Geo::ProjectSyncWorker).to receive(:perform_async) expect(Geo::ProjectSyncWorker).to receive(:perform_async)
.with(project_in_synced_group.id, within(1.minute).of(Time.now)) .with(unsynced_project_in_restricted_group.id, within(1.minute).of(Time.now))
.once .once
.and_return(spy) .and_return(spy)
...@@ -117,11 +118,11 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -117,11 +118,11 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
end end
it 'does not perform Geo::ProjectSyncWorker for synced projects updated recently that do not belong to selected namespaces to replicate' do it 'does not perform Geo::ProjectSyncWorker for synced projects updated recently that do not belong to selected namespaces to replicate' do
create(:geo_project_registry, :synced, :repository_dirty, project: project_in_synced_group) create(:geo_project_registry, :synced, :repository_dirty, project: unsynced_project_in_restricted_group)
create(:geo_project_registry, :synced, :repository_dirty, project: unsynced_project) create(:geo_project_registry, :synced, :repository_dirty, project: unsynced_project)
expect(Geo::ProjectSyncWorker).to receive(:perform_async) expect(Geo::ProjectSyncWorker).to receive(:perform_async)
.with(project_in_synced_group.id, within(1.minute).of(Time.now)) .with(unsynced_project_in_restricted_group.id, within(1.minute).of(Time.now))
.once .once
.and_return(spy) .and_return(spy)
...@@ -129,13 +130,53 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -129,13 +130,53 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
end end
end end
context 'repositories that have never been updated' do
let!(:project_list) { create_list(:project, 4, last_repository_updated_at: 2.hours.ago) }
let!(:abandoned_project) { create(:project) }
before do
# Project sync failed but never received an update
create(:geo_project_registry, :repository_sync_failed, project: abandoned_project)
abandoned_project.update_column(:last_repository_updated_at, 1.year.ago)
# Neither of these are needed for this spec
unsynced_project.destroy
unsynced_project_in_restricted_group.destroy
allow_any_instance_of(described_class).to receive(:db_retrieve_batch_size).and_return(2) # Must be >1 because of the Geo::BaseSchedulerWorker#interleave
secondary.update!(repos_max_capacity: 3) # Must be more than db_retrieve_batch_size
project_list.each do |project|
allow(Geo::ProjectSyncWorker)
.to receive(:perform_async)
.with(project.id, anything)
.and_call_original
end
allow_any_instance_of(Geo::ProjectRegistry).to receive(:wiki_sync_due?).and_return(false)
allow_any_instance_of(Geo::RepositorySyncService).to receive(:expire_repository_caches)
end
it 'tries to sync project where last attempt to sync failed' do
expect(Geo::ProjectSyncWorker)
.to receive(:perform_async)
.with(abandoned_project.id, anything)
.at_least(:once)
.and_return(spy)
3.times do
Sidekiq::Testing.inline! { subject.perform(shard_name) }
end
end
end
context 'all repositories fail' do context 'all repositories fail' do
let!(:project_list) { create_list(:project, 4, :random_last_repository_updated_at) } let!(:project_list) { create_list(:project, 4, :random_last_repository_updated_at) }
before do before do
# Neither of these are needed for this spec # Neither of these are needed for this spec
unsynced_project.destroy unsynced_project.destroy
project_in_synced_group.destroy unsynced_project_in_restricted_group.destroy
allow_any_instance_of(described_class).to receive(:db_retrieve_batch_size).and_return(2) # Must be >1 because of the Geo::BaseSchedulerWorker#interleave allow_any_instance_of(described_class).to receive(:db_retrieve_batch_size).and_return(2) # Must be >1 because of the Geo::BaseSchedulerWorker#interleave
secondary.update!(repos_max_capacity: 3) # Must be more than db_retrieve_batch_size secondary.update!(repos_max_capacity: 3) # Must be more than db_retrieve_batch_size
...@@ -161,14 +202,14 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach ...@@ -161,14 +202,14 @@ describe Geo::RepositoryShardSyncWorker, :geo, :delete, :clean_gitlab_redis_cach
context 'additional shards' do context 'additional shards' do
it 'skips backfill for projects on unhealthy shards' do it 'skips backfill for projects on unhealthy shards' do
missing_not_synced = create(:project, group: synced_group) missing_not_synced = create(:project, group: restricted_group)
missing_not_synced.update_column(:repository_storage, 'unknown') missing_not_synced.update_column(:repository_storage, 'unknown')
missing_dirty = create(:project, group: synced_group) missing_dirty = create(:project, group: restricted_group)
missing_dirty.update_column(:repository_storage, 'unknown') missing_dirty.update_column(:repository_storage, 'unknown')
create(:geo_project_registry, :synced, :repository_dirty, project: missing_dirty) create(:geo_project_registry, :synced, :repository_dirty, project: missing_dirty)
expect(Geo::ProjectSyncWorker).to receive(:perform_async).with(project_in_synced_group.id, anything) expect(Geo::ProjectSyncWorker).to receive(:perform_async).with(unsynced_project_in_restricted_group.id, anything)
expect(Geo::ProjectSyncWorker).not_to receive(:perform_async).with(missing_not_synced.id, anything) expect(Geo::ProjectSyncWorker).not_to receive(:perform_async).with(missing_not_synced.id, anything)
expect(Geo::ProjectSyncWorker).not_to receive(:perform_async).with(missing_dirty.id, anything) expect(Geo::ProjectSyncWorker).not_to receive(:perform_async).with(missing_dirty.id, anything)
......
...@@ -508,6 +508,10 @@ module API ...@@ -508,6 +508,10 @@ module API
expose :end_date expose :end_date
expose :created_at expose :created_at
expose :updated_at expose :updated_at
expose :labels do |epic, options|
# Avoids an N+1 query since labels are preloaded
epic.labels.map(&:title).sort
end
end end
class EpicIssue < Issue class EpicIssue < Issue
......
...@@ -5,6 +5,8 @@ describe LabelsFinder do ...@@ -5,6 +5,8 @@ describe LabelsFinder do
let(:group_1) { create(:group) } let(:group_1) { create(:group) }
let(:group_2) { create(:group) } let(:group_2) { create(:group) }
let(:group_3) { create(:group) } let(:group_3) { create(:group) }
let(:private_group_1) { create(:group, :private) }
let(:private_subgroup_1) { create(:group, :private, parent: private_group_1) }
let(:project_1) { create(:project, namespace: group_1) } let(:project_1) { create(:project, namespace: group_1) }
let(:project_2) { create(:project, namespace: group_2) } let(:project_2) { create(:project, namespace: group_2) }
...@@ -20,6 +22,8 @@ describe LabelsFinder do ...@@ -20,6 +22,8 @@ describe LabelsFinder do
let!(:group_label_1) { create(:group_label, group: group_1, title: 'Label 1 (group)') } let!(:group_label_1) { create(:group_label, group: group_1, title: 'Label 1 (group)') }
let!(:group_label_2) { create(:group_label, group: group_1, title: 'Group Label 2') } let!(:group_label_2) { create(:group_label, group: group_1, title: 'Group Label 2') }
let!(:group_label_3) { create(:group_label, group: group_2, title: 'Group Label 3') } let!(:group_label_3) { create(:group_label, group: group_2, title: 'Group Label 3') }
let!(:private_group_label_1) { create(:group_label, group: private_group_1, title: 'Private Group Label 1') }
let!(:private_subgroup_label_1) { create(:group_label, group: private_subgroup_1, title: 'Private Sub Group Label 1') }
let(:user) { create(:user) } let(:user) { create(:user) }
...@@ -66,6 +70,25 @@ describe LabelsFinder do ...@@ -66,6 +70,25 @@ describe LabelsFinder do
expect(finder.execute).to eq [group_label_2, group_label_1] expect(finder.execute).to eq [group_label_2, group_label_1]
end end
end end
context 'when including labels from group ancestors', :nested_groups do
it 'returns labels from group and its ancestors' do
private_group_1.add_developer(user)
private_subgroup_1.add_developer(user)
finder = described_class.new(user, group_id: private_subgroup_1.id, only_group_labels: true, include_ancestor_groups: true)
expect(finder.execute).to eq [private_group_label_1, private_subgroup_label_1]
end
it 'ignores labels from groups which user can not read' do
private_subgroup_1.add_developer(user)
finder = described_class.new(user, group_id: private_subgroup_1.id, only_group_labels: true, include_ancestor_groups: true)
expect(finder.execute).to eq [private_subgroup_label_1]
end
end
end end
context 'filtering by project_id' do context 'filtering by project_id' do
......
import Vue from 'vue'; import Vue from 'vue';
import addGitlabSlackApplication from '~/add_gitlab_slack_application/components/add_gitlab_slack_application.vue'; import addGitlabSlackApplication from 'ee/add_gitlab_slack_application/components/add_gitlab_slack_application.vue';
import GitlabSlackService from '~/add_gitlab_slack_application/services/gitlab_slack_service'; import GitlabSlackService from 'ee/add_gitlab_slack_application/services/gitlab_slack_service';
import * as UrlUtility from '~/lib/utils/url_utility'; import * as UrlUtility from '~/lib/utils/url_utility';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('AddGitlabSlackApplication', () => { describe('AddGitlabSlackApplication', () => {
const redirectLink = '//redirectLink'; const redirectLink = '//redirectLink';
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
import Vue from 'vue'; import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import boardNewIssue from '~/boards/components/board_new_issue'; import boardNewIssue from '~/boards/components/board_new_issue.vue';
import '~/boards/models/list'; import '~/boards/models/list';
import { listObj, boardsMockInterceptor, mockBoardService } from './mock_data'; import { listObj, boardsMockInterceptor, mockBoardService } from './mock_data';
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import Vue from 'vue'; import Vue from 'vue';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import AssigneeSelect from '~/boards/components/assignee_select.vue';
import '~/boards/services/board_service'; import '~/boards/services/board_service';
import '~/boards/stores/boards_store'; import '~/boards/stores/boards_store';
import IssuableContext from '~/issuable_context'; import IssuableContext from '~/issuable_context';
import AssigneeSelect from 'ee/boards/components/assignee_select.vue';
import { boardObj, mockBoardService } from '../mock_data'; import { boardObj, mockBoardService } from '../mock_data';
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import boardForm from '~/boards/components/board_form.vue'; import boardForm from 'ee/boards/components/board_form.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('board_form.vue', () => { describe('board_form.vue', () => {
const props = { const props = {
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
import Vue from 'vue'; import Vue from 'vue';
import BoardService from '~/boards/services/board_service'; import BoardService from '~/boards/services/board_service';
import '~/boards/components/boards_selector'; import 'ee/boards/components/boards_selector';
import setTimeoutPromiseHelper from '../../helpers/set_timeout_promise_helper'; import setTimeoutPromiseHelper from 'spec/helpers/set_timeout_promise_helper';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const throttleDuration = 1; const throttleDuration = 1;
......
...@@ -4,7 +4,7 @@ import Vue from 'vue'; ...@@ -4,7 +4,7 @@ import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import '~/labels_select'; import '~/labels_select';
import LabelsSelect from '~/boards/components/labels_select.vue'; import LabelsSelect from 'ee/boards/components/labels_select.vue';
import IssuableContext from '~/issuable_context'; import IssuableContext from '~/issuable_context';
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import WeightSelect from '~/boards/components/weight_select.vue'; import WeightSelect from 'ee/boards/components/weight_select.vue';
import IssuableContext from '~/issuable_context'; import IssuableContext from '~/issuable_context';
let vm; let vm;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
import Vue from 'vue'; import Vue from 'vue';
import MockAdapater from 'axios-mock-adapter'; import MockAdapater from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import MilestoneSelect from '~/boards/components/milestone_select.vue'; import MilestoneSelect from 'ee/boards/components/milestone_select.vue';
import IssuableContext from '~/issuable_context'; import IssuableContext from '~/issuable_context';
import { boardObj } from './mock_data'; import { boardObj } from './mock_data';
......
import VariableList from '~/ci_variable_list/ci_variable_list'; import VariableList from '~/ci_variable_list/ci_variable_list';
import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
describe('VariableList (EE features)', () => { describe('VariableList (EE features)', () => {
preloadFixtures('projects/ci_cd_settings.html.raw'); preloadFixtures('projects/ci_cd_settings.html.raw');
......
import VariableList from '~/ci_variable_list/ci_variable_list'; import VariableList from '~/ci_variable_list/ci_variable_list';
import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
const HIDE_CLASS = 'hide'; const HIDE_CLASS = 'hide';
......
...@@ -7,7 +7,7 @@ import { ...@@ -7,7 +7,7 @@ import {
REQUEST_SUCCESS, REQUEST_SUCCESS,
REQUEST_FAILURE, REQUEST_FAILURE,
} from '~/clusters/constants'; } from '~/clusters/constants';
import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
describe('Clusters', () => { describe('Clusters', () => {
let cluster; let cluster;
......
...@@ -12,7 +12,7 @@ import { ...@@ -12,7 +12,7 @@ import {
REQUEST_FAILURE, REQUEST_FAILURE,
} from '~/clusters/constants'; } from '~/clusters/constants';
import applicationRow from '~/clusters/components/application_row.vue'; import applicationRow from '~/clusters/components/application_row.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { DEFAULT_APPLICATION_STATE } from '../services/mock_data'; import { DEFAULT_APPLICATION_STATE } from '../services/mock_data';
describe('Application Row', () => { describe('Application Row', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import applications from '~/clusters/components/applications.vue'; import applications from '~/clusters/components/applications.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Applications', () => { describe('Applications', () => {
let vm; let vm;
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue'; import commitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Commit pipeline status component', () => { describe('Commit pipeline status component', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import banner from '~/cycle_analytics/components/banner.vue'; import banner from '~/cycle_analytics/components/banner.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Cycle analytics banner', () => { describe('Cycle analytics banner', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import component from '~/cycle_analytics/components/total_time_component.vue'; import component from '~/cycle_analytics/components/total_time_component.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Total time component', () => { describe('Total time component', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import DeployBoard from '~/environments/components/deploy_board_component.vue'; import DeployBoard from 'ee/environments/components/deploy_board_component.vue';
import { deployBoardMockData } from './mock_data'; import { deployBoardMockData } from './mock_data';
describe('Deploy Board', () => { describe('Deploy Board', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import DeployBoardInstance from '~/environments/components/deploy_board_instance_component.vue'; import DeployBoardInstance from 'ee/environments/components/deploy_board_instance_component.vue';
describe('Deploy Board Instance', () => { describe('Deploy Board Instance', () => {
let DeployBoardInstanceComponent; let DeployBoardInstanceComponent;
......
import Vue from 'vue'; import Vue from 'vue';
import emptyState from '~/environments/components/empty_state.vue'; import emptyState from '~/environments/components/empty_state.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('environments empty state', () => { describe('environments empty state', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import environmentTableComp from '~/environments/components/environments_table.vue'; import environmentTableComp from '~/environments/components/environments_table.vue';
import eventHub from '~/environments/event_hub'; import eventHub from '~/environments/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { deployBoardMockData } from './mock_data'; import { deployBoardMockData } from './mock_data';
import mountComponent from '../helpers/vue_mount_component_helper';
describe('Environment table', () => { describe('Environment table', () => {
let Component; let Component;
......
import _ from 'underscore'; import _ from 'underscore';
import Vue from 'vue'; import Vue from 'vue';
import environmentsComponent from '~/environments/components/environments_app.vue'; import environmentsComponent from '~/environments/components/environments_app.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { headersInterceptor } from 'spec/helpers/vue_resource_helper';
import { environment, folder } from './mock_data'; import { environment, folder } from './mock_data';
import { headersInterceptor } from '../helpers/vue_resource_helper';
import mountComponent from '../helpers/vue_mount_component_helper';
describe('Environment', () => { describe('Environment', () => {
const mockData = { const mockData = {
......
import _ from 'underscore'; import _ from 'underscore';
import Vue from 'vue'; import Vue from 'vue';
import environmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue'; import environmentsFolderViewComponent from '~/environments/folder/environments_folder_view.vue';
import { headersInterceptor } from 'spec/helpers/vue_resource_helper';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { environmentsList } from '../mock_data'; import { environmentsList } from '../mock_data';
import { headersInterceptor } from '../../helpers/vue_resource_helper';
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('Environments Folder View', () => { describe('Environments Folder View', () => {
let Component; let Component;
......
import Vue from 'vue'; import Vue from 'vue';
import epicHeader from 'ee/epics/epic_show/components/epic_header.vue'; import epicHeader from 'ee/epics/epic_show/components/epic_header.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { headerProps } from '../mock_data'; import { headerProps } from '../mock_data';
describe('epicHeader', () => { describe('epicHeader', () => {
......
...@@ -7,9 +7,9 @@ import epicSidebar from 'ee/epics/sidebar/components/sidebar_app.vue'; ...@@ -7,9 +7,9 @@ import epicSidebar from 'ee/epics/sidebar/components/sidebar_app.vue';
import issuableApp from '~/issue_show/components/app.vue'; import issuableApp from '~/issue_show/components/app.vue';
import issuableAppEventHub from '~/issue_show/event_hub'; import issuableAppEventHub from '~/issue_show/event_hub';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import issueShowData from 'spec/issue_show/mock_data';
import { props } from '../mock_data'; import { props } from '../mock_data';
import issueShowData from '../../../issue_show/mock_data';
describe('EpicShowApp', () => { describe('EpicShowApp', () => {
let mock; let mock;
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import _ from 'underscore'; import _ from 'underscore';
import newEpic from 'ee/epics/new_epic/components/new_epic.vue'; import newEpic from 'ee/epics/new_epic/components/new_epic.vue';
import * as urlUtility from '~/lib/utils/url_utility'; import * as urlUtility from '~/lib/utils/url_utility';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('newEpic', () => { describe('newEpic', () => {
let vm; let vm;
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import _ from 'underscore'; import _ from 'underscore';
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import epicSidebar from 'ee/epics/sidebar/components/sidebar_app.vue'; import epicSidebar from 'ee/epics/sidebar/components/sidebar_app.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('epicSidebar', () => { describe('epicSidebar', () => {
let vm; let vm;
......
...@@ -8,7 +8,7 @@ import { ...@@ -8,7 +8,7 @@ import {
mouseenter, mouseenter,
inserted, inserted,
} from '~/feature_highlight/feature_highlight_helper'; } from '~/feature_highlight/feature_highlight_helper';
import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
describe('feature highlight helper', () => { describe('feature highlight helper', () => {
describe('getSelector', () => { describe('getSelector', () => {
......
...@@ -6,10 +6,9 @@ import appComponent from 'ee/geo_nodes/components/app.vue'; ...@@ -6,10 +6,9 @@ import appComponent from 'ee/geo_nodes/components/app.vue';
import eventHub from 'ee/geo_nodes/event_hub'; import eventHub from 'ee/geo_nodes/event_hub';
import GeoNodesStore from 'ee/geo_nodes/store/geo_nodes_store'; import GeoNodesStore from 'ee/geo_nodes/store/geo_nodes_store';
import GeoNodesService from 'ee/geo_nodes/service/geo_nodes_service'; import GeoNodesService from 'ee/geo_nodes/service/geo_nodes_service';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { PRIMARY_VERSION, NODE_DETAILS_PATH, mockNodes, rawMockNodeDetails } from '../mock_data'; import { PRIMARY_VERSION, NODE_DETAILS_PATH, mockNodes, rawMockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = () => { const createComponent = () => {
const Component = Vue.extend(appComponent); const Component = Vue.extend(appComponent);
const store = new GeoNodesStore(PRIMARY_VERSION.version, PRIMARY_VERSION.revision); const store = new GeoNodesStore(PRIMARY_VERSION.version, PRIMARY_VERSION.revision);
......
import Vue from 'vue'; import Vue from 'vue';
import geoNodeActionsComponent from 'ee/geo_nodes/components/geo_node_actions.vue'; import geoNodeActionsComponent from 'ee/geo_nodes/components/geo_node_actions.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockNodes } from '../mock_data'; import { mockNodes } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (node = mockNodes[0], nodeEditAllowed = true, nodeMissingOauth = false) => { const createComponent = (node = mockNodes[0], nodeEditAllowed = true, nodeMissingOauth = false) => {
const Component = Vue.extend(geoNodeActionsComponent); const Component = Vue.extend(geoNodeActionsComponent);
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import geoNodeDetailItemComponent from 'ee/geo_nodes/components/geo_node_detail_item.vue'; import geoNodeDetailItemComponent from 'ee/geo_nodes/components/geo_node_detail_item.vue';
import { VALUE_TYPE, CUSTOM_TYPE } from 'ee/geo_nodes/constants'; import { VALUE_TYPE, CUSTOM_TYPE } from 'ee/geo_nodes/constants';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { rawMockNodeDetails } from '../mock_data'; import { rawMockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (config) => { const createComponent = (config) => {
const Component = Vue.extend(geoNodeDetailItemComponent); const Component = Vue.extend(geoNodeDetailItemComponent);
const defaultConfig = Object.assign({ const defaultConfig = Object.assign({
......
import Vue from 'vue'; import Vue from 'vue';
import geoNodeDetailsComponent from 'ee/geo_nodes/components/geo_node_details.vue'; import geoNodeDetailsComponent from 'ee/geo_nodes/components/geo_node_details.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockNodes, mockNodeDetails } from '../mock_data'; import { mockNodes, mockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (nodeDetails = mockNodeDetails) => { const createComponent = (nodeDetails = mockNodeDetails) => {
const Component = Vue.extend(geoNodeDetailsComponent); const Component = Vue.extend(geoNodeDetailsComponent);
......
import Vue from 'vue'; import Vue from 'vue';
import geoNodeEventStatusComponent from 'ee/geo_nodes/components/geo_node_event_status.vue'; import geoNodeEventStatusComponent from 'ee/geo_nodes/components/geo_node_event_status.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockNodeDetails } from '../mock_data'; import { mockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ( const createComponent = (
eventId = mockNodeDetails.lastEvent.id, eventId = mockNodeDetails.lastEvent.id,
eventTimeStamp = mockNodeDetails.lastEvent.timeStamp, eventTimeStamp = mockNodeDetails.lastEvent.timeStamp,
......
import Vue from 'vue'; import Vue from 'vue';
import geoNodeHealthStatusComponent from 'ee/geo_nodes/components/geo_node_health_status.vue'; import geoNodeHealthStatusComponent from 'ee/geo_nodes/components/geo_node_health_status.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockNodeDetails } from '../mock_data'; import { mockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (status = mockNodeDetails.health) => { const createComponent = (status = mockNodeDetails.health) => {
const Component = Vue.extend(geoNodeHealthStatusComponent); const Component = Vue.extend(geoNodeHealthStatusComponent);
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import geoNodeItemComponent from 'ee/geo_nodes/components/geo_node_item.vue'; import geoNodeItemComponent from 'ee/geo_nodes/components/geo_node_item.vue';
import eventHub from 'ee/geo_nodes/event_hub'; import eventHub from 'ee/geo_nodes/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockNodes, mockNodeDetails } from '../mock_data'; import { mockNodes, mockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (node = mockNodes[0]) => { const createComponent = (node = mockNodes[0]) => {
const Component = Vue.extend(geoNodeItemComponent); const Component = Vue.extend(geoNodeItemComponent);
......
import Vue from 'vue'; import Vue from 'vue';
import geoNodeSyncSettingsComponent from 'ee/geo_nodes/components/geo_node_sync_settings.vue'; import geoNodeSyncSettingsComponent from 'ee/geo_nodes/components/geo_node_sync_settings.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockNodeDetails } from '../mock_data'; import { mockNodeDetails } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ( const createComponent = (
selectiveSyncType = mockNodeDetails.selectiveSyncType, selectiveSyncType = mockNodeDetails.selectiveSyncType,
lastEvent = mockNodeDetails.lastEvent, lastEvent = mockNodeDetails.lastEvent,
......
import Vue from 'vue'; import Vue from 'vue';
import geoNodesListComponent from 'ee/geo_nodes/components/geo_nodes_list.vue'; import geoNodesListComponent from 'ee/geo_nodes/components/geo_nodes_list.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockNodes } from '../mock_data'; import { mockNodes } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = () => { const createComponent = () => {
const Component = Vue.extend(geoNodesListComponent); const Component = Vue.extend(geoNodesListComponent);
......
...@@ -3,10 +3,9 @@ import * as urlUtils from '~/lib/utils/url_utility'; ...@@ -3,10 +3,9 @@ import * as urlUtils from '~/lib/utils/url_utility';
import groupItemComponent from '~/groups/components/group_item.vue'; import groupItemComponent from '~/groups/components/group_item.vue';
import groupFolderComponent from '~/groups/components/group_folder.vue'; import groupFolderComponent from '~/groups/components/group_folder.vue';
import eventHub from '~/groups/event_hub'; import eventHub from '~/groups/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockParentGroupItem, mockChildren } from '../mock_data'; import { mockParentGroupItem, mockChildren } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (group = mockParentGroupItem, parentGroup = mockChildren[0]) => { const createComponent = (group = mockParentGroupItem, parentGroup = mockChildren[0]) => {
const Component = Vue.extend(groupItemComponent); const Component = Vue.extend(groupItemComponent);
......
...@@ -4,10 +4,9 @@ import groupsComponent from '~/groups/components/groups.vue'; ...@@ -4,10 +4,9 @@ import groupsComponent from '~/groups/components/groups.vue';
import groupFolderComponent from '~/groups/components/group_folder.vue'; import groupFolderComponent from '~/groups/components/group_folder.vue';
import groupItemComponent from '~/groups/components/group_item.vue'; import groupItemComponent from '~/groups/components/group_item.vue';
import eventHub from '~/groups/event_hub'; import eventHub from '~/groups/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockGroups, mockPageInfo } from '../mock_data'; import { mockGroups, mockPageInfo } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (searchEmpty = false) => { const createComponent = (searchEmpty = false) => {
const Component = Vue.extend(groupsComponent); const Component = Vue.extend(groupsComponent);
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import itemActionsComponent from '~/groups/components/item_actions.vue'; import itemActionsComponent from '~/groups/components/item_actions.vue';
import eventHub from '~/groups/event_hub'; import eventHub from '~/groups/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockParentGroupItem, mockChildren } from '../mock_data'; import { mockParentGroupItem, mockChildren } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (group = mockParentGroupItem, parentGroup = mockChildren[0]) => { const createComponent = (group = mockParentGroupItem, parentGroup = mockChildren[0]) => {
const Component = Vue.extend(itemActionsComponent); const Component = Vue.extend(itemActionsComponent);
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import itemCaretComponent from '~/groups/components/item_caret.vue'; import itemCaretComponent from '~/groups/components/item_caret.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const createComponent = (isGroupOpen = false) => { const createComponent = (isGroupOpen = false) => {
const Component = Vue.extend(itemCaretComponent); const Component = Vue.extend(itemCaretComponent);
......
import Vue from 'vue'; import Vue from 'vue';
import itemStatsComponent from '~/groups/components/item_stats.vue'; import itemStatsComponent from '~/groups/components/item_stats.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { import {
mockParentGroupItem, mockParentGroupItem,
ITEM_TYPE, ITEM_TYPE,
...@@ -9,8 +10,6 @@ import { ...@@ -9,8 +10,6 @@ import {
PROJECT_VISIBILITY_TYPE, PROJECT_VISIBILITY_TYPE,
} from '../mock_data'; } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (item = mockParentGroupItem) => { const createComponent = (item = mockParentGroupItem) => {
const Component = Vue.extend(itemStatsComponent); const Component = Vue.extend(itemStatsComponent);
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import itemStatsValueComponent from '~/groups/components/item_stats_value.vue'; import itemStatsValueComponent from '~/groups/components/item_stats_value.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const createComponent = ({ title, cssClass, iconName, tooltipPlacement, value }) => { const createComponent = ({ title, cssClass, iconName, tooltipPlacement, value }) => {
const Component = Vue.extend(itemStatsValueComponent); const Component = Vue.extend(itemStatsValueComponent);
......
import Vue from 'vue'; import Vue from 'vue';
import itemTypeIconComponent from '~/groups/components/item_type_icon.vue'; import itemTypeIconComponent from '~/groups/components/item_type_icon.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { ITEM_TYPE } from '../mock_data'; import { ITEM_TYPE } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (itemType = ITEM_TYPE.GROUP, isGroupOpen = false) => { const createComponent = (itemType = ITEM_TYPE.GROUP, isGroupOpen = false) => {
const Component = Vue.extend(itemTypeIconComponent); const Component = Vue.extend(itemTypeIconComponent);
......
import Vue from 'vue'; import Vue from 'vue';
import eventHub from '~/issuable/related_issues/event_hub'; import eventHub from 'ee/issuable/related_issues/event_hub';
import addIssuableForm from '~/issuable/related_issues/components/add_issuable_form.vue'; import addIssuableForm from 'ee/issuable/related_issues/components/add_issuable_form.vue';
const issuable1 = { const issuable1 = {
id: 200, id: 200,
......
import Vue from 'vue'; import Vue from 'vue';
import issueItem from '~/issuable/related_issues/components/issue_item.vue'; import issueItem from 'ee/issuable/related_issues/components/issue_item.vue';
import eventHub from '~/issuable/related_issues/event_hub'; import eventHub from 'ee/issuable/related_issues/event_hub';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('issueItem', () => { describe('issueItem', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import eventHub from '~/issuable/related_issues/event_hub'; import eventHub from 'ee/issuable/related_issues/event_hub';
import issueToken from '~/issuable/related_issues/components/issue_token.vue'; import issueToken from 'ee/issuable/related_issues/components/issue_token.vue';
describe('IssueToken', () => { describe('IssueToken', () => {
const idKey = 200; const idKey = 200;
......
import Vue from 'vue'; import Vue from 'vue';
import eventHub from '~/issuable/related_issues/event_hub'; import eventHub from 'ee/issuable/related_issues/event_hub';
import relatedIssuesBlock from '~/issuable/related_issues/components/related_issues_block.vue'; import relatedIssuesBlock from 'ee/issuable/related_issues/components/related_issues_block.vue';
import { issuable1, issuable2, issuable3, issuable4, issuable5 } from '../mock_data'; import { issuable1, issuable2, issuable3, issuable4, issuable5 } from '../mock_data';
......
import Vue from 'vue'; import Vue from 'vue';
import _ from 'underscore'; import _ from 'underscore';
import relatedIssuesRoot from '~/issuable/related_issues/components/related_issues_root.vue'; import relatedIssuesRoot from 'ee/issuable/related_issues/components/related_issues_root.vue';
import relatedIssuesService from '~/issuable/related_issues/services/related_issues_service'; import relatedIssuesService from 'ee/issuable/related_issues/services/related_issues_service';
import { defaultProps, issuable1, issuable2 } from '../mock_data'; import { defaultProps, issuable1, issuable2 } from '../mock_data';
......
import RelatedIssuesStore from '~/issuable/related_issues/stores/related_issues_store'; import RelatedIssuesStore from 'ee/issuable/related_issues/stores/related_issues_store';
import { issuable1, issuable2, issuable3, issuable4, issuable5 } from '../mock_data'; import { issuable1, issuable2, issuable3, issuable4, issuable5 } from '../mock_data';
......
...@@ -6,8 +6,8 @@ import '~/render_gfm'; ...@@ -6,8 +6,8 @@ import '~/render_gfm';
import * as urlUtils from '~/lib/utils/url_utility'; import * as urlUtils from '~/lib/utils/url_utility';
import issuableApp from '~/issue_show/components/app.vue'; import issuableApp from '~/issue_show/components/app.vue';
import eventHub from '~/issue_show/event_hub'; import eventHub from '~/issue_show/event_hub';
import setTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
import issueShowData from '../mock_data'; import issueShowData from '../mock_data';
import setTimeoutPromise from '../../helpers/set_timeout_promise_helper';
function formatText(text) { function formatText(text) {
return text.trim().replace(/\s\s+/g, ' '); return text.trim().replace(/\s\s+/g, ' ');
......
import Vue from 'vue'; import Vue from 'vue';
import descriptionComponent from '~/issue_show/components/description.vue'; import descriptionComponent from '~/issue_show/components/description.vue';
import * as taskList from '~/task_list'; import * as taskList from '~/task_list';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Description component', () => { describe('Description component', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import headerComponent from '~/jobs/components/header.vue'; import headerComponent from '~/jobs/components/header.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Job details header', () => { describe('Job details header', () => {
let HeaderComponent; let HeaderComponent;
......
...@@ -4,7 +4,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -4,7 +4,7 @@ import axios from '~/lib/utils/axios_utils';
import stopJobsModal from '~/pages/admin/jobs/index/components/stop_jobs_modal.vue'; import stopJobsModal from '~/pages/admin/jobs/index/components/stop_jobs_modal.vue';
import * as urlUtility from '~/lib/utils/url_utility'; import * as urlUtility from '~/lib/utils/url_utility';
import mountComponent from '../../../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('stop_jobs_modal.vue', () => { describe('stop_jobs_modal.vue', () => {
const props = { const props = {
......
...@@ -5,7 +5,7 @@ import deleteMilestoneModal from '~/pages/milestones/shared/components/delete_mi ...@@ -5,7 +5,7 @@ import deleteMilestoneModal from '~/pages/milestones/shared/components/delete_mi
import eventHub from '~/pages/milestones/shared/event_hub'; import eventHub from '~/pages/milestones/shared/event_hub';
import * as urlUtility from '~/lib/utils/url_utility'; import * as urlUtility from '~/lib/utils/url_utility';
import mountComponent from '../../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('delete_milestone_modal.vue', () => { describe('delete_milestone_modal.vue', () => {
const Component = Vue.extend(deleteMilestoneModal); const Component = Vue.extend(deleteMilestoneModal);
......
import Vue from 'vue'; import Vue from 'vue';
import jobComponent from '~/pipelines/components/graph/job_component.vue'; import jobComponent from '~/pipelines/components/graph/job_component.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('pipeline graph job component', () => { describe('pipeline graph job component', () => {
let JobComponent; let JobComponent;
......
import Vue from 'vue'; import Vue from 'vue';
import LinkedPipelineComponent from '~/pipelines/components/graph/linked_pipeline.vue'; import LinkedPipelineComponent from 'ee/pipelines/components/graph/linked_pipeline.vue';
import mockData from './linked_pipelines_mock_data'; import mockData from './linked_pipelines_mock_data';
const LinkedPipeline = Vue.extend(LinkedPipelineComponent); const LinkedPipeline = Vue.extend(LinkedPipelineComponent);
......
import Vue from 'vue'; import Vue from 'vue';
import LinkedPipelinesColumn from '~/pipelines/components/graph/linked_pipelines_column.vue'; import LinkedPipelinesColumn from 'ee/pipelines/components/graph/linked_pipelines_column.vue';
import mockData from './linked_pipelines_mock_data'; import mockData from './linked_pipelines_mock_data';
const LinkedPipelinesColumnComponent = Vue.extend(LinkedPipelinesColumn); const LinkedPipelinesColumnComponent = Vue.extend(LinkedPipelinesColumn);
......
...@@ -2,7 +2,7 @@ import _ from 'underscore'; ...@@ -2,7 +2,7 @@ import _ from 'underscore';
import Vue from 'vue'; import Vue from 'vue';
import pipelinesComp from '~/pipelines/components/pipelines.vue'; import pipelinesComp from '~/pipelines/components/pipelines.vue';
import Store from '~/pipelines/stores/pipelines_store'; import Store from '~/pipelines/stores/pipelines_store';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Pipelines', () => { describe('Pipelines', () => {
const jsonFixtureName = 'pipelines/pipelines.json'; const jsonFixtureName = 'pipelines/pipelines.json';
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import deleteAccountModal from '~/profile/account/components/delete_account_modal.vue'; import deleteAccountModal from '~/profile/account/components/delete_account_modal.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('DeleteAccountModal component', () => { describe('DeleteAccountModal component', () => {
const actionUrl = `${gl.TEST_HOST}/delete/user`; const actionUrl = `${gl.TEST_HOST}/delete/user`;
......
import Vue from 'vue'; import Vue from 'vue';
import eventHub from '~/projects/settings_service_desk/event_hub'; import eventHub from 'ee/projects/settings_service_desk/event_hub';
import serviceDeskSetting from '~/projects/settings_service_desk/components/service_desk_setting.vue'; import serviceDeskSetting from 'ee/projects/settings_service_desk/components/service_desk_setting.vue';
describe('ServiceDeskSetting', () => { describe('ServiceDeskSetting', () => {
let ServiceDeskSetting; let ServiceDeskSetting;
......
import ServiceDeskStore from '~/projects/settings_service_desk/stores/service_desk_store'; import ServiceDeskStore from 'ee/projects/settings_service_desk/stores/service_desk_store';
describe('ServiceDeskStore', () => { describe('ServiceDeskStore', () => {
let store; let store;
......
...@@ -6,7 +6,7 @@ import eventHub from '~/projects_dropdown/event_hub'; ...@@ -6,7 +6,7 @@ import eventHub from '~/projects_dropdown/event_hub';
import ProjectsStore from '~/projects_dropdown/store/projects_store'; import ProjectsStore from '~/projects_dropdown/store/projects_store';
import ProjectsService from '~/projects_dropdown/service/projects_service'; import ProjectsService from '~/projects_dropdown/service/projects_service';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { currentSession, mockProject, mockRawProject } from '../mock_data'; import { currentSession, mockProject, mockRawProject } from '../mock_data';
const createComponent = () => { const createComponent = () => {
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import projectsListFrequentComponent from '~/projects_dropdown/components/projects_list_frequent.vue'; import projectsListFrequentComponent from '~/projects_dropdown/components/projects_list_frequent.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockFrequents } from '../mock_data'; import { mockFrequents } from '../mock_data';
const createComponent = () => { const createComponent = () => {
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import projectsListItemComponent from '~/projects_dropdown/components/projects_list_item.vue'; import projectsListItemComponent from '~/projects_dropdown/components/projects_list_item.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockProject } from '../mock_data'; import { mockProject } from '../mock_data';
const createComponent = () => { const createComponent = () => {
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import projectsListSearchComponent from '~/projects_dropdown/components/projects_list_search.vue'; import projectsListSearchComponent from '~/projects_dropdown/components/projects_list_search.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockProject } from '../mock_data'; import { mockProject } from '../mock_data';
const createComponent = () => { const createComponent = () => {
......
...@@ -3,7 +3,7 @@ import Vue from 'vue'; ...@@ -3,7 +3,7 @@ import Vue from 'vue';
import searchComponent from '~/projects_dropdown/components/search.vue'; import searchComponent from '~/projects_dropdown/components/search.vue';
import eventHub from '~/projects_dropdown/event_hub'; import eventHub from '~/projects_dropdown/event_hub';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const createComponent = () => { const createComponent = () => {
const Component = Vue.extend(searchComponent); const Component = Vue.extend(searchComponent);
......
import _ from 'underscore'; import _ from 'underscore';
import Vue from 'vue'; import Vue from 'vue';
import registry from '~/registry/components/app.vue'; import registry from '~/registry/components/app.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { reposServerResponse } from '../mock_data'; import { reposServerResponse } from '../mock_data';
describe('Registry List', () => { describe('Registry List', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import changedFileIcon from '~/ide/components/changed_file_icon.vue'; import changedFileIcon from 'ee/ide/components/changed_file_icon.vue';
import createComponent from '../../helpers/vue_mount_component_helper'; import createComponent from 'spec/helpers/vue_mount_component_helper';
describe('IDE changed file icon', () => { describe('IDE changed file icon', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue'; import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue';
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor commit sidebar list collapsed', () => { describe('Multi-file editor commit sidebar list collapsed', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import listItem from '~/ide/components/commit_sidebar/list_item.vue'; import listItem from '~/ide/components/commit_sidebar/list_item.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor commit sidebar list item', () => { describe('Multi-file editor commit sidebar list item', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import commitSidebarList from '~/ide/components/commit_sidebar/list.vue'; import commitSidebarList from '~/ide/components/commit_sidebar/list.vue';
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file } from '../../helpers'; import { file } from '../../helpers';
describe('Multi-file editor commit sidebar list', () => { describe('Multi-file editor commit sidebar list', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import ideContextBar from '~/ide/components/ide_context_bar.vue'; import ideContextBar from '~/ide/components/ide_context_bar.vue';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
describe('Multi-file editor right context bar', () => { describe('Multi-file editor right context bar', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import ideSidebar from '~/ide/components/ide_side_bar.vue'; import ideSidebar from '~/ide/components/ide_side_bar.vue';
import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from '../helpers'; import { resetStore } from '../helpers';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper';
describe('IdeSidebar', () => { describe('IdeSidebar', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import ide from '~/ide/components/ide.vue'; import ide from '~/ide/components/ide.vue';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
describe('ide component', () => { describe('ide component', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import newBranchForm from '~/ide/components/new_branch_form.vue'; import newBranchForm from '~/ide/components/new_branch_form.vue';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from '../helpers'; import { resetStore } from '../helpers';
describe('Multi-file editor new branch form', () => { describe('Multi-file editor new branch form', () => {
......
import Vue from 'vue'; import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import newDropdown from '~/ide/components/new_dropdown/index.vue'; import newDropdown from '~/ide/components/new_dropdown/index.vue';
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from '../../helpers'; import { resetStore } from '../../helpers';
describe('new dropdown component', () => { describe('new dropdown component', () => {
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import service from '~/ide/services'; import service from '~/ide/services';
import modal from '~/ide/components/new_dropdown/modal.vue'; import modal from '~/ide/components/new_dropdown/modal.vue';
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { file, resetStore } from '../../helpers'; import { file, resetStore } from '../../helpers';
describe('new file modal component', () => { describe('new file modal component', () => {
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import upload from '~/ide/components/new_dropdown/upload.vue'; import upload from '~/ide/components/new_dropdown/upload.vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import service from '~/ide/services'; import service from '~/ide/services';
import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { resetStore } from '../../helpers'; import { resetStore } from '../../helpers';
describe('new dropdown upload', () => { describe('new dropdown upload', () => {
......
...@@ -2,8 +2,8 @@ import Vue from 'vue'; ...@@ -2,8 +2,8 @@ import Vue from 'vue';
import store from '~/ide/stores'; import store from '~/ide/stores';
import service from '~/ide/services'; import service from '~/ide/services';
import repoCommitSection from '~/ide/components/repo_commit_section.vue'; import repoCommitSection from '~/ide/components/repo_commit_section.vue';
import getSetTimeoutPromise from '../../helpers/set_timeout_promise_helper'; import { createComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import { createComponentWithStore } from '../../helpers/vue_mount_component_helper'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
import { file, resetStore } from '../helpers'; import { file, resetStore } from '../helpers';
describe('RepoCommitSection', () => { describe('RepoCommitSection', () => {
......
...@@ -7,10 +7,9 @@ import appComponent from 'ee/roadmap/components/app.vue'; ...@@ -7,10 +7,9 @@ import appComponent from 'ee/roadmap/components/app.vue';
import RoadmapStore from 'ee/roadmap/store/roadmap_store'; import RoadmapStore from 'ee/roadmap/store/roadmap_store';
import RoadmapService from 'ee/roadmap/service/roadmap_service'; import RoadmapService from 'ee/roadmap/service/roadmap_service';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframe, mockGroupId, epicsPath, rawEpics, mockSvgPath } from '../mock_data'; import { mockTimeframe, mockGroupId, epicsPath, rawEpics, mockSvgPath } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = () => { const createComponent = () => {
const Component = Vue.extend(appComponent); const Component = Vue.extend(appComponent);
const timeframe = mockTimeframe; const timeframe = mockTimeframe;
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import epicItemDetailsComponent from 'ee/roadmap/components/epic_item_details.vue'; import epicItemDetailsComponent from 'ee/roadmap/components/epic_item_details.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockGroupId, mockEpic } from '../mock_data'; import { mockGroupId, mockEpic } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = (epic = mockEpic, currentGroupId = mockGroupId) => { const createComponent = (epic = mockEpic, currentGroupId = mockGroupId) => {
const Component = Vue.extend(epicItemDetailsComponent); const Component = Vue.extend(epicItemDetailsComponent);
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import epicItemComponent from 'ee/roadmap/components/epic_item.vue'; import epicItemComponent from 'ee/roadmap/components/epic_item.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframe, mockEpic, mockGroupId, mockShellWidth } from '../mock_data'; import { mockTimeframe, mockEpic, mockGroupId, mockShellWidth } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ({ const createComponent = ({
epic = mockEpic, epic = mockEpic,
timeframe = mockTimeframe, timeframe = mockTimeframe,
......
...@@ -3,10 +3,9 @@ import Vue from 'vue'; ...@@ -3,10 +3,9 @@ import Vue from 'vue';
import epicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue'; import epicItemTimelineComponent from 'ee/roadmap/components/epic_item_timeline.vue';
import { TIMELINE_CELL_MIN_WIDTH, TIMELINE_END_OFFSET_FULL, TIMELINE_END_OFFSET_HALF } from 'ee/roadmap/constants'; import { TIMELINE_CELL_MIN_WIDTH, TIMELINE_END_OFFSET_FULL, TIMELINE_END_OFFSET_HALF } from 'ee/roadmap/constants';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframe, mockEpic, mockShellWidth } from '../mock_data'; import { mockTimeframe, mockEpic, mockShellWidth } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ({ const createComponent = ({
timeframe = mockTimeframe, timeframe = mockTimeframe,
timeframeItem = mockTimeframe[0], timeframeItem = mockTimeframe[0],
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import epicsListEmptyComponent from 'ee/roadmap/components/epics_list_empty.vue'; import epicsListEmptyComponent from 'ee/roadmap/components/epics_list_empty.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframe, mockSvgPath } from '../mock_data'; import { mockTimeframe, mockSvgPath } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = () => { const createComponent = () => {
const Component = Vue.extend(epicsListEmptyComponent); const Component = Vue.extend(epicsListEmptyComponent);
......
...@@ -3,10 +3,9 @@ import Vue from 'vue'; ...@@ -3,10 +3,9 @@ import Vue from 'vue';
import epicsListSectionComponent from 'ee/roadmap/components/epics_list_section.vue'; import epicsListSectionComponent from 'ee/roadmap/components/epics_list_section.vue';
import RoadmapStore from 'ee/roadmap/store/roadmap_store'; import RoadmapStore from 'ee/roadmap/store/roadmap_store';
import eventHub from 'ee/roadmap/event_hub'; import eventHub from 'ee/roadmap/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { rawEpics, mockTimeframe, mockGroupId, mockShellWidth } from '../mock_data'; import { rawEpics, mockTimeframe, mockGroupId, mockShellWidth } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const store = new RoadmapStore(mockGroupId, mockTimeframe); const store = new RoadmapStore(mockGroupId, mockTimeframe);
store.setEpics(rawEpics); store.setEpics(rawEpics);
const mockEpics = store.getEpics(); const mockEpics = store.getEpics();
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import roadmapShellComponent from 'ee/roadmap/components/roadmap_shell.vue'; import roadmapShellComponent from 'ee/roadmap/components/roadmap_shell.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockEpic, mockTimeframe, mockGroupId } from '../mock_data'; import { mockEpic, mockTimeframe, mockGroupId } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ({ const createComponent = ({
epics = [mockEpic], epics = [mockEpic],
timeframe = mockTimeframe, timeframe = mockTimeframe,
......
...@@ -3,10 +3,9 @@ import Vue from 'vue'; ...@@ -3,10 +3,9 @@ import Vue from 'vue';
import roadmapTimelineSectionComponent from 'ee/roadmap/components/roadmap_timeline_section.vue'; import roadmapTimelineSectionComponent from 'ee/roadmap/components/roadmap_timeline_section.vue';
import eventHub from 'ee/roadmap/event_hub'; import eventHub from 'ee/roadmap/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockEpic, mockTimeframe, mockShellWidth } from '../mock_data'; import { mockEpic, mockTimeframe, mockShellWidth } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ({ const createComponent = ({
epics = [mockEpic], epics = [mockEpic],
timeframe = mockTimeframe, timeframe = mockTimeframe,
......
...@@ -3,10 +3,9 @@ import Vue from 'vue'; ...@@ -3,10 +3,9 @@ import Vue from 'vue';
import timelineHeaderItemComponent from 'ee/roadmap/components/timeline_header_item.vue'; import timelineHeaderItemComponent from 'ee/roadmap/components/timeline_header_item.vue';
import { TIMELINE_CELL_MIN_WIDTH } from 'ee/roadmap/constants'; import { TIMELINE_CELL_MIN_WIDTH } from 'ee/roadmap/constants';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframe, mockShellWidth } from '../mock_data'; import { mockTimeframe, mockShellWidth } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const mockTimeframeIndex = 0; const mockTimeframeIndex = 0;
const createComponent = ({ const createComponent = ({
......
...@@ -2,10 +2,9 @@ import Vue from 'vue'; ...@@ -2,10 +2,9 @@ import Vue from 'vue';
import timelineHeaderSubItemComponent from 'ee/roadmap/components/timeline_header_sub_item.vue'; import timelineHeaderSubItemComponent from 'ee/roadmap/components/timeline_header_sub_item.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframe } from '../mock_data'; import { mockTimeframe } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const createComponent = ({ const createComponent = ({
currentDate = mockTimeframe[0], currentDate = mockTimeframe[0],
timeframeItem = mockTimeframe[0], timeframeItem = mockTimeframe[0],
......
...@@ -3,10 +3,9 @@ import Vue from 'vue'; ...@@ -3,10 +3,9 @@ import Vue from 'vue';
import timelineTodayIndicatorComponent from 'ee/roadmap/components/timeline_today_indicator.vue'; import timelineTodayIndicatorComponent from 'ee/roadmap/components/timeline_today_indicator.vue';
import eventHub from 'ee/roadmap/event_hub'; import eventHub from 'ee/roadmap/event_hub';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { mockTimeframe } from '../mock_data'; import { mockTimeframe } from '../mock_data';
import mountComponent from '../../helpers/vue_mount_component_helper';
const mockCurrentDate = new Date( const mockCurrentDate = new Date(
mockTimeframe[0].getFullYear(), mockTimeframe[0].getFullYear(),
mockTimeframe[0].getMonth(), mockTimeframe[0].getMonth(),
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import CESidebarStore from '~/sidebar/stores/sidebar_store'; import CESidebarStore from '~/sidebar/stores/sidebar_store';
import SidebarStore from 'ee/sidebar/stores/sidebar_store'; import SidebarStore from 'ee/sidebar/stores/sidebar_store';
import sidebarItemEpic from 'ee/sidebar/components/sidebar_item_epic.vue'; import sidebarItemEpic from 'ee/sidebar/components/sidebar_item_epic.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('sidebarItemEpic', () => { describe('sidebarItemEpic', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import editFormButtons from '~/sidebar/components/lock/edit_form_buttons.vue'; import editFormButtons from '~/sidebar/components/lock/edit_form_buttons.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('EditFormButtons', () => { describe('EditFormButtons', () => {
let vm1; let vm1;
......
import Vue from 'vue'; import Vue from 'vue';
import participants from '~/sidebar/components/participants/participants.vue'; import participants from '~/sidebar/components/participants/participants.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const PARTICIPANT = { const PARTICIPANT = {
id: 1, id: 1,
......
...@@ -4,8 +4,8 @@ import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees'; ...@@ -4,8 +4,8 @@ import SidebarAssignees from '~/sidebar/components/assignees/sidebar_assignees';
import SidebarMediator from '~/sidebar/sidebar_mediator'; import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarService from '~/sidebar/services/sidebar_service'; import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarStore from '~/sidebar/stores/sidebar_store'; import SidebarStore from '~/sidebar/stores/sidebar_store';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import Mock from './mock_data'; import Mock from './mock_data';
import mountComponent from '../helpers/vue_mount_component_helper';
describe('sidebar assignees', () => { describe('sidebar assignees', () => {
let vm; let vm;
......
...@@ -4,7 +4,7 @@ import SidebarMediator from '~/sidebar/sidebar_mediator'; ...@@ -4,7 +4,7 @@ import SidebarMediator from '~/sidebar/sidebar_mediator';
import SidebarService from '~/sidebar/services/sidebar_service'; import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarStore from '~/sidebar/stores/sidebar_store'; import SidebarStore from '~/sidebar/stores/sidebar_store';
import eventHub from '~/sidebar/event_hub'; import eventHub from '~/sidebar/event_hub';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import Mock from './mock_data'; import Mock from './mock_data';
describe('Sidebar Subscriptions', function () { describe('Sidebar Subscriptions', function () {
......
...@@ -4,7 +4,7 @@ import SidebarMediator from 'ee/sidebar/sidebar_mediator'; ...@@ -4,7 +4,7 @@ import SidebarMediator from 'ee/sidebar/sidebar_mediator';
import SidebarService from '~/sidebar/services/sidebar_service'; import SidebarService from '~/sidebar/services/sidebar_service';
import SidebarStore from 'ee/sidebar/stores/sidebar_store'; import SidebarStore from 'ee/sidebar/stores/sidebar_store';
import eventHub from '~/sidebar/event_hub'; import eventHub from '~/sidebar/event_hub';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import Mock from './ee_mock_data'; import Mock from './ee_mock_data';
describe('Sidebar Weight', function () { describe('Sidebar Weight', function () {
......
import Vue from 'vue'; import Vue from 'vue';
import subscriptions from '~/sidebar/components/subscriptions/subscriptions.vue'; import subscriptions from '~/sidebar/components/subscriptions/subscriptions.vue';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Subscriptions', function () { describe('Subscriptions', function () {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import weight from 'ee/sidebar/components/weight/weight.vue'; import weight from 'ee/sidebar/components/weight/weight.vue';
import eventHub from '~/sidebar/event_hub'; import eventHub from '~/sidebar/event_hub';
import mountComponent from '../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import getSetTimeoutPromise from '../helpers/set_timeout_promise_helper'; import getSetTimeoutPromise from 'spec/helpers/set_timeout_promise_helper';
const DEFAULT_PROPS = { const DEFAULT_PROPS = {
weightOptions: ['No Weight', 1, 2, 3], weightOptions: ['No Weight', 1, 2, 3],
......
import Vue from 'vue'; import Vue from 'vue';
import authorComponent from '~/vue_merge_request_widget/components/mr_widget_author.vue'; import authorComponent from '~/vue_merge_request_widget/components/mr_widget_author.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetAuthor', () => { describe('MRWidgetAuthor', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import authorTimeComponent from '~/vue_merge_request_widget/components/mr_widget_author_time.vue'; import authorTimeComponent from '~/vue_merge_request_widget/components/mr_widget_author_time.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetAuthorTime', () => { describe('MRWidgetAuthorTime', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import headerComponent from '~/vue_merge_request_widget/components/mr_widget_header.vue'; import headerComponent from '~/vue_merge_request_widget/components/mr_widget_header.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetHeader', () => { describe('MRWidgetHeader', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import mergeHelpComponent from '~/vue_merge_request_widget/components/mr_widget_merge_help.vue'; import mergeHelpComponent from '~/vue_merge_request_widget/components/mr_widget_merge_help.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetMergeHelp', () => { describe('MRWidgetMergeHelp', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue'; import pipelineComponent from '~/vue_merge_request_widget/components/mr_widget_pipeline.vue';
import mountComponent from 'spec/helpers/vue_mount_component_helper'; // eslint-disable-line import/first
import mockData from '../mock_data'; import mockData from '../mock_data';
import mockLinkedPipelines from '../../pipelines/graph/linked_pipelines_mock_data'; import mockLinkedPipelines from 'spec/pipelines/graph/linked_pipelines_mock_data'; // eslint-disable-line import/first
import mountComponent from '../../helpers/vue_mount_component_helper';
describe('MRWidgetPipeline', () => { describe('MRWidgetPipeline', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import component from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue'; import component from '~/vue_merge_request_widget/components/states/mr_widget_rebase.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Merge request widget rebase component', () => { describe('Merge request widget rebase component', () => {
let Component; let Component;
......
import Vue from 'vue'; import Vue from 'vue';
import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue'; import relatedLinksComponent from '~/vue_merge_request_widget/components/mr_widget_related_links.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetRelatedLinks', () => { describe('MRWidgetRelatedLinks', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import mrStatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue'; import mrStatusIcon from '~/vue_merge_request_widget/components/mr_widget_status_icon.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MR widget status icon component', () => { describe('MR widget status icon component', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import archivedComponent from '~/vue_merge_request_widget/components/states/mr_widget_archived.vue'; import archivedComponent from '~/vue_merge_request_widget/components/states/mr_widget_archived.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetArchived', () => { describe('MRWidgetArchived', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import autoMergeFailedComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue'; import autoMergeFailedComponent from '~/vue_merge_request_widget/components/states/mr_widget_auto_merge_failed.vue';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetAutoMergeFailed', () => { describe('MRWidgetAutoMergeFailed', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking.vue'; import checkingComponent from '~/vue_merge_request_widget/components/states/mr_widget_checking.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetChecking', () => { describe('MRWidgetChecking', () => {
let Component; let Component;
......
import Vue from 'vue'; import Vue from 'vue';
import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed.vue'; import closedComponent from '~/vue_merge_request_widget/components/states/mr_widget_closed.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetClosed', () => { describe('MRWidgetClosed', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue'; import conflictsComponent from '~/vue_merge_request_widget/components/states/mr_widget_conflicts.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetConflicts', () => { describe('MRWidgetConflicts', () => {
let Component; let Component;
......
import Vue from 'vue'; import Vue from 'vue';
import failedToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue'; import failedToMergeComponent from '~/vue_merge_request_widget/components/states/mr_widget_failed_to_merge.vue';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetFailedToMerge', () => { describe('MRWidgetFailedToMerge', () => {
let Component; let Component;
......
import Vue from 'vue'; import Vue from 'vue';
import mwpsComponent from '~/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue'; import mwpsComponent from '~/vue_merge_request_widget/components/states/mr_widget_merge_when_pipeline_succeeds.vue';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetMergeWhenPipelineSucceeds', () => { describe('MRWidgetMergeWhenPipelineSucceeds', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue'; import mergedComponent from '~/vue_merge_request_widget/components/states/mr_widget_merged.vue';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetMerged', () => { describe('MRWidgetMerged', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue'; import mergingComponent from '~/vue_merge_request_widget/components/states/mr_widget_merging.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetMerging', () => { describe('MRWidgetMerging', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import missingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue'; import missingBranchComponent from '~/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetMissingBranch', () => { describe('MRWidgetMissingBranch', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import notAllowedComponent from '~/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue'; import notAllowedComponent from '~/vue_merge_request_widget/components/states/mr_widget_not_allowed.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetNotAllowed', () => { describe('MRWidgetNotAllowed', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue'; import pipelineBlockedComponent from '~/vue_merge_request_widget/components/states/mr_widget_pipeline_blocked.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('MRWidgetPipelineBlocked', () => { describe('MRWidgetPipelineBlocked', () => {
let vm; let vm;
......
...@@ -4,6 +4,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -4,6 +4,7 @@ import axios from '~/lib/utils/axios_utils';
import mrWidgetOptions from 'ee/vue_merge_request_widget/mr_widget_options'; import mrWidgetOptions from 'ee/vue_merge_request_widget/mr_widget_options';
import MRWidgetService from 'ee/vue_merge_request_widget/services/mr_widget_service'; import MRWidgetService from 'ee/vue_merge_request_widget/services/mr_widget_service';
import MRWidgetStore from 'ee/vue_merge_request_widget/stores/mr_widget_store'; import MRWidgetStore from 'ee/vue_merge_request_widget/stores/mr_widget_store';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import mockData, { import mockData, {
baseIssues, baseIssues,
headIssues, headIssues,
...@@ -21,8 +22,6 @@ import { ...@@ -21,8 +22,6 @@ import {
sastHeadAllIssues, sastHeadAllIssues,
} from '../vue_shared/security_reports/mock_data'; } from '../vue_shared/security_reports/mock_data';
import mountComponent from '../helpers/vue_mount_component_helper';
describe('ee merge request widget options', () => { describe('ee merge request widget options', () => {
let vm; let vm;
let Component; let Component;
......
...@@ -3,8 +3,8 @@ import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options'; ...@@ -3,8 +3,8 @@ import mrWidgetOptions from '~/vue_merge_request_widget/mr_widget_options';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
import notify from '~/lib/utils/notify'; import notify from '~/lib/utils/notify';
import { stateKey } from '~/vue_merge_request_widget/stores/state_maps'; import { stateKey } from '~/vue_merge_request_widget/stores/state_maps';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import mockData from './mock_data'; import mockData from './mock_data';
import mountComponent from '../helpers/vue_mount_component_helper';
const returnPromise = data => new Promise((resolve) => { const returnPromise = data => new Promise((resolve) => {
resolve({ resolve({
......
import Vue from 'vue'; import Vue from 'vue';
import ciBadge from '~/vue_shared/components/ci_badge_link.vue'; import ciBadge from '~/vue_shared/components/ci_badge_link.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('CI Badge Link Component', () => { describe('CI Badge Link Component', () => {
let CIBadge; let CIBadge;
......
import Vue from 'vue'; import Vue from 'vue';
import clipboardButton from '~/vue_shared/components/clipboard_button.vue'; import clipboardButton from '~/vue_shared/components/clipboard_button.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('clipboard button', () => { describe('clipboard button', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import expandButton from '~/vue_shared/components/expand_button.vue'; import expandButton from '~/vue_shared/components/expand_button.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('expand button', () => { describe('expand button', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import fileIcon from '~/vue_shared/components/file_icon.vue'; import fileIcon from '~/vue_shared/components/file_icon.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('File Icon component', () => { describe('File Icon component', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import GlModal from '~/vue_shared/components/gl_modal.vue'; import GlModal from '~/vue_shared/components/gl_modal.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const modalComponent = Vue.extend(GlModal); const modalComponent = Vue.extend(GlModal);
......
import Vue from 'vue'; import Vue from 'vue';
import headerCi from '~/vue_shared/components/header_ci_component.vue'; import headerCi from '~/vue_shared/components/header_ci_component.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Header CI Component', () => { describe('Header CI Component', () => {
let HeaderCi; let HeaderCi;
......
import Vue from 'vue'; import Vue from 'vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Sprite Icon Component', function () { describe('Sprite Icon Component', function () {
describe('Initialization', function () { describe('Initialization', function () {
......
import Vue from 'vue'; import Vue from 'vue';
import issueWarning from '~/vue_shared/components/issue/issue_warning.vue'; import issueWarning from '~/vue_shared/components/issue/issue_warning.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const IssueWarning = Vue.extend(issueWarning); const IssueWarning = Vue.extend(issueWarning);
......
/* eslint-disable no-restricted-syntax */ /* eslint-disable no-restricted-syntax */
import Vue from 'vue'; import Vue from 'vue';
import linkToMemberAvatar from '~/vue_shared/components/link_to_member_avatar'; import linkToMemberAvatar from 'ee/vue_shared/components/link_to_member_avatar';
(() => { (() => {
function initComponent(propsData = {}) { function initComponent(propsData = {}) {
......
import Vue from 'vue'; import Vue from 'vue';
import LinkedPipelinesMiniList from '~/vue_shared/components/linked_pipelines_mini_list.vue'; import LinkedPipelinesMiniList from 'ee/vue_shared/components/linked_pipelines_mini_list.vue';
import mockData from '../../pipelines/graph/linked_pipelines_mock_data'; import mockData from 'spec/pipelines/graph/linked_pipelines_mock_data';
const ListComponent = Vue.extend(LinkedPipelinesMiniList); const ListComponent = Vue.extend(LinkedPipelinesMiniList);
......
import Vue from 'vue'; import Vue from 'vue';
import loadingButton from '~/vue_shared/components/loading_button.vue'; import loadingButton from '~/vue_shared/components/loading_button.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const LABEL = 'Hello'; const LABEL = 'Hello';
......
import Vue from 'vue'; import Vue from 'vue';
import modal from '~/vue_shared/components/modal.vue'; import modal from '~/vue_shared/components/modal.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const modalComponent = Vue.extend(modal); const modalComponent = Vue.extend(modal);
......
import Vue from 'vue'; import Vue from 'vue';
import navigationTabs from '~/vue_shared/components/navigation_tabs.vue'; import navigationTabs from '~/vue_shared/components/navigation_tabs.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('navigation tabs component', () => { describe('navigation tabs component', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import placeholderSystemNote from '~/vue_shared/components/notes/placeholder_system_note.vue'; import placeholderSystemNote from '~/vue_shared/components/notes/placeholder_system_note.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('placeholder system note component', () => { describe('placeholder system note component', () => {
let PlaceholderSystemNote; let PlaceholderSystemNote;
......
import Vue from 'vue'; import Vue from 'vue';
import panelResizer from '~/vue_shared/components/panel_resizer.vue'; import panelResizer from '~/vue_shared/components/panel_resizer.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Panel Resizer component', () => { describe('Panel Resizer component', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import datePicker from '~/vue_shared/components/pikaday.vue'; import datePicker from '~/vue_shared/components/pikaday.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('datePicker', () => { describe('datePicker', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import collapsedCalendarIcon from '~/vue_shared/components/sidebar/collapsed_calendar_icon.vue'; import collapsedCalendarIcon from '~/vue_shared/components/sidebar/collapsed_calendar_icon.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('collapsedCalendarIcon', () => { describe('collapsedCalendarIcon', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import collapsedGroupedDatePicker from '~/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue'; import collapsedGroupedDatePicker from '~/vue_shared/components/sidebar/collapsed_grouped_date_picker.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('collapsedGroupedDatePicker', () => { describe('collapsedGroupedDatePicker', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import sidebarDatePicker from '~/vue_shared/components/sidebar/date_picker.vue'; import sidebarDatePicker from '~/vue_shared/components/sidebar/date_picker.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('sidebarDatePicker', () => { describe('sidebarDatePicker', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import toggleSidebar from '~/vue_shared/components/sidebar/toggle_sidebar.vue'; import toggleSidebar from '~/vue_shared/components/sidebar/toggle_sidebar.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('toggleSidebar', () => { describe('toggleSidebar', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue'; import skeletonLoadingContainer from '~/vue_shared/components/skeleton_loading_container.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Skeleton loading container', () => { describe('Skeleton loading container', () => {
let vm; let vm;
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import stackedProgressBarComponent from '~/vue_shared/components/stacked_progress_bar.vue'; import stackedProgressBarComponent from '~/vue_shared/components/stacked_progress_bar.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const createComponent = (config) => { const createComponent = (config) => {
const Component = Vue.extend(stackedProgressBarComponent); const Component = Vue.extend(stackedProgressBarComponent);
......
import Vue from 'vue'; import Vue from 'vue';
import toggleButton from '~/vue_shared/components/toggle_button.vue'; import toggleButton from '~/vue_shared/components/toggle_button.vue';
import mountComponent from '../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('Toggle Button', () => { describe('Toggle Button', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import { placeholderImage } from '~/lazy_loader'; import { placeholderImage } from '~/lazy_loader';
import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue'; import userAvatarImage from '~/vue_shared/components/user_avatar/user_avatar_image.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
const DEFAULT_PROPS = { const DEFAULT_PROPS = {
size: 99, size: 99,
......
import Vue from 'vue'; import Vue from 'vue';
import modal from 'ee/vue_shared/security_reports/components/dast_modal.vue'; import modal from 'ee/vue_shared/security_reports/components/dast_modal.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('mr widget modal', () => { describe('mr widget modal', () => {
let vm; let vm;
......
import Vue from 'vue'; import Vue from 'vue';
import reportIssues from 'ee/vue_shared/security_reports/components/report_issues.vue'; import reportIssues from 'ee/vue_shared/security_reports/components/report_issues.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { import {
codequalityParsedIssues, codequalityParsedIssues,
} from '../../../vue_mr_widget/mock_data'; } from 'spec/vue_mr_widget/mock_data';
import { import {
sastParsedIssues, sastParsedIssues,
dockerReportParsed, dockerReportParsed,
......
import Vue from 'vue'; import Vue from 'vue';
import reportSection from 'ee/vue_shared/security_reports/components/report_section.vue'; import reportSection from 'ee/vue_shared/security_reports/components/report_section.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper'; import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { codequalityParsedIssues } from '../../../vue_mr_widget/mock_data'; import { codequalityParsedIssues } from 'spec/vue_mr_widget/mock_data';
describe('Report section', () => { describe('Report section', () => {
let vm; let vm;
......
...@@ -1421,7 +1421,7 @@ describe API::Issues do ...@@ -1421,7 +1421,7 @@ describe API::Issues do
context 'when source project does not exist' do context 'when source project does not exist' do
it 'returns 404 when trying to move an issue' do it 'returns 404 when trying to move an issue' do
post api("/projects/12345/issues/#{issue.iid}/move", user), post api("/projects/0/issues/#{issue.iid}/move", user),
to_project_id: target_project.id to_project_id: target_project.id
expect(response).to have_gitlab_http_status(404) expect(response).to have_gitlab_http_status(404)
...@@ -1432,7 +1432,7 @@ describe API::Issues do ...@@ -1432,7 +1432,7 @@ describe API::Issues do
context 'when target project does not exist' do context 'when target project does not exist' do
it 'returns 404 when trying to move an issue' do it 'returns 404 when trying to move an issue' do
post api("/projects/#{project.id}/issues/#{issue.iid}/move", user), post api("/projects/#{project.id}/issues/#{issue.iid}/move", user),
to_project_id: 12345 to_project_id: 0
expect(response).to have_gitlab_http_status(404) expect(response).to have_gitlab_http_status(404)
end end
......
...@@ -1266,7 +1266,7 @@ describe API::V3::Issues do ...@@ -1266,7 +1266,7 @@ describe API::V3::Issues do
context 'when source project does not exist' do context 'when source project does not exist' do
it 'returns 404 when trying to move an issue' do it 'returns 404 when trying to move an issue' do
post v3_api("/projects/999999/issues/#{issue.id}/move", user), post v3_api("/projects/0/issues/#{issue.id}/move", user),
to_project_id: target_project.id to_project_id: target_project.id
expect(response).to have_gitlab_http_status(404) expect(response).to have_gitlab_http_status(404)
...@@ -1277,7 +1277,7 @@ describe API::V3::Issues do ...@@ -1277,7 +1277,7 @@ describe API::V3::Issues do
context 'when target project does not exist' do context 'when target project does not exist' do
it 'returns 404 when trying to move an issue' do it 'returns 404 when trying to move an issue' do
post v3_api("/projects/#{project.id}/issues/#{issue.id}/move", user), post v3_api("/projects/#{project.id}/issues/#{issue.id}/move", user),
to_project_id: 999999 to_project_id: 0
expect(response).to have_gitlab_http_status(404) expect(response).to have_gitlab_http_status(404)
end end
......
...@@ -15,47 +15,79 @@ describe Labels::FindOrCreateService do ...@@ -15,47 +15,79 @@ describe Labels::FindOrCreateService do
context 'when acting on behalf of a specific user' do context 'when acting on behalf of a specific user' do
let(:user) { create(:user) } let(:user) { create(:user) }
subject(:service) { described_class.new(user, project, params) }
before do
project.add_developer(user)
end
context 'when label does not exist at group level' do context 'when finding labels on project level' do
it 'creates a new label at project level' do subject(:service) { described_class.new(user, project, params) }
expect { service.execute }.to change(project.labels, :count).by(1)
before do
project.add_developer(user)
end end
end
context 'when label exists at group level' do context 'when label does not exist at group level' do
it 'returns the group label' do it 'creates a new label at project level' do
group_label = create(:group_label, group: group, title: 'Security') expect { service.execute }.to change(project.labels, :count).by(1)
end
end
expect(service.execute).to eq group_label context 'when label exists at group level' do
it 'returns the group label' do
group_label = create(:group_label, group: group, title: 'Security')
expect(service.execute).to eq group_label
end
end
context 'when label exists at project level' do
it 'returns the project label' do
project_label = create(:label, project: project, title: 'Security')
expect(service.execute).to eq project_label
end
end end
end end
context 'when label does not exist at group level' do context 'when finding labels on group level' do
it 'creates a new label at project leve' do subject(:service) { described_class.new(user, group, params) }
expect { service.execute }.to change(project.labels, :count).by(1)
before do
group.add_developer(user)
end
context 'when label does not exist at group level' do
it 'creates a new label at group level' do
expect { service.execute }.to change(group.labels, :count).by(1)
end
end
context 'when label exists at group level' do
it 'returns the group label' do
group_label = create(:group_label, group: group, title: 'Security')
expect(service.execute).to eq group_label
end
end end
end end
end
context 'when authorization is not required' do
context 'when finding labels on project level' do
subject(:service) { described_class.new(nil, project, params) }
context 'when label exists at project level' do
it 'returns the project label' do it 'returns the project label' do
project_label = create(:label, project: project, title: 'Security') project_label = create(:label, project: project, title: 'Security')
expect(service.execute).to eq project_label expect(service.execute(skip_authorization: true)).to eq project_label
end end
end end
end
context 'when authorization is not required' do context 'when finding labels on group level' do
subject(:service) { described_class.new(nil, project, params) } subject(:service) { described_class.new(nil, group, params) }
it 'returns the project label' do it 'returns the group label' do
project_label = create(:label, project: project, title: 'Security') group_label = create(:group_label, group: group, title: 'Security')
expect(service.execute(skip_authorization: true)).to eq project_label expect(service.execute(skip_authorization: true)).to eq group_label
end
end end
end end
end end
......
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