Commit d072c18d authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into ce-to-ee-2017-12-16

parents 458f54dc 0a395a08
/* eslint-disable comma-dangle, space-before-function-paren, no-new */
/* global MilestoneSelect */
/* global Sidebar */
import Vue from 'vue';
import weight from 'ee/sidebar/components/weight/weight.vue';
import Flash from '../../flash';
import Sidebar from '../../right_sidebar';
import eventHub from '../../sidebar/event_hub';
import assigneeTitle from '../../sidebar/components/assignees/assignee_title';
import assignees from '../../sidebar/components/assignees/assignees';
......
......@@ -25,7 +25,6 @@ class ListIssue {
this.isLoading = {
weight: false,
};
this.isLoading = {};
this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
this.milestone_id = obj.milestone_id;
......
/* global CommentsStore */
/* global notes */
import Vue from 'vue';
import collapseIcon from '../icons/collapse_icon.svg';
import Notes from '../../notes';
import userAvatarImage from '../../vue_shared/components/user_avatar/user_avatar_image.vue';
const DiffNoteAvatars = Vue.extend({
......@@ -129,7 +129,7 @@ const DiffNoteAvatars = Vue.extend({
},
methods: {
clickedAvatar(e) {
notes.onAddDiffNote(e);
Notes.instance.onAddDiffNote(e);
// Toggle the active state of the toggle all button
this.toggleDiscussionsToggleState();
......
......@@ -11,7 +11,7 @@ import NotificationsForm from './notifications_form';
import notificationsDropdown from './notifications_dropdown';
import groupAvatar from './group_avatar';
import GroupLabelSubscription from './group_label_subscription';
/* global LineHighlighter */
import LineHighlighter from './line_highlighter';
import BuildArtifacts from './build_artifacts';
import CILintEditor from './ci_lint_editor';
import groupsSelect from './groups_select';
......@@ -21,7 +21,7 @@ import NamespaceSelect from './namespace_select';
import NewCommitForm from './new_commit_form';
import Project from './project';
import projectAvatar from './project_avatar';
/* global MergeRequest */
import MergeRequest from './merge_request';
import Compare from './compare';
import initCompareAutocomplete from './compare_autocomplete';
/* global PathLocks */
......@@ -30,7 +30,7 @@ import ProjectNew from './project_new';
import projectImport from './project_import';
import Labels from './labels';
import LabelManager from './label_manager';
/* global Sidebar */
import Sidebar from './right_sidebar';
/* global WeightSelect */
/* global AdminEmailSelect */
......
......@@ -3,7 +3,7 @@
/* global WeightSelect */
import LabelsSelect from './labels_select';
import IssuableContext from './issuable_context';
/* global Sidebar */
import Sidebar from './right_sidebar';
import DueDateSelectors from './due_date_select';
......@@ -17,5 +17,5 @@ export default () => {
new WeightSelect();
new IssuableContext(sidebarOptions.currentUser);
new DueDateSelectors();
window.sidebar = new Sidebar();
Sidebar.initialize();
};
/* global Notes */
import Notes from './notes';
export default () => {
const dataEl = document.querySelector('.js-notes-data');
......@@ -10,5 +10,7 @@ export default () => {
autocomplete,
} = JSON.parse(dataEl.innerHTML);
window.notes = new Notes(notesUrl, notesIds, now, diffView, autocomplete);
// Create a singleton so that we don't need to assign
// into the window object, we can just access the current isntance with Notes.instance
Notes.initialize(notesUrl, notesIds, now, diffView, autocomplete);
};
......@@ -175,4 +175,4 @@ LineHighlighter.prototype.__setLocationHash__ = function(value) {
}, document.title, value);
};
window.LineHighlighter = LineHighlighter;
export default LineHighlighter;
......@@ -45,14 +45,10 @@ import './layout_nav';
import LazyLoader from './lazy_loader';
import './line_highlighter';
import initLogoAnimation from './logo';
import './merge_request';
import './merge_request_tabs';
import './milestone_select';
import './notes';
import './preview_markdown';
import './projects_dropdown';
import './render_gfm';
import './right_sidebar';
import initBreadcrumbs from './breadcrumb';
// EE-only scripts
......
......@@ -7,9 +7,7 @@ import MergeRequestTabs from './merge_request_tabs';
import IssuablesHelper from './helpers/issuables_helper';
import { addDelimiter } from './lib/utils/text_utility';
(function() {
this.MergeRequest = (function() {
function MergeRequest(opts) {
function MergeRequest(opts) {
// Initialize MergeRequest behavior
//
// Options:
......@@ -40,26 +38,26 @@ import { addDelimiter } from './lib/utils/text_utility';
}
});
}
}
}
// Local jQuery finder
MergeRequest.prototype.$ = function(selector) {
// Local jQuery finder
MergeRequest.prototype.$ = function(selector) {
return this.$el.find(selector);
};
};
MergeRequest.prototype.initTabs = function() {
MergeRequest.prototype.initTabs = function() {
if (window.mrTabs) {
window.mrTabs.unbindEvents();
}
window.mrTabs = new MergeRequestTabs(this.opts);
};
};
MergeRequest.prototype.showAllCommits = function() {
MergeRequest.prototype.showAllCommits = function() {
this.$('.first-commits').remove();
return this.$('.all-commits').removeClass('hide');
};
};
MergeRequest.prototype.initMRBtnListeners = function() {
MergeRequest.prototype.initMRBtnListeners = function() {
var _this;
_this = this;
return $('a.btn-close, a.btn-reopen').on('click', function(e) {
......@@ -81,9 +79,9 @@ import { addDelimiter } from './lib/utils/text_utility';
}
}
});
};
};
MergeRequest.prototype.submitNoteForm = function(form, $button) {
MergeRequest.prototype.submitNoteForm = function(form, $button) {
var noteText;
noteText = form.find("textarea.js-note-text").val();
if (noteText.trim().length > 0) {
......@@ -91,9 +89,9 @@ import { addDelimiter } from './lib/utils/text_utility';
$button.data('submitted', true);
return $button.trigger('click');
}
};
};
MergeRequest.prototype.initCommitMessageListeners = function() {
MergeRequest.prototype.initCommitMessageListeners = function() {
$(document).on('click', 'a.js-with-description-link', function(e) {
var textarea = $('textarea.js-commit-message');
e.preventDefault();
......@@ -111,24 +109,24 @@ import { addDelimiter } from './lib/utils/text_utility';
$('.js-with-description-hint').show();
$('.js-without-description-hint').hide();
});
};
};
MergeRequest.prototype.updateStatusText = function(classToRemove, classToAdd, newStatusText) {
MergeRequest.prototype.updateStatusText = function(classToRemove, classToAdd, newStatusText) {
$('.detail-page-header .status-box')
.removeClass(classToRemove)
.addClass(classToAdd)
.find('span')
.text(newStatusText);
};
};
MergeRequest.prototype.decreaseCounter = function(by = 1) {
MergeRequest.prototype.decreaseCounter = function(by = 1) {
const $el = $('.nav-links .js-merge-counter');
const count = Math.max((parseInt($el.text().replace(/[^\d]/, ''), 10) - by), 0);
$el.text(addDelimiter(count));
};
};
MergeRequest.prototype.hideCloseButton = function() {
MergeRequest.prototype.hideCloseButton = function() {
const el = document.querySelector('.merge-request .js-issuable-actions');
const closeDropdownItem = el.querySelector('li.close-item');
if (closeDropdownItem) {
......@@ -141,8 +139,6 @@ import { addDelimiter } from './lib/utils/text_utility';
}
// Dropdown for mobile screen
el.querySelector('li.js-close-item').classList.add('hidden');
};
};
return MergeRequest;
})();
}).call(window);
export default MergeRequest;
/* eslint-disable no-new, class-methods-use-this */
/* global notes */
import Cookies from 'js-cookie';
import Flash from './flash';
......@@ -16,6 +15,7 @@ import initDiscussionTab from './image_diff/init_discussion_tab';
import Diff from './diff';
import { localTimeAgo } from './lib/utils/datetime_utility';
import syntaxHighlight from './syntax_highlight';
import Notes from './notes';
/* eslint-disable max-len */
// MergeRequestTabs
......@@ -324,7 +324,7 @@ export default class MergeRequestTabs {
if (anchor && anchor.length > 0) {
const notesContent = anchor.closest('.notes_content');
const lineType = notesContent.hasClass('new') ? 'new' : 'old';
notes.toggleDiffNote({
Notes.instance.toggleDiffNote({
target: anchor,
lineType,
forceShow: true,
......
......@@ -37,6 +37,12 @@ const MAX_VISIBLE_COMMIT_LIST_COUNT = 3;
const REGEX_QUICK_ACTIONS = /^\/\w+.*$/gm;
export default class Notes {
static initialize(notes_url, note_ids, last_fetched_at, view, enableGFM = true) {
if (!this.instance) {
this.instance = new Notes(notes_url, note_ids, last_fetched_at, view, enableGFM);
}
}
constructor(notes_url, note_ids, last_fetched_at, view, enableGFM = true) {
this.updateTargetButtons = this.updateTargetButtons.bind(this);
this.updateComment = this.updateComment.bind(this);
......
<script>
/* global LineHighlighter */
import { mapGetters } from 'vuex';
import LineHighlighter from '../../line_highlighter';
import syntaxHighlight from '../../syntax_highlight';
export default {
......
......@@ -3,25 +3,29 @@
import _ from 'underscore';
import Cookies from 'js-cookie';
(function() {
this.Sidebar = (function() {
function Sidebar(currentUser) {
function Sidebar(currentUser) {
this.toggleTodo = this.toggleTodo.bind(this);
this.sidebar = $('aside');
this.removeListeners();
this.addEventListeners();
}
Sidebar.initialize = function(currentUser) {
if (!this.instance) {
this.instance = new Sidebar(currentUser);
}
};
Sidebar.prototype.removeListeners = function () {
Sidebar.prototype.removeListeners = function () {
this.sidebar.off('click', '.sidebar-collapsed-icon');
this.sidebar.off('hidden.gl.dropdown');
$('.dropdown').off('loading.gl.dropdown');
$('.dropdown').off('loaded.gl.dropdown');
$(document).off('click', '.js-sidebar-toggle');
};
};
Sidebar.prototype.addEventListeners = function() {
Sidebar.prototype.addEventListeners = function() {
const $document = $(document);
this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked);
......@@ -31,9 +35,9 @@ import Cookies from 'js-cookie';
$document.on('click', '.js-sidebar-toggle', this.sidebarToggleClicked);
return $(document).off('click', '.js-issuable-todo').on('click', '.js-issuable-todo', this.toggleTodo);
};
};
Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
Sidebar.prototype.sidebarToggleClicked = function (e, triggered) {
var $allGutterToggleIcons, $this, $thisIcon;
e.preventDefault();
$this = $(this);
......@@ -53,9 +57,9 @@ import Cookies from 'js-cookie';
if (!triggered) {
Cookies.set("collapsed_gutter", $('.right-sidebar').hasClass('right-sidebar-collapsed'));
}
};
};
Sidebar.prototype.toggleTodo = function(e) {
Sidebar.prototype.toggleTodo = function(e) {
var $btnText, $this, $todoLoading, ajaxType, url;
$this = $(e.currentTarget);
ajaxType = $this.attr('data-delete-path') ? 'DELETE' : 'POST';
......@@ -86,9 +90,9 @@ import Cookies from 'js-cookie';
return _this.todoUpdateDone(data);
};
})(this));
};
};
Sidebar.prototype.todoUpdateDone = function(data) {
Sidebar.prototype.todoUpdateDone = function(data) {
const deletePath = data.delete_path ? data.delete_path : null;
const attrPrefix = deletePath ? 'mark' : 'todo';
const $todoBtns = $('.js-issuable-todo');
......@@ -115,9 +119,9 @@ import Cookies from 'js-cookie';
$elText.text($el.data(`${attrPrefix}-text`));
}
});
};
};
Sidebar.prototype.sidebarDropdownLoading = function(e) {
Sidebar.prototype.sidebarDropdownLoading = function(e) {
var $loading, $sidebarCollapsedIcon, i, img;
$sidebarCollapsedIcon = $(this).closest('.block').find('.sidebar-collapsed-icon');
img = $sidebarCollapsedIcon.find('img');
......@@ -130,9 +134,9 @@ import Cookies from 'js-cookie';
i.before($loading);
return i.hide();
}
};
};
Sidebar.prototype.sidebarDropdownLoaded = function(e) {
Sidebar.prototype.sidebarDropdownLoaded = function(e) {
var $sidebarCollapsedIcon, i, img;
$sidebarCollapsedIcon = $(this).closest('.block').find('.sidebar-collapsed-icon');
img = $sidebarCollapsedIcon.find('img');
......@@ -143,9 +147,9 @@ import Cookies from 'js-cookie';
} else {
return i.show();
}
};
};
Sidebar.prototype.sidebarCollapseClicked = function(e) {
Sidebar.prototype.sidebarCollapseClicked = function(e) {
var $block, sidebar;
if ($(e.currentTarget).hasClass('dont-change-state')) {
return;
......@@ -154,9 +158,9 @@ import Cookies from 'js-cookie';
e.preventDefault();
$block = $(this).closest('.block');
return sidebar.openDropdown($block);
};
};
Sidebar.prototype.openDropdown = function(blockOrName) {
Sidebar.prototype.openDropdown = function(blockOrName) {
var $block;
$block = _.isString(blockOrName) ? this.getBlock(blockOrName) : blockOrName;
if (!this.isOpen()) {
......@@ -169,34 +173,34 @@ import Cookies from 'js-cookie';
setTimeout(() => {
$block.find('.js-sidebar-dropdown-toggle').trigger('click');
});
};
};
Sidebar.prototype.setCollapseAfterUpdate = function($block) {
Sidebar.prototype.setCollapseAfterUpdate = function($block) {
$block.addClass('collapse-after-update');
return $('.layout-page').addClass('with-overlay');
};
};
Sidebar.prototype.onSidebarDropdownHidden = function(e) {
Sidebar.prototype.onSidebarDropdownHidden = function(e) {
var $block, sidebar;
sidebar = e.data;
e.preventDefault();
$block = $(e.target).closest('.block');
return sidebar.sidebarDropdownHidden($block);
};
};
Sidebar.prototype.sidebarDropdownHidden = function($block) {
Sidebar.prototype.sidebarDropdownHidden = function($block) {
if ($block.hasClass('collapse-after-update')) {
$block.removeClass('collapse-after-update');
$('.layout-page').removeClass('with-overlay');
return this.toggleSidebar('hide');
}
};
};
Sidebar.prototype.triggerOpenSidebar = function() {
Sidebar.prototype.triggerOpenSidebar = function() {
return this.sidebar.find('.js-sidebar-toggle').trigger('click');
};
};
Sidebar.prototype.toggleSidebar = function(action) {
Sidebar.prototype.toggleSidebar = function(action) {
if (action == null) {
action = 'toggle';
}
......@@ -213,16 +217,14 @@ import Cookies from 'js-cookie';
return this.triggerOpenSidebar();
}
}
};
};
Sidebar.prototype.isOpen = function() {
Sidebar.prototype.isOpen = function() {
return this.sidebar.is('.right-sidebar-expanded');
};
};
Sidebar.prototype.getBlock = function(name) {
Sidebar.prototype.getBlock = function(name) {
return this.sidebar.find(".block." + name);
};
};
return Sidebar;
})();
}).call(window);
export default Sidebar;
/* global Mousetrap */
/* global sidebar */
import _ from 'underscore';
import 'mousetrap';
import Sidebar from './right_sidebar';
import ShortcutsNavigation from './shortcuts_navigation';
import { CopyAsGFM } from './behaviors/copy_as_gfm';
......@@ -69,7 +69,7 @@ export default class ShortcutsIssuable extends ShortcutsNavigation {
}
static openSidebarDropdown(name) {
sidebar.openDropdown(name);
Sidebar.instance.openDropdown(name);
return false;
}
}
......@@ -6,7 +6,7 @@ Vue.use(VueResource);
export default class MRWidgetService {
constructor(endpoints) {
this.mergeResource = Vue.resource(endpoints.mergePath);
this.mergeCheckResource = Vue.resource(endpoints.statusPath);
this.mergeCheckResource = Vue.resource(`${endpoints.statusPath}?serializer=widget`);
this.cancelAutoMergeResource = Vue.resource(endpoints.cancelAutoMergePath);
this.removeWIPResource = Vue.resource(endpoints.removeWIPPath);
this.removeSourceBranchResource = Vue.resource(endpoints.sourceBranchPath);
......
......@@ -133,7 +133,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
.new(project, current_user, wip_event: 'unwip')
.execute(@merge_request)
render json: serializer.represent(@merge_request)
render json: serialize_widget(@merge_request)
end
def commit_change_content
......@@ -149,7 +149,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
.new(@project, current_user)
.cancel(@merge_request)
render json: serializer.represent(@merge_request)
render json: serialize_widget(@merge_request)
end
def merge
......@@ -313,6 +313,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
end
def serialize_widget(merge_request)
serializer.represent(merge_request, serializer: 'widget')
end
def serializer
MergeRequestSerializer.new(current_user: current_user, project: merge_request.project)
end
......
......@@ -32,7 +32,7 @@ module IssuablesHelper
end
end
def serialize_issuable(issuable)
def serialize_issuable(issuable, serializer: nil)
serializer_klass = case issuable
when Issue
IssueSerializer
......@@ -42,7 +42,7 @@ module IssuablesHelper
serializer_klass
.new(current_user: current_user, project: issuable.project)
.represent(issuable)
.represent(issuable, serializer: serializer)
.to_json
end
......
......@@ -3,14 +3,6 @@ class IssuableEntity < Grape::Entity
expose :id
expose :iid
expose :author_id
expose :description
expose :lock_version
expose :milestone_id
expose :title
expose :updated_by_id
expose :created_at
expose :updated_at
expose :milestone, using: API::Entities::Milestone
expose :labels, using: LabelEntity
end
class IssuableSidebarEntity < Grape::Entity
include TimeTrackableEntity
include RequestAwareEntity
prepend ::EE::IssuableSidebarEntity
......@@ -9,9 +10,4 @@ class IssuableSidebarEntity < Grape::Entity
expose :subscribed do |issuable|
issuable.subscribed?(request.current_user, issuable.project)
end
expose :time_estimate
expose :total_time_spent
expose :human_time_estimate
expose :human_total_time_spent
end
......@@ -2,7 +2,15 @@ class IssueEntity < IssuableEntity
include TimeTrackableEntity
expose :state
expose :milestone_id
expose :updated_by_id
expose :created_at
expose :updated_at
expose :deleted_at
expose :milestone, using: API::Entities::Milestone
expose :labels, using: LabelEntity
expose :lock_version
expose :author_id
expose :confidential
expose :discussion_locked
expose :assignees, using: API::Entities::UserBasic
......
class MergeRequestSerializer < BaseSerializer
# This overrided method takes care of which entity should be used
# to serialize the `merge_request` based on `basic` key in `opts` param.
# to serialize the `merge_request` based on `serializer` key in `opts` param.
# Hence, `entity` doesn't need to be declared on the class scope.
def represent(merge_request, opts = {})
entity =
case opts[:serializer]
when 'basic', 'sidebar'
MergeRequestBasicEntity
else
MergeRequestEntity
when 'widget'
MergeRequestWidgetEntity
end
super(merge_request, opts, entity)
......
class MergeRequestEntity < IssuableEntity
include TimeTrackableEntity
prepend ::EE::MergeRequestEntity
class MergeRequestWidgetEntity < IssuableEntity
prepend ::EE::MergeRequestWidgetEntity
expose :state
expose :deleted_at
expose :in_progress_merge_commit_sha
expose :merge_commit_sha
expose :merge_error
......
......@@ -21,7 +21,7 @@
-# haml-lint:disable InlineJavaScript
:javascript
window.gl = window.gl || {};
window.gl.mrWidgetData = #{serialize_issuable(@merge_request)}
window.gl.mrWidgetData = #{serialize_issuable(@merge_request, serializer: 'widget')}
// Append static, server-generated data not included in merge request entity (EE-Only)
// Object.assign would be useful here, but it blows up Phantom.js in tests
......
......@@ -8,11 +8,12 @@
= image_tag 'illustrations/issues.svg'
.col-xs-12
.text-content
- if has_button && current_user
- if current_user
%h4
= _("The Issue Tracker is the place to add things that need to be improved or solved in a project")
%p
= _("Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable.")
- if has_button
.text-center
- if project_select_button
= render 'shared/new_project_item_select', path: 'issues/new', label: 'New issue', type: :issues
......
---
title: Stop sending milestone and labels data over the wire for MR widget requests
merge_request:
author:
type: performance
......@@ -502,8 +502,8 @@ stages:
unit_test:
stage: test
script:
- composer install
- cp .env.example .env
- composer install
- php artisan key:generate
- php artisan migrate
- vendor/bin/phpunit
......
module EE
module MergeRequestEntity
module MergeRequestWidgetEntity
extend ActiveSupport::Concern
prepended do
......
......@@ -16,18 +16,18 @@ module QA
end
end
module Scenario
module Factory
autoload :License, 'qa/ee/factory/license'
module Geo
autoload :Node, 'qa/ee/scenario/geo/node'
autoload :Node, 'qa/ee/factory/geo/node'
end
end
module Scenario
module Test
autoload :Geo, 'qa/ee/scenario/test/geo'
end
module License
autoload :Add, 'qa/ee/scenario/license/add'
end
end
end
end
module QA
module EE
module Scenario
module Factory
module Geo
class Node < QA::Scenario::Template
class Node < QA::Factory::Base
attr_accessor :address
def perform
def fabricate!
QA::Page::Main::Login.act { sign_in_using_credentials }
QA::Page::Main::Menu.act { go_to_admin_area }
QA::Page::Admin::Menu.act { go_to_geo_nodes }
......
module QA
module EE
module Factory
class License < QA::Factory::Base
def fabricate!(license)
QA::Page::Main::Login.act { sign_in_using_credentials }
QA::Page::Main::Menu.act { go_to_admin_area }
QA::Page::Admin::Menu.act { go_to_license }
EE::Page::Admin::License.act(license) do |key|
add_new_license(key) if no_license?
end
QA::Page::Main::Menu.act { sign_out }
end
end
end
end
end
module QA
module EE
module Scenario
module License
class Add < QA::Scenario::Template
def perform(license)
QA::Page::Main::Login.act { sign_in_using_credentials }
QA::Page::Main::Menu.act { go_to_admin_area }
QA::Page::Admin::Menu.act { go_to_license }
EE::Page::Admin::License.act(license) do |key|
add_new_license(key) if no_license?
end
QA::Page::Main::Menu.act { sign_out }
end
end
end
end
end
end
......@@ -39,32 +39,26 @@ module QA
end
def add_license
# TODO EE license to Runtime.license, gitlab-org/gitlab-qa#86
#
puts 'Adding GitLab EE license ...'
QA::Runtime::Browser.visit(:geo_primary, QA::Page::Main::Login) do
Scenario::License::Add.perform(ENV['EE_LICENSE'])
Factory::License.fabricate!(ENV['EE_LICENSE'])
end
end
def enable_hashed_storage
# TODO, Factory::HashedStorage - gitlab-org/gitlab-qa#86
#
puts 'Enabling hashed repository storage setting ...'
QA::Runtime::Browser.visit(:geo_primary, QA::Page::Main::Login) do
QA::Scenario::Gitlab::Admin::HashedStorage.perform(:enabled)
QA::Factory::Settings::HashedStorage.fabricate!(:enabled)
end
end
def add_secondary_node
# TODO, Factory::Geo::Node - gitlab-org/gitlab-qa#86
#
puts 'Adding new Geo secondary node ...'
QA::Runtime::Browser.visit(:geo_primary, QA::Page::Main::Login) do
Scenario::Geo::Node.perform do |node|
Factory::Geo::Node.fabricate! do |node|
node.address = QA::Runtime::Scenario.geo_secondary_address
end
end
......
......@@ -11,7 +11,7 @@ module QA
return unless ENV['EE_LICENSE']
QA::Runtime::Browser.visit(:gitlab, QA::Page::Main::Login) do
EE::Scenario::License::Add.perform(ENV['EE_LICENSE'])
EE::Factory::License.fabricate!(ENV['EE_LICENSE'])
end
end
end
......
......@@ -4,9 +4,9 @@ module QA
Runtime::Browser.visit(:geo_primary, QA::Page::Main::Login) do
Page::Main::Login.act { sign_in_using_credentials }
Scenario::Gitlab::Project::Create.perform do |scenario|
scenario.name = 'geo-project'
scenario.description = 'Geo test project'
Factory::Resource::Project.fabricate! do |project|
project.name = 'geo-project'
project.description = 'Geo test project'
end
geo_project_name = Page::Project::Show.act { project_name }
......
......@@ -91,11 +91,11 @@ describe Projects::MergeRequestsController do
end
end
context 'without basic serializer param' do
it 'renders the merge request in the json format' do
go(format: :json)
context 'with widget serializer param' do
it 'renders widget MR entity as json' do
go(serializer: 'widget', format: :json)
expect(response).to match_response_schema('entities/merge_request')
expect(response).to match_response_schema('entities/merge_request_widget')
end
end
end
......
......@@ -10,8 +10,7 @@ describe EpicEntity do
subject { described_class.new(resource, request: request).as_json }
it 'has Issuable attributes' do
expect(subject).to include(:id, :iid, :author_id, :description, :lock_version, :milestone_id,
:title, :updated_by_id, :created_at, :updated_at, :milestone, :labels)
expect(subject).to include(:id, :iid, :description, :title)
end
it 'has epic specific attributes' do
......
require 'spec_helper'
describe MergeRequestEntity do
describe MergeRequestWidgetEntity do
let(:user) { create(:user) }
let(:project) { create :project, :repository }
let(:merge_request) { create(:merge_request, source_project: project, target_project: project) }
......
......@@ -8,6 +8,19 @@ describe 'Issues' do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
describe 'while user is signed out' do
describe 'empty state' do
it 'user sees empty state' do
visit project_issues_path(project)
expect(page).to have_content('Register / Sign In')
expect(page).to have_content('The Issue Tracker is the place to add things that need to be improved or solved in a project.')
expect(page).to have_content('You can register or sign in to create issues for this project.')
end
end
end
describe 'while user is signed in' do
before do
sign_in(user)
user2 = create(:user)
......@@ -15,6 +28,16 @@ describe 'Issues' do
project.team << [[user, user2], :developer]
end
describe 'empty state' do
it 'user sees empty state' do
visit project_issues_path(project)
expect(page).to have_content('The Issue Tracker is the place to add things that need to be improved or solved in a project')
expect(page).to have_content('Issues can be bugs, tasks or ideas to be discussed. Also, issues are searchable and filterable.')
expect(page).to have_content('New issue')
end
end
describe 'Edit issue' do
let!(:issue) do
create(:issue,
......@@ -769,4 +792,5 @@ describe 'Issues' do
expect(page).not_to have_css('.is-active')
end
end
end
end
......@@ -15,8 +15,8 @@ feature 'Mini Pipeline Graph', :js do
visit_merge_request
end
def visit_merge_request(format = :html)
visit project_merge_request_path(project, merge_request, format: format)
def visit_merge_request(format: :html, serializer: nil)
visit project_merge_request_path(project, merge_request, format: format, serializer: serializer)
end
it 'should display a mini pipeline graph' do
......@@ -33,12 +33,12 @@ feature 'Mini Pipeline Graph', :js do
end
it 'avoids repeated database queries' do
before = ActiveRecord::QueryRecorder.new { visit_merge_request(:json) }
before = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
create(:ci_build, pipeline: pipeline, legacy_artifacts_file: artifacts_file2)
create(:ci_build, pipeline: pipeline, when: 'manual')
after = ActiveRecord::QueryRecorder.new { visit_merge_request(:json) }
after = ActiveRecord::QueryRecorder.new { visit_merge_request(format: :json, serializer: 'widget') }
expect(before.count).to eq(after.count)
expect(before.cached_count).to eq(after.cached_count)
......
......@@ -81,15 +81,15 @@
"target_branch_tree_path": { "type": "string" },
"source_branch_path": { "type": "string" },
"conflict_resolution_path": { "type": ["string", "null"] },
"cancel_merge_when_pipeline_succeeds_path": { "type": "string" },
"create_issue_to_resolve_discussions_path": { "type": "string" },
"merge_path": { "type": "string" },
"cancel_merge_when_pipeline_succeeds_path": { "type": ["string", "null"] },
"create_issue_to_resolve_discussions_path": { "type": ["string", "null"] },
"merge_path": { "type": ["string", "null"] },
"cherry_pick_in_fork_path": { "type": ["string", "null"] },
"revert_in_fork_path": { "type": ["string", "null"] },
"email_patches_path": { "type": "string" },
"plain_diff_path": { "type": "string" },
"status_path": { "type": "string" },
"new_blob_path": { "type": "string" },
"new_blob_path": { "type": ["string", "null"] },
"merge_check_path": { "type": "string" },
"ci_environments_status_path": { "type": "string" },
"merge_commit_message_with_description": { "type": "string" },
......
/* global Sidebar */
/* eslint-disable no-new */
import _ from 'underscore';
import '~/right_sidebar';
import Sidebar from '~/right_sidebar';
describe('Issuable right sidebar collapsed todo toggle', () => {
const fixtureName = 'issues/open-issue.html.raw';
......
/* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, jasmine/no-spec-dupes, no-underscore-dangle, max-len */
/* global LineHighlighter */
import '~/line_highlighter';
import LineHighlighter from '~/line_highlighter';
(function() {
describe('LineHighlighter', function() {
......
/* global Notes */
import 'autosize';
import '~/gl_form';
import '~/lib/utils/text_utility';
import '~/render_gfm';
import '~/render_math';
import '~/notes';
import Notes from '~/notes';
const upArrowKeyCode = 38;
......
/* eslint-disable space-before-function-paren, no-return-assign */
/* global MergeRequest */
import '~/merge_request';
import MergeRequest from '~/merge_request';
import CloseReopenReportToggle from '~/close_reopen_report_toggle';
import IssuablesHelper from '~/helpers/issuables_helper';
......
/* eslint-disable no-var, comma-dangle, object-shorthand */
/* global Notes */
import * as urlUtils from '~/lib/utils/url_utility';
import MergeRequestTabs from '~/merge_request_tabs';
......@@ -7,7 +6,7 @@ import '~/commit/pipelines/pipelines_bundle';
import '~/breakpoints';
import '~/lib/utils/common_utils';
import Diff from '~/diff';
import '~/notes';
import Notes from '~/notes';
import 'vendor/jquery.scrollTo';
(function () {
......@@ -279,8 +278,8 @@ import 'vendor/jquery.scrollTo';
loadFixtures('merge_requests/diff_comment.html.raw');
$('body').attr('data-page', 'projects:merge_requests:show');
window.gl.ImageFile = () => {};
window.notes = new Notes('', []);
spyOn(window.notes, 'toggleDiffNote').and.callThrough();
Notes.initialize('', []);
spyOn(Notes.instance, 'toggleDiffNote').and.callThrough();
});
afterEach(() => {
......@@ -338,7 +337,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteId.length).toBeGreaterThan(0);
expect(window.notes.toggleDiffNote).toHaveBeenCalledWith({
expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
target: jasmine.any(Object),
lineType: 'old',
forceShow: true,
......@@ -349,7 +348,7 @@ import 'vendor/jquery.scrollTo';
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
......@@ -359,7 +358,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteLineNumId.length).toBeGreaterThan(0);
expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
});
......@@ -393,7 +392,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteId.length).toBeGreaterThan(0);
expect(window.notes.toggleDiffNote).toHaveBeenCalledWith({
expect(Notes.instance.toggleDiffNote).toHaveBeenCalledWith({
target: jasmine.any(Object),
lineType: 'new',
forceShow: true,
......@@ -404,7 +403,7 @@ import 'vendor/jquery.scrollTo';
spyOn(urlUtils, 'getLocationHash').and.returnValue('note_something-that-does-not-exist');
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
......@@ -414,7 +413,7 @@ import 'vendor/jquery.scrollTo';
this.class.loadDiff('/foo/bar/merge_requests/1/diffs');
expect(noteLineNumId.length).toBeGreaterThan(0);
expect(window.notes.toggleDiffNote).not.toHaveBeenCalled();
expect(Notes.instance.toggleDiffNote).not.toHaveBeenCalled();
});
});
});
......
/* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, max-len */
/* global Notes */
import * as urlUtils from '~/lib/utils/url_utility';
import 'autosize';
import '~/gl_form';
import '~/lib/utils/text_utility';
import '~/render_gfm';
import '~/notes';
import Notes from '~/notes';
(function() {
window.gon || (window.gon = {});
......
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, max-len */
/* global Sidebar */
import '~/commons/bootstrap';
import '~/right_sidebar';
import Sidebar from '~/right_sidebar';
(function() {
var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState;
......
require 'spec_helper'
describe MergeRequestSerializer do
let(:user) { build_stubbed(:user) }
let(:merge_request) { build_stubbed(:merge_request) }
let(:serializer) do
let(:user) { create(:user) }
let(:resource) { create(:merge_request) }
let(:json_entity) do
described_class.new(current_user: user)
.represent(resource, serializer: serializer)
.with_indifferent_access
end
describe '#represent' do
let(:opts) { { serializer: serializer_entity } }
subject { serializer.represent(merge_request, serializer: serializer_entity) }
context 'widget merge request serialization' do
let(:serializer) { 'widget' }
context 'when passing basic serializer param' do
let(:serializer_entity) { 'basic' }
it 'matches issue json schema' do
expect(json_entity).to match_schema('entities/merge_request_widget')
end
end
it 'calls super class #represent with correct params' do
expect_any_instance_of(BaseSerializer).to receive(:represent)
.with(merge_request, opts, MergeRequestBasicEntity)
context 'sidebar merge request serialization' do
let(:serializer) { 'sidebar' }
subject
it 'matches basic merge request json schema' do
expect(json_entity).to match_schema('entities/merge_request_basic')
end
end
context 'when serializer param is falsy' do
let(:serializer_entity) { nil }
it 'calls super class #represent with correct params' do
expect_any_instance_of(BaseSerializer).to receive(:represent)
.with(merge_request, opts, MergeRequestEntity)
context 'basic merge request serialization' do
let(:serializer) { 'basic' }
subject
it 'matches basic merge request json schema' do
expect(json_entity).to match_schema('entities/merge_request_basic')
end
end
context 'no serializer' do
let(:serializer) { nil }
it 'raises an error' do
expect { json_entity }.to raise_error(NoMethodError)
end
end
end
require 'spec_helper'
describe MergeRequestEntity do
describe MergeRequestWidgetEntity do
let(:project) { create :project, :repository }
let(:resource) { create(:merge_request, source_project: project, target_project: project) }
let(:user) { create(:user) }
......@@ -35,37 +35,6 @@ describe MergeRequestEntity do
end
end
it 'includes issues_links' do
issues_links = subject[:issues_links]
expect(issues_links).to include(:closing, :mentioned_but_not_closing,
:assign_to_closing)
end
it 'has Issuable attributes' do
expect(subject).to include(:id, :iid, :author_id, :description, :lock_version, :milestone_id,
:title, :updated_by_id, :created_at, :updated_at, :milestone, :labels)
end
it 'has time estimation attributes' do
expect(subject).to include(:time_estimate, :total_time_spent, :human_time_estimate, :human_total_time_spent)
end
it 'has important MergeRequest attributes' do
expect(subject).to include(:state, :deleted_at, :diff_head_sha, :merge_commit_message,
:has_conflicts, :has_ci, :merge_path,
:conflict_resolution_path,
:cancel_merge_when_pipeline_succeeds_path,
:create_issue_to_resolve_discussions_path,
:source_branch_path, :target_branch_commits_path,
:target_branch_tree_path, :commits_count, :merge_ongoing,
:ff_only_enabled,
## EE
:can_push_to_source_branch, :approvals_before_merge,
:squash, :rebase_commit_sha, :rebase_in_progress,
:approvals_path)
end
it 'has email_patches_path' do
expect(subject[:email_patches_path])
.to eq("/#{resource.project.full_path}/merge_requests/#{resource.iid}.patch")
......@@ -120,18 +89,6 @@ describe MergeRequestEntity do
end
end
it 'includes merge_event' do
create(:event, :merged, author: user, project: resource.project, target: resource)
expect(subject[:merge_event]).to include(:author, :updated_at)
end
it 'includes closed_event' do
create(:event, :closed, author: user, project: resource.project, target: resource)
expect(subject[:closed_event]).to include(:author, :updated_at)
end
describe 'diverged_commits_count' do
context 'when MR open and its diverging' do
it 'returns diverged commits count' do
......
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