Commit dd66c7b7 authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'rc/ce-to-ee-wednesday' into 'master'

CE Upstream - Wednesday

Closes gitlab-ci-multi-runner#2284

See merge request !1577
parents 9cfdb603 ec3044ac
...@@ -281,8 +281,6 @@ docs:check:apilint: ...@@ -281,8 +281,6 @@ docs:check:apilint:
image: "phusion/baseimage" image: "phusion/baseimage"
stage: test stage: test
<<: *dedicated-runner <<: *dedicated-runner
variables:
GIT_DEPTH: "3"
cache: {} cache: {}
dependencies: [] dependencies: []
before_script: [] before_script: []
...@@ -293,8 +291,6 @@ docs:check:links: ...@@ -293,8 +291,6 @@ docs:check:links:
image: "registry.gitlab.com/gitlab-org/gitlab-build-images:nanoc-bootstrap-ruby-2.4-alpine" image: "registry.gitlab.com/gitlab-org/gitlab-build-images:nanoc-bootstrap-ruby-2.4-alpine"
stage: test stage: test
<<: *dedicated-runner <<: *dedicated-runner
variables:
GIT_DEPTH: "3"
cache: {} cache: {}
dependencies: [] dependencies: []
before_script: [] before_script: []
......
...@@ -476,10 +476,10 @@ AwardsHandler.prototype.setupSearch = function setupSearch() { ...@@ -476,10 +476,10 @@ AwardsHandler.prototype.setupSearch = function setupSearch() {
this.registerEventListener('on', $('input.emoji-search'), 'input', (e) => { this.registerEventListener('on', $('input.emoji-search'), 'input', (e) => {
const term = $(e.target).val().trim(); const term = $(e.target).val().trim();
// Clean previous search results // Clean previous search results
$('ul.emoji-menu-search, h5.emoji-search').remove(); $('ul.emoji-menu-search, h5.emoji-search-title').remove();
if (term.length > 0) { if (term.length > 0) {
// Generate a search result block // Generate a search result block
const h5 = $('<h5 class="emoji-search" />').text('Search results'); const h5 = $('<h5 class="emoji-search-title"/>').text('Search results');
const foundEmojis = this.searchEmojis(term).show(); const foundEmojis = this.searchEmojis(term).show();
const ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis); const ul = $('<ul>').addClass('emoji-menu-list emoji-menu-search').append(foundEmojis);
$('.emoji-menu-content ul, .emoji-menu-content h5').hide(); $('.emoji-menu-content ul, .emoji-menu-content h5').hide();
......
/* eslint-disable no-new */
import Vue from 'vue';
import PDFLab from 'vendor/pdflab';
import workerSrc from 'vendor/pdf.worker';
Vue.use(PDFLab, {
workerSrc,
});
export default () => {
const el = document.getElementById('js-pdf-viewer');
new Vue({
el,
data() {
return {
error: false,
loadError: false,
loading: true,
pdf: el.dataset.endpoint,
};
},
methods: {
onLoad() {
this.loading = false;
},
onError(error) {
this.loading = false;
this.loadError = true;
this.error = error;
},
},
template: `
<div class="container-fluid md prepend-top-default append-bottom-default">
<div
class="text-center loading"
v-if="loading && !error">
<i
class="fa fa-spinner fa-spin"
aria-hidden="true"
aria-label="PDF loading">
</i>
</div>
<pdf-lab
v-if="!loadError"
:pdf="pdf"
@pdflabload="onLoad"
@pdflaberror="onError" />
<p
class="text-center"
v-if="error">
<span v-if="loadError">
An error occured whilst loading the file. Please try again later.
</span>
<span v-else>
An error occured whilst decoding the file.
</span>
</p>
</div>
`,
});
};
import renderPDF from './pdf';
document.addEventListener('DOMContentLoaded', renderPDF);
import JSZip from 'jszip';
import JSZipUtils from 'jszip-utils';
export default class SketchLoader {
constructor(container) {
this.container = container;
this.loadingIcon = this.container.querySelector('.js-loading-icon');
this.load();
}
load() {
return this.getZipFile()
.then(data => JSZip.loadAsync(data))
.then(asyncResult => asyncResult.files['previews/preview.png'].async('uint8array'))
.then((content) => {
const url = window.URL || window.webkitURL;
const blob = new Blob([new Uint8Array(content)], {
type: 'image/png',
});
const previewUrl = url.createObjectURL(blob);
this.render(previewUrl);
})
.catch(this.error.bind(this));
}
getZipFile() {
return new JSZip.external.Promise((resolve, reject) => {
JSZipUtils.getBinaryContent(this.container.dataset.endpoint, (err, data) => {
if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
render(previewUrl) {
const previewLink = document.createElement('a');
const previewImage = document.createElement('img');
previewLink.href = previewUrl;
previewLink.target = '_blank';
previewImage.src = previewUrl;
previewImage.className = 'img-responsive';
previewLink.appendChild(previewImage);
this.container.appendChild(previewLink);
this.removeLoadingIcon();
}
error() {
const errorMsg = document.createElement('p');
errorMsg.className = 'prepend-top-default append-bottom-default text-center';
errorMsg.textContent = `
Cannot show preview. For previews on sketch files, they must have the file format
introduced by Sketch version 43 and above.
`;
this.container.appendChild(errorMsg);
this.removeLoadingIcon();
}
removeLoadingIcon() {
if (this.loadingIcon) {
this.loadingIcon.remove();
}
}
}
/* eslint-disable no-new */
import SketchLoader from './sketch';
document.addEventListener('DOMContentLoaded', () => {
const el = document.getElementById('js-sketch-viewer');
new SketchLoader(el);
});
/* eslint-disable comma-dangle, space-before-function-paren, one-var */ /* eslint-disable comma-dangle, space-before-function-paren, one-var */
/* global Sortable */ /* global Sortable */
import Vue from 'vue'; import Vue from 'vue';
import boardList from './board_list';
import boardBlankState from './board_blank_state'; import boardBlankState from './board_blank_state';
require('./board_delete'); require('./board_delete');
...@@ -16,7 +16,7 @@ require('./board_list'); ...@@ -16,7 +16,7 @@ require('./board_list');
gl.issueBoards.Board = Vue.extend({ gl.issueBoards.Board = Vue.extend({
template: '#js-board-template', template: '#js-board-template',
components: { components: {
'board-list': gl.issueBoards.BoardList, boardList,
'board-delete': gl.issueBoards.BoardDelete, 'board-delete': gl.issueBoards.BoardDelete,
boardBlankState, boardBlankState,
}, },
......
/* eslint-disable comma-dangle, space-before-function-paren, max-len */
/* global Sortable */ /* global Sortable */
import Vue from 'vue';
import boardNewIssue from './board_new_issue'; import boardNewIssue from './board_new_issue';
import boardCard from './board_card'; import boardCard from './board_card';
import eventHub from '../eventhub';
(() => { const Store = gl.issueBoards.BoardsStore;
const Store = gl.issueBoards.BoardsStore;
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
gl.issueBoards.BoardList = Vue.extend({ export default {
template: '#js-board-list-template', name: 'BoardList',
components: { props: {
boardCard, disabled: {
boardNewIssue, type: Boolean,
required: true,
}, },
props: { list: {
disabled: Boolean, type: Object,
list: Object, required: true,
issues: Array,
loading: Boolean,
issueLinkBase: String,
rootPath: String,
}, },
data () { issues: {
return { type: Array,
scrollOffset: 250, required: true,
filters: Store.state.filters,
showCount: false,
showIssueForm: false
};
}, },
watch: { loading: {
filters: { type: Boolean,
handler () { required: true,
this.list.loadingMore = false; },
this.$refs.list.scrollTop = 0; issueLinkBase: {
}, type: String,
deep: true required: true,
}, },
issues () { rootPath: {
this.$nextTick(() => { type: String,
if (this.scrollHeight() <= this.listHeight() && this.list.issuesSize > this.list.issues.length) { required: true,
this.list.page += 1; },
this.list.getIssues(false); },
} data() {
return {
scrollOffset: 250,
filters: Store.state.filters,
showCount: false,
showIssueForm: false,
};
},
components: {
boardCard,
boardNewIssue,
},
methods: {
listHeight() {
return this.$refs.list.getBoundingClientRect().height;
},
scrollHeight() {
return this.$refs.list.scrollHeight;
},
scrollTop() {
return this.$refs.list.scrollTop + this.listHeight();
},
loadNextPage() {
const getIssues = this.list.nextPage();
if (this.scrollHeight() > Math.ceil(this.listHeight())) { if (getIssues) {
this.showCount = true; this.list.loadingMore = true;
} else { getIssues.then(() => {
this.showCount = false; this.list.loadingMore = false;
}
}); });
} }
}, },
methods: { toggleForm() {
listHeight () { this.showIssueForm = !this.showIssueForm;
return this.$refs.list.getBoundingClientRect().height; },
}, onScroll() {
scrollHeight () { if ((this.scrollTop() > this.scrollHeight() - this.scrollOffset) && !this.list.loadingMore) {
return this.$refs.list.scrollHeight; this.loadNextPage();
}, }
scrollTop () { },
return this.$refs.list.scrollTop + this.listHeight(); },
watch: {
filters: {
handler() {
this.list.loadingMore = false;
this.$refs.list.scrollTop = 0;
}, },
loadNextPage () { deep: true,
const getIssues = this.list.nextPage(); },
issues() {
this.$nextTick(() => {
if (this.scrollHeight() <= this.listHeight() &&
this.list.issuesSize > this.list.issues.length) {
this.list.page += 1;
this.list.getIssues(false);
}
if (getIssues) { if (this.scrollHeight() > Math.ceil(this.listHeight())) {
this.list.loadingMore = true; this.showCount = true;
getIssues.then(() => { } else {
this.list.loadingMore = false; this.showCount = false;
});
} }
}, });
toggleForm() {
this.showIssueForm = !this.showIssueForm;
},
},
created() {
gl.IssueBoardsApp.$on(`hide-issue-form-${this.list.id}`, this.toggleForm);
}, },
mounted () { },
const options = gl.issueBoards.getBoardSortableDefaultOptions({ created() {
scroll: document.querySelectorAll('.boards-list')[0], eventHub.$on(`hide-issue-form-${this.list.id}`, this.toggleForm);
group: 'issues', },
disabled: this.disabled, mounted() {
filter: '.board-list-count, .is-disabled', const options = gl.issueBoards.getBoardSortableDefaultOptions({
dataIdAttr: 'data-issue-id', scroll: document.querySelectorAll('.boards-list')[0],
onStart: (e) => { group: 'issues',
const card = this.$refs.issue[e.oldIndex]; disabled: this.disabled,
filter: '.board-list-count, .is-disabled',
dataIdAttr: 'data-issue-id',
onStart: (e) => {
const card = this.$refs.issue[e.oldIndex];
card.showDetail = false; card.showDetail = false;
Store.moving.list = card.list; Store.moving.list = card.list;
Store.moving.issue = Store.moving.list.findIssue(+e.item.dataset.issueId); Store.moving.issue = Store.moving.list.findIssue(+e.item.dataset.issueId);
gl.issueBoards.onStart(); gl.issueBoards.onStart();
}, },
onAdd: (e) => { onAdd: (e) => {
gl.issueBoards.BoardsStore.moveIssueToList(Store.moving.list, this.list, Store.moving.issue, e.newIndex); gl.issueBoards.BoardsStore
.moveIssueToList(Store.moving.list, this.list, Store.moving.issue, e.newIndex);
this.$nextTick(() => { this.$nextTick(() => {
e.item.remove(); e.item.remove();
}); });
}, },
onUpdate: (e) => { onUpdate: (e) => {
const sortedArray = this.sortable.toArray().filter(id => id !== '-1'); const sortedArray = this.sortable.toArray().filter(id => id !== '-1');
gl.issueBoards.BoardsStore.moveIssueInList(this.list, Store.moving.issue, e.oldIndex, e.newIndex, sortedArray); gl.issueBoards.BoardsStore
}, .moveIssueInList(this.list, Store.moving.issue, e.oldIndex, e.newIndex, sortedArray);
onMove(e) { },
return !e.related.classList.contains('board-list-count'); onMove(e) {
} return !e.related.classList.contains('board-list-count');
}); },
});
this.sortable = Sortable.create(this.$refs.list, options); this.sortable = Sortable.create(this.$refs.list, options);
// Scroll event on list to load more // Scroll event on list to load more
this.$refs.list.onscroll = () => { this.$refs.list.addEventListener('scroll', this.onScroll);
if ((this.scrollTop() > this.scrollHeight() - this.scrollOffset) && !this.list.loadingMore) { },
this.loadNextPage(); beforeDestroy() {
} eventHub.$off(`hide-issue-form-${this.list.id}`, this.toggleForm);
}; this.$refs.list.removeEventListener('scroll', this.onScroll);
}, },
beforeDestroy() { template: `
gl.IssueBoardsApp.$off(`hide-issue-form-${this.list.id}`, this.toggleForm); <div class="board-list-component">
}, <div
}); class="board-list-loading text-center"
})(); aria-label="Loading issues"
v-if="loading">
<i
class="fa fa-spinner fa-spin"
aria-hidden="true">
</i>
</div>
<board-new-issue
:list="list"
v-if="list.type !== 'closed' && showIssueForm"/>
<ul
class="board-list"
v-show="!loading"
ref="list"
:data-board="list.id"
:class="{ 'is-smaller': showIssueForm }">
<board-card
v-for="(issue, index) in issues"
ref="issue"
:index="index"
:list="list"
:issue="issue"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
:disabled="disabled"
:key="issue.id" />
<li
class="board-list-count text-center"
v-if="showCount"
data-id="-1">
<i
class="fa fa-spinner fa-spin"
aria-label="Loading more issues"
aria-hidden="true"
v-show="list.loadingMore">
</i>
<span v-if="list.issues.length === list.issuesSize">
Showing all issues
</span>
<span v-else>
Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
</span>
</li>
</ul>
</div>
`,
};
/* global ListIssue */ /* global ListIssue */
import eventHub from '../eventhub';
const Store = gl.issueBoards.BoardsStore; const Store = gl.issueBoards.BoardsStore;
export default { export default {
...@@ -53,7 +55,7 @@ export default { ...@@ -53,7 +55,7 @@ export default {
}, },
cancel() { cancel() {
this.title = ''; this.title = '';
gl.IssueBoardsApp.$emit(`hide-issue-form-${this.list.id}`); eventHub.$emit(`hide-issue-form-${this.list.id}`);
}, },
}, },
mounted() { mounted() {
......
/* eslint-disable import/prefer-default-export */
/**
* Function that allows a number with an X amount of decimals
* to be formatted in the following fashion:
* * For 1 digit to the left of the decimal point and X digits to the right of it
* * * Show 3 digits to the right
* * For 2 digits to the left of the decimal point and X digits to the right of it
* * * Show 2 digits to the right
*/
export function formatRelevantDigits(number) {
let digitsLeft = '';
let relevantDigits = 0;
let formattedNumber = '';
if (!isNaN(Number(number))) {
digitsLeft = number.split('.')[0];
switch (digitsLeft.length) {
case 1:
relevantDigits = 3;
break;
case 2:
relevantDigits = 2;
break;
case 3:
relevantDigits = 1;
break;
default:
relevantDigits = 4;
break;
}
formattedNumber = Number(number).toFixed(relevantDigits);
}
return formattedNumber;
}
...@@ -292,6 +292,10 @@ ...@@ -292,6 +292,10 @@
} }
@media(min-width: $screen-xs-max) { @media(min-width: $screen-xs-max) {
&.merge-requests .text-content {
margin-top: 40px;
}
&.labels .text-content { &.labels .text-content {
margin-top: 70px; margin-top: 70px;
} }
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
} }
.issue-boards-page { .issue-boards-page {
.page-with-sidebar { .content-wrapper {
padding-bottom: 0; padding-bottom: 0;
} }
...@@ -101,8 +101,8 @@ ...@@ -101,8 +101,8 @@
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS height: 475px; // Needed for PhantomJS
height: calc(100vh - 220px); height: calc(100vh - 222px);
min-height: 409px; min-height: 475px;
transition: width .2s; transition: width .2s;
&.is-compact { &.is-compact {
......
...@@ -309,6 +309,16 @@ ...@@ -309,6 +309,16 @@
text { text {
fill: $stat-graph-axis-fill; fill: $stat-graph-axis-fill;
} }
.label-axis-text,
.text-metric-usage {
fill: $black;
font-weight: 500;
}
.legend-axis-text {
fill: $black;
}
} }
.x-axis path, .x-axis path,
......
...@@ -459,20 +459,13 @@ a.deploy-project-label { ...@@ -459,20 +459,13 @@ a.deploy-project-label {
flex-wrap: wrap; flex-wrap: wrap;
.btn { .btn {
margin: 0 10px 10px 0;
padding: 8px; padding: 8px;
margin-left: 10px;
} }
> div { > div {
margin-bottom: 10px;
padding-left: 0; padding-left: 0;
&:last-child {
margin-bottom: 0;
.btn {
margin-right: 0;
}
}
} }
} }
} }
......
...@@ -10,6 +10,7 @@ class Groups::ApplicationController < ApplicationController ...@@ -10,6 +10,7 @@ class Groups::ApplicationController < ApplicationController
unless @group unless @group
id = params[:group_id] || params[:id] id = params[:group_id] || params[:id]
@group = Group.find_by_full_path(id) @group = Group.find_by_full_path(id)
@group_merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id).execute
unless @group && can?(current_user, :read_group, @group) unless @group && can?(current_user, :read_group, @group)
@group = nil @group = nil
......
class Import::BaseController < ApplicationController class Import::BaseController < ApplicationController
private private
def find_or_create_namespace(name, owner) def find_or_create_namespace(names, owner)
return current_user.namespace if name == owner return current_user.namespace if names == owner
return current_user.namespace unless current_user.can_create_group? return current_user.namespace unless current_user.can_create_group?
begin names = params[:target_namespace].presence || names
name = params[:target_namespace].presence || name full_path_namespace = Namespace.find_by_full_path(names)
namespace = Group.create!(name: name, path: name, owner: current_user)
namespace.add_owner(current_user) return full_path_namespace if full_path_namespace
namespace
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid names.split('/').inject(nil) do |parent, name|
Namespace.find_by_full_path(name) begin
namespace = Group.create!(name: name,
path: name,
owner: current_user,
parent: parent)
namespace.add_owner(current_user)
namespace
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid
Namespace.where(parent: parent).find_by_path_or_name(name)
end
end end
end end
end end
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# state: 'open' or 'closed' or 'all' # state: 'open' or 'closed' or 'all'
# group_id: integer # group_id: integer
# project_id: integer # project_id: integer
# milestone_id: integer # milestone_title: string
# assignee_id: integer # assignee_id: integer
# search: string # search: string
# label_name: string # label_name: string
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
# state: 'open' or 'closed' or 'all' # state: 'open' or 'closed' or 'all'
# group_id: integer # group_id: integer
# project_id: integer # project_id: integer
# milestone_id: integer # milestone_title: string
# assignee_id: integer # assignee_id: integer
# search: string # search: string
# label_name: string # label_name: string
......
...@@ -46,10 +46,18 @@ class Blob < SimpleDelegator ...@@ -46,10 +46,18 @@ class Blob < SimpleDelegator
text? && language && language.name == 'SVG' text? && language && language.name == 'SVG'
end end
def pdf?
name && File.extname(name) == '.pdf'
end
def ipython_notebook? def ipython_notebook?
text? && language&.name == 'Jupyter Notebook' text? && language&.name == 'Jupyter Notebook'
end end
def sketch?
binary? && extname.downcase.delete('.') == 'sketch'
end
def size_within_svg_limits? def size_within_svg_limits?
size <= MAXIMUM_SVG_SIZE size <= MAXIMUM_SVG_SIZE
end end
...@@ -67,8 +75,12 @@ class Blob < SimpleDelegator ...@@ -67,8 +75,12 @@ class Blob < SimpleDelegator
end end
elsif image? || svg? elsif image? || svg?
'image' 'image'
elsif pdf?
'pdf'
elsif ipython_notebook? elsif ipython_notebook?
'notebook' 'notebook'
elsif sketch?
'sketch'
elsif text? elsif text?
'text' 'text'
else else
......
...@@ -541,6 +541,8 @@ module Ci ...@@ -541,6 +541,8 @@ module Ci
end end
def dependencies def dependencies
return [] if empty_dependencies?
depended_jobs = depends_on_builds depended_jobs = depends_on_builds
return depended_jobs unless options[:dependencies].present? return depended_jobs unless options[:dependencies].present?
...@@ -550,6 +552,10 @@ module Ci ...@@ -550,6 +552,10 @@ module Ci
end end
end end
def empty_dependencies?
options[:dependencies]&.empty?
end
private private
def update_artifacts_size def update_artifacts_size
......
...@@ -177,6 +177,16 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -177,6 +177,16 @@ class MergeRequestDiff < ActiveRecord::Base
st_commits.count st_commits.count
end end
def utf8_st_diffs
return [] if st_diffs.blank?
st_diffs.map do |diff|
diff.each do |k, v|
diff[k] = encode_utf8(v) if v.respond_to?(:encoding)
end
end
end
private private
# Old GitLab implementations may have generated diffs as ["--broken-diff"]. # Old GitLab implementations may have generated diffs as ["--broken-diff"].
...@@ -270,14 +280,6 @@ class MergeRequestDiff < ActiveRecord::Base ...@@ -270,14 +280,6 @@ class MergeRequestDiff < ActiveRecord::Base
project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha) project.merge_base_commit(head_commit_sha, start_commit_sha).try(:sha)
end end
def utf8_st_diffs
st_diffs.map do |diff|
diff.each do |k, v|
diff[k] = encode_utf8(v) if v.respond_to?(:encoding)
end
end
end
# #
# #save or #update_attributes providing changes on serialized attributes do a lot of # #save or #update_attributes providing changes on serialized attributes do a lot of
# serialization and deserialization calls resulting in bad performance. # serialization and deserialization calls resulting in bad performance.
......
...@@ -62,6 +62,7 @@ module Users ...@@ -62,6 +62,7 @@ module Users
:email, :email,
:external, :external,
:force_random_password, :force_random_password,
:password_automatically_set,
:hide_no_password, :hide_no_password,
:hide_no_ssh_key, :hide_no_ssh_key,
:key_id, :key_id,
...@@ -85,6 +86,7 @@ module Users ...@@ -85,6 +86,7 @@ module Users
[ [
:email, :email,
:email_confirmation, :email_confirmation,
:password_automatically_set,
:name, :name,
:password, :password,
:username :username
......
- page_title "Merge Requests" - page_title "Merge Requests"
.top-area - if @group_merge_requests.empty?
= render 'shared/issuable/nav', type: :merge_requests = render 'shared/empty_states/merge_requests', project_select_button: true
- if current_user - else
.nav-controls .top-area
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New Merge Request" = render 'shared/issuable/nav', type: :merge_requests
- if current_user
.nav-controls
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request"
= render 'shared/issuable/filter', type: :merge_requests = render 'shared/issuable/filter', type: :merge_requests
.row-content-block.second-block .row-content-block.second-block
Only merge requests from Only merge requests from
%strong= @group.name %strong= @group.name
group are listed here. group are listed here.
- if current_user - if current_user
To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page. To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
= render 'shared/merge_requests' .prepend-top-default
= render 'shared/merge_requests'
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('pdf_viewer')
.file-content#js-pdf-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } }
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('sketch_viewer')
.file-content#js-sketch-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } }
.js-loading-icon.text-center.prepend-top-default.append-bottom-default.js-loading-icon{ 'aria-label' => 'Loading Sketch preview' }
= icon('spinner spin 2x', 'aria-hidden' => 'true');
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
= page_specific_javascript_bundle_tag('boards') = page_specific_javascript_bundle_tag('boards')
%script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board" %script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board"
%script#js-board-list-template{ type: "text/x-template" }= render "projects/boards/components/board_list"
%script#js-board-modal-filter{ type: "text/x-template" }= render "shared/issuable/search_bar", type: :boards_modal %script#js-board-modal-filter{ type: "text/x-template" }= render "shared/issuable/search_bar", type: :boards_modal
= render "projects/issues/head" = render "projects/issues/head"
......
.board-list-component
.board-list-loading.text-center{ "v-if" => "loading" }
= icon("spinner spin")
- if can? current_user, :create_issue, @project
%board-new-issue{ ":list" => "list",
"v-if" => 'list.type !== "closed" && showIssueForm' }
%ul.board-list{ "ref" => "list",
"v-show" => "!loading",
":data-board" => "list.id",
":class" => '{ "is-smaller": showIssueForm }' }
%board-card{ "v-for" => "(issue, index) in issues",
"ref" => "issue",
":index" => "index",
":list" => "list",
":issue" => "issue",
":issue-link-base" => "issueLinkBase",
":root-path" => "rootPath",
":disabled" => "disabled",
":key" => "issue.id" }
%li.board-list-count.text-center{ "v-if" => "showCount",
"data-issue-id" => "-1" }
= icon("spinner spin", "v-show" => "list.loadingMore" )
%span{ "v-if" => "list.issues.length === list.issuesSize" }
Showing all issues
%span{ "v-else" => true }
Showing {{ list.issues.length }} of {{ list.issuesSize }} issues
- if environment.external_url && can?(current_user, :read_environment, environment) - if environment.external_url && can?(current_user, :read_environment, environment)
= link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url' do = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url' do
= icon('external-link') = icon('external-link')
View deployment
...@@ -4,3 +4,4 @@ ...@@ -4,3 +4,4 @@
= link_to environment_metrics_path(environment), title: 'See metrics', class: 'btn metrics-button' do = link_to environment_metrics_path(environment), title: 'See metrics', class: 'btn metrics-button' do
= icon('area-chart') = icon('area-chart')
Monitoring
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
.col-sm-6 .col-sm-6
%h3.page-title %h3.page-title
Environment: Environment:
= @environment.name = link_to @environment.name, environment_path(@environment)
.col-sm-6 .col-sm-6
.nav-controls .nav-controls
......
...@@ -4,9 +4,9 @@ ...@@ -4,9 +4,9 @@
%div{ class: container_class } %div{ class: container_class }
.top-area.adjust .top-area.adjust
.col-md-9 .col-md-7
%h3.page-title= @environment.name %h3.page-title= @environment.name
.col-md-3 .col-md-5
.nav-controls .nav-controls
= render 'projects/environments/metrics_button', environment: @environment = render 'projects/environments/metrics_button', environment: @environment
= render 'projects/environments/terminal_button', environment: @environment = render 'projects/environments/terminal_button', environment: @environment
......
%ul.content-list.mr-list.issuable-list %ul.content-list.mr-list.issuable-list
= render @merge_requests - if @merge_requests.exists?
- if @merge_requests.blank? = render @merge_requests
%li - else
.nothing-here-block No merge requests to show = render 'shared/empty_states/merge_requests'
- if @merge_requests.present? - if @merge_requests.present?
= paginate @merge_requests, theme: "gitlab" = paginate @merge_requests, theme: "gitlab"
...@@ -7,16 +7,19 @@ ...@@ -7,16 +7,19 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('filtered_search') = page_specific_javascript_bundle_tag('filtered_search')
%div{ class: container_class } - if @project.merge_requests.exists?
.top-area %div{ class: container_class }
= render 'shared/issuable/nav', type: :merge_requests .top-area
.nav-controls = render 'shared/issuable/nav', type: :merge_requests
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) .nav-controls
- if merge_project - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do - if merge_project
New Merge Request = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New merge request" do
New merge request
= render 'shared/issuable/search_bar', type: :merge_requests = render 'shared/issuable/search_bar', type: :merge_requests
.merge-requests-holder .merge-requests-holder
= render 'merge_requests' = render 'merge_requests'
- else
= render 'shared/empty_states/merge_requests', button_path: new_namespace_project_merge_request_path(@project.namespace, @project)
...@@ -78,7 +78,7 @@ ...@@ -78,7 +78,7 @@
- if git_import_enabled? - if git_import_enabled?
%button.btn.js-toggle-button.import_git{ type: "button" } %button.btn.js-toggle-button.import_git{ type: "button" }
= icon('git', text: 'Repo by URL') = icon('git', text: 'Repo by URL')
.import_gitlab_project .import_gitlab_project.has-tooltip{ data: { container: 'body' } }
- if gitlab_project_import_enabled? - if gitlab_project_import_enabled?
= link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do = link_to new_import_gitlab_project_path, class: 'btn btn_import_gitlab_project project-submit' do
= icon('gitlab', text: 'GitLab export') = icon('gitlab', text: 'GitLab export')
...@@ -109,6 +109,9 @@ ...@@ -109,6 +109,9 @@
%p Please wait a moment, this page will automatically refresh when ready. %p Please wait a moment, this page will automatically refresh when ready.
:javascript :javascript
var importBtnTooltip = "Please enter a valid project name.";
var $importBtnWrapper = $('.import_gitlab_project');
$('.how_to_import_link').bind('click', function (e) { $('.how_to_import_link').bind('click', function (e) {
e.preventDefault(); e.preventDefault();
var import_modal = $(this).next(".modal").show(); var import_modal = $(this).next(".modal").show();
...@@ -123,15 +126,8 @@ ...@@ -123,15 +126,8 @@
$(".btn_import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val()); $(".btn_import_gitlab_project").attr("href", _href + '?namespace_id=' + $("#project_namespace_id").val() + '&path=' + $("#project_path").val());
}); });
$('.btn_import_gitlab_project').attr('disabled',true) $('.btn_import_gitlab_project').attr('disabled', $('#project_path').val().trim().length === 0);
$('.import_gitlab_project').attr('title', 'Project path and name required.'); $importBtnWrapper.attr('title', importBtnTooltip);
$('.import_gitlab_project').click(function( event ) {
if($('.btn_import_gitlab_project').attr('disabled')) {
event.preventDefault();
new Flash("Please enter path and name for the project to be imported to.");
}
});
$('#new_project').submit(function(){ $('#new_project').submit(function(){
var $path = $('#project_path'); var $path = $('#project_path');
...@@ -139,13 +135,13 @@ ...@@ -139,13 +135,13 @@
}); });
$('#project_path').keyup(function(){ $('#project_path').keyup(function(){
if($(this).val().length !=0) { if($(this).val().trim().length !== 0) {
$('.btn_import_gitlab_project').attr('disabled', false); $('.btn_import_gitlab_project').attr('disabled', false);
$('.import_gitlab_project').attr('title',''); $importBtnWrapper.attr('title','');
$(".flash-container").html("") $importBtnWrapper.removeClass('has-tooltip');
} else { } else {
$('.btn_import_gitlab_project').attr('disabled',true); $('.btn_import_gitlab_project').attr('disabled',true);
$('.import_gitlab_project').attr('title', 'Project path and name required.'); $importBtnWrapper.addClass('has-tooltip');
} }
}); });
......
- commit_message = @page.persisted? ? "Update #{@page.title}" : "Create #{@page.title}"
= form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'form-horizontal wiki-form common-note-form prepend-top-default js-quick-submit' } do |f| = form_for [@project.namespace.becomes(Namespace), @project, @page], method: @page.persisted? ? :put : :post, html: { class: 'form-horizontal wiki-form common-note-form prepend-top-default js-quick-submit' } do |f|
= form_errors(@page) = form_errors(@page)
...@@ -28,7 +30,7 @@ ...@@ -28,7 +30,7 @@
.form-group .form-group
= f.label :commit_message, class: 'control-label' = f.label :commit_message, class: 'control-label'
.col-sm-10= f.text_field :message, class: 'form-control', rows: 18 .col-sm-10= f.text_field :message, class: 'form-control', rows: 18, value: commit_message
.form-actions .form-actions
- if @page && @page.persisted? - if @page && @page.persisted?
......
...@@ -6,4 +6,4 @@ ...@@ -6,4 +6,4 @@
= paginate @merge_requests, theme: "gitlab" = paginate @merge_requests, theme: "gitlab"
- else - else
.nothing-here-block No merge requests to show = render 'shared/empty_states/merge_requests'
- button_path = local_assigns.fetch(:button_path, false)
- project_select_button = local_assigns.fetch(:project_select_button, false)
- has_button = button_path || project_select_button
.row.empty-state.merge-requests
.col-xs-12{ class: "#{'col-sm-6 pull-right' if has_button}" }
.svg-content
= render 'shared/empty_states/icons/merge_requests.svg'
.col-xs-12{ class: "#{'col-sm-6' if has_button}" }
.text-content
- if has_button
%h4
Merge requests are a place to propose changes you've made to a project and discuss those changes with others.
%p
Interested parties can even contribute by pushing commits if they want to.
- if project_select_button
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: 'New merge request'
- else
= link_to 'New merge request', button_path, class: 'btn btn-new', title: 'New merge request', id: 'new_merge_request_link'
- else
%h4.text-center
There are no merge requests to show.
<svg xmlns="http://www.w3.org/2000/svg" viewBox="755 221 385 225" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><rect id="a" width="278" height="179" rx="10"/><mask id="d" width="278" height="179" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><path id="b" d="M13.6 49H57c5.5 0 10-4.5 10-10V10c0-5.5-4.5-10-10-10H10C4.5 0 0 4.5 0 10v42c0 5.5 3.2 7 7.2 3l6.4-6z"/><mask id="e" width="67" height="57.2" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><path id="c" d="M13.6 49H57c5.5 0 10-4.5 10-10V10c0-5.5-4.5-10-10-10H10C4.5 0 0 4.5 0 10v42c0 5.5 3.2 7 7.2 3l6.4-6z"/><mask id="f" width="67" height="57.2" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask></defs><g fill="none" fill-rule="evenodd"><g fill="#F9F9F9" transform="translate(752 227)"><rect width="120" height="22" x="30" rx="11"/><rect width="132" height="22" y="44" rx="11"/><rect width="190" height="22" x="208" y="66" rx="11"/><rect width="158" height="22" x="129" y="197" rx="11"/><rect width="158" height="22" x="66" y="154" rx="11"/><rect width="350" height="22" x="31" y="110" rx="11"/><path d="M153 22H21h21.5c6 0 11 5 11 11s-5 11-11 11H21h132-36.5c-6 0-11-5-11-11s5-11 11-11H153zm252 66H288h36.5c6 0 11 5 11 11s-5 11-11 11H288h117-36.5c-6 0-11-5-11-11s5-11 11-11H405zm-244 44H44h36.5c6 0 11 5 11 11s-5 11-11 11H44h117-36.5c-6 0-11-5-11-11s5-11 11-11H161zm75 44H119h21.5c6 0 11 5 11 11s-5 11-11 11H119h117-51.5c-6 0-11-5-11-11s5-11 11-11H236z"/></g><g transform="translate(812 240)"><use fill="#FFF" stroke="#EEE" stroke-width="8" mask="url(#d)" xlink:href="#a"/><path fill="#EEE" d="M4 29h271v4H4z"/><g transform="translate(34 60)"><rect width="6" height="2" y="1" fill="#B5A7DD" rx="1"/><rect width="15" height="4" x="15" fill="#EEE" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#EEE" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="48" fill="#FC6D26" opacity=".5" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#EEE" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#FC6D26" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#B5A7DD" rx="1"/><rect width="6" height="2" y="23" fill="#B5A7DD" rx="1"/></g><g transform="translate(34 93)"><rect width="6" height="2" y="1" fill="#B5A7DD" rx="1"/><rect width="15" height="4" x="15" fill="#FC6D26" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#FC6D26" opacity=".5" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#EEE" rx="2"/><rect width="20" height="4" x="48" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#FC6D26" opacity=".5" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#B5A7DD" rx="1"/><rect width="6" height="2" y="23" fill="#B5A7DD" rx="1"/></g><g transform="translate(34 126)"><rect width="6" height="2" y="1" fill="#B5A7DD" rx="1"/><rect width="15" height="4" x="15" fill="#EEE" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#EEE" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#EEE" rx="2"/><rect width="20" height="4" x="48" fill="#FC6D26" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#EEE" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#FC6D26" opacity=".5" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#B5A7DD" rx="1"/><rect width="6" height="2" y="23" fill="#B5A7DD" rx="1"/></g><g transform="translate(157 59)"><rect width="6" height="2" y="1" fill="#FDE5D8" rx="1"/><rect width="15" height="4" x="15" fill="#EEE" rx="2"/><rect width="15" height="4" x="72" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="22" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="15" height="4" x="53" y="11" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="48" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="20" height="4" x="15" y="22" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="29" y="11" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" fill="#6B4FBB" rx="2"/><rect width="10" height="4" x="15" y="11" fill="#EEE" rx="2"/><rect width="6" height="2" y="12" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="23" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="34" fill="#FDE5D8" rx="1"/><rect width="15" height="4" x="15" y="33" fill="#EEE" rx="2"/><rect width="15" height="4" x="58" y="22" fill="#EEE" rx="2"/><rect width="15" height="4" x="39" y="55" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="15" height="4" x="29" y="44" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="48" y="33" fill="#6B4FBB" rx="2"/><rect width="20" height="4" x="15" y="55" fill="#EEE" rx="2"/><rect width="10" height="4" x="34" y="33" fill="#EEE" rx="2"/><rect width="10" height="4" x="15" y="44" fill="#EEE" rx="2"/><rect width="10" height="4" x="48" y="44" fill="#EEE" rx="2"/><rect width="10" height="4" x="62" y="44" fill="#EEE" rx="2"/><rect width="10" height="4" x="77" y="22" fill="#EEE" rx="2"/><rect width="6" height="2" y="45" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="56" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="67" fill="#FDE5D8" rx="1"/><rect width="15" height="4" x="15" y="66" fill="#6B4FBB" rx="2"/><rect width="15" height="4" x="39" y="88" fill="#EEE" rx="2"/><rect width="15" height="4" x="53" y="77" fill="#6B4FBB" opacity=".5" rx="2"/><rect width="20" height="4" x="15" y="88" fill="#EEE" rx="2"/><rect width="20" height="4" x="29" y="77" fill="#6B4FBB" rx="2"/><rect width="10" height="4" x="34" y="66" fill="#EEE" rx="2"/><rect width="10" height="4" x="72" y="77" fill="#EEE" rx="2"/><rect width="10" height="4" x="15" y="77" fill="#EEE" rx="2"/><rect width="6" height="2" y="78" fill="#FDE5D8" rx="1"/><rect width="6" height="2" y="89" fill="#FDE5D8" rx="1"/></g></g><g transform="translate(1057 221)"><use fill="#FFF" stroke="#FDE5D8" stroke-width="8" mask="url(#e)" xlink:href="#b"/><rect width="29" height="3" x="14" y="14" fill="#FDB692" rx="1.5"/><rect width="39" height="3" x="14" y="23" fill="#FDB692" rx="1.5"/><rect width="29" height="3" x="14" y="32" fill="#FDB692" rx="1.5"/></g><g transform="translate(1046 285)"><circle cx="16" cy="15" r="15" fill="#FFF7F4" stroke="#FC6D26" stroke-width="3"/><path stroke="#FC6D26" stroke-width="2" d="M0 14h1c5 0 9.2-2.7 11.4-6.7M14 1V0"/><path stroke="#FC6D26" stroke-width="2" d="M7.8 3c3 4.3 7.8 7 13.2 7 3.3 0 6.3-1 9-2.7"/><circle cx="10.5" cy="17.5" r="1.5" fill="#FC6D26"/><circle cx="21.5" cy="17.5" r="1.5" fill="#FC6D26"/></g><g transform="translate(825 370)"><circle cx="15" cy="16" r="15" fill="#F4F1FA" stroke="#6B4FBB" stroke-width="3"/><path fill="#6B4FBB" d="M25 7h2.7C25 2.8 20.4 0 15 0 9.6 0 5 2.8 2.3 7H5l2.5-3L10 7l2.5-3L15 7l2.5-3L20 7l2.5-3L25 7z"/><circle cx="9.5" cy="17.5" r="1.5" fill="#6B4FBB"/><circle cx="20.5" cy="17.5" r="1.5" fill="#6B4FBB"/></g><g transform="matrix(-1 0 0 1 840 306)"><use fill="#FFF" stroke="#E2DCF2" stroke-width="8" mask="url(#f)" xlink:href="#c"/><rect width="29" height="3" x="24" y="14" fill="#6B4FBB" opacity=".5" rx="1.5"/><rect width="19" height="3" x="34" y="23" fill="#6B4FBB" opacity=".5" rx="1.5"/><rect width="19" height="3" x="34" y="32" fill="#6B4FBB" opacity=".5" rx="1.5"/></g></g></svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
<title>path-1</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="_activity" fill="#7E7D7D">
<g id="Page-1">
<g id="path-1">
<path d="M5,0 C4.448,0 4,0.448 4,1 L4,3 L1,3 C0.448,3 0,3.448 0,4 L0,9 C0,9.552 0.448,10 1,10 L5,10 L5,8 L11,8 L11,10 L15,10 C15.552,10 16,9.552 16,9 L16,4 C16,3.448 15.552,3 15,3 L12,3 L12,1 C12,0.448 11.552,0 11,0 L5,0 L5,0 L5,0 L5,0 Z M6,2.5 C6,2.224 6.224,2 6.5,2 L9.5,2 C9.776,2 10,2.224 10,2.5 C10,2.776 9.776,3 9.5,3 L6.5,3 C6.224,3 6,2.776 6,2.5 L6,2.5 L6,2.5 L6,2.5 Z M6,11 L10.001,11 L10.001,9 L6,9 L6,11 L6,11 L6,11 L6,11 Z M11,11 L11,12 L5,12 L5,11 L1,11 C0.448,11 0,11.448 0,12 L0,15 C0,15.552 0.448,16 1,16 L15,16 C15.552,16 16,15.552 16,15 L16,12 C16,11.448 15.552,11 15,11 L11,11 L11,11 L11,11 L11,11 Z"></path>
</g>
</g>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
<title>Pasted Image 240</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M3,8 C3,5.951 4.236,4.194 6,3.422 L6,0 L1,0 C0.448,0 0,0.448 0,1 L0,15 C0,15.552 0.448,16 1,16 L6,16 L6,12.578 C4.236,11.806 3,10.049 3,8 M7,12.899 L7,16 L9,16 L9,12.899 C8.677,12.965 8.343,13 8,13 C7.657,13 7.323,12.965 7,12.899 M15,0 L10,0 L10,3.422 C11.764,4.194 13,5.951 13,8 C13,10.049 11.764,11.806 10,12.578 L10,16 L15,16 C15.552,16 16,15.552 16,15 L16,1 C16,0.448 15.552,0 15,0 M10,8 C10,9.105 9.105,10 8,10 C6.895,10 6,9.105 6,8 C6,6.895 6.895,6 8,6 C9.105,6 10,6.895 10,8 M4,8 C4,10.209 5.791,12 8,12 C10.209,12 12,10.209 12,8 C12,5.791 10.209,4 8,4 C5.791,4 4,5.791 4,8 M9,3.101 L9,0 L7,0 L7,3.101 C7.323,3.035 7.657,3 8,3 C8.343,3 8.677,3.035 9,3.101" id="Pasted-Image-240" fill="#7E7D7D"></path>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.7.2 (28276) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group">
<path d="M8,0 C3.581,0 0,3.581 0,8 C0,12.419 3.581,16 8,16 C12.419,16 16,12.419 16,8 C16,3.581 12.419,0 8,0 M8,2 C11.308,2 14,4.692 14,8 C14,11.308 11.308,14 8,14 C4.692,14 2,11.308 2,8 C2,4.692 4.692,2 8,2" id="Fill-1" fill="#7E7C7C"></path>
<polygon id="Stroke-6" fill="#7E7C7C" points="2.0197351 9.86809696 6.4567351 6.52409696 5.79233671 6.46815759 9.53233671 10.4271576 9.87070552 10.78534 10.2338016 10.4522494 15.0258016 6.05624938 14.3497984 5.31935062 9.55779844 9.71535062 10.2592633 9.74044241 6.51926329 5.78144241 6.21208651 5.45627854 5.8548649 5.72550304 1.4178649 9.06950304"></polygon>
<path d="M7.0313,6.3928 C7.0313,6.9448 6.5833,7.3928 6.0313,7.3928 C5.4793,7.3928 5.0313,6.9448 5.0313,6.3928 C5.0313,5.8408 5.4793,5.3928 6.0313,5.3928 C6.5833,5.3928 7.0313,5.8408 7.0313,6.3928" id="Fill-8" fill="#FEFEFE"></path>
<path d="M6.5313,6.3928 C6.5313,6.66865763 6.30715763,6.8928 6.0313,6.8928 C5.75544237,6.8928 5.5313,6.66865763 5.5313,6.3928 C5.5313,6.11694237 5.75544237,5.8928 6.0313,5.8928 C6.30715763,5.8928 6.5313,6.11694237 6.5313,6.3928 L6.5313,6.3928 Z M7.5313,6.3928 C7.5313,5.56465763 6.85944237,4.8928 6.0313,4.8928 C5.20315763,4.8928 4.5313,5.56465763 4.5313,6.3928 C4.5313,7.22094237 5.20315763,7.8928 6.0313,7.8928 C6.85944237,7.8928 7.5313,7.22094237 7.5313,6.3928 L7.5313,6.3928 Z" id="Stroke-10" fill="#7E7C7C"></path>
<path d="M10.8854,9.8715 C10.8854,10.4235 10.4374,10.8715 9.8854,10.8715 C9.3334,10.8715 8.8854,10.4235 8.8854,9.8715 C8.8854,9.3195 9.3334,8.8715 9.8854,8.8715 C10.4374,8.8715 10.8854,9.3195 10.8854,9.8715" id="Fill-12" fill="#FEFEFE"></path>
<path d="M10.3854,9.8715 C10.3854,10.1473576 10.1612576,10.3715 9.8854,10.3715 C9.60954237,10.3715 9.3854,10.1473576 9.3854,9.8715 C9.3854,9.59564237 9.60954237,9.3715 9.8854,9.3715 C10.1612576,9.3715 10.3854,9.59564237 10.3854,9.8715 L10.3854,9.8715 Z M11.3854,9.8715 C11.3854,9.04335763 10.7135424,8.3715 9.8854,8.3715 C9.05725763,8.3715 8.3854,9.04335763 8.3854,9.8715 C8.3854,10.6996424 9.05725763,11.3715 9.8854,11.3715 C10.7135424,11.3715 11.3854,10.6996424 11.3854,9.8715 L11.3854,9.8715 Z" id="Stroke-14" fill="#7E7C7C"></path>
</g>
</g>
</svg>
\ No newline at end of file
<svg width="14px" height="10px" viewBox="322 21 14 10" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<path d="M330.078605,22.8166945 L335.259532,29.6235062 C335.615145,30.0907182 335.412062,30.4694683 334.822641,30.4694683 L331.657805,30.4694683 L324.04678,30.4694683 C323.449879,30.4694683 323.260751,30.0822112 323.609889,29.6235062 L328.790816,22.8166945 C329.146429,22.3494825 329.729467,22.3579895 330.078605,22.8166945 Z" id="delta" stroke="#5C5C5C" stroke-width="1" fill="none"></path>
</svg>
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
<title>Pasted Image 237</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Pasted-Image-237">
<path d="M15.1111,16 C15.6021,16 16.0001,15.602 16.0001,15.111 L16.0001,4.444 C15.5341,3.983 12.0671,0.378 11.5551,0 L0.8891,0 C0.3981,0 0.0001,0.398 0.0001,0.889 L0.0001,15.111 C0.0001,15.602 0.3981,16 0.8891,16 L15.1111,16 M14.0001,14.111 L1.8891,14.111 L1.8891,2 L10.8131,2 C11.4451,2.42 13.5811,4.555 14.0001,5.187 L14.0001,14.111" id="Fill-1" fill="#7E7D7D"></path>
<path d="M0.889,0 C0.398,0 0,0.398 0,0.889 L0,15.111 C0,15.602 0.398,16 0.889,16 L15.111,16 C15.602,16 16,15.602 16,15.111 L16,4.445 C15.534,3.983 12.068,0.377 11.555,0 L0.889,0 L0.889,0 Z M1.889,2 L10.813,2 C11.446,2.42 13.581,4.554 14,5.187 L14,14.111 L1.889,14.111 L1.889,2 L1.889,2 Z" id="Clip-4"></path>
<polygon id="Fill-6" fill="#7E7D7D" points="9 7 11 7 11 2 9 2"></polygon>
<polygon id="Clip-9" points="9 7 11 7 11 2.001 9 2.001"></polygon>
<polygon id="Fill-11" fill="#7E7D7D" points="10 7 15.444 7 15.444 5 10 5"></polygon>
<polygon id="Clip-14" points="10 7 15.444 7 15.444 5 10 5"></polygon>
</g>
</g>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 15"><path d="M9,7.5l5.83-5.91a.48.48,0,0,0,0-.69L14.11.15a.46.46,0,0,0-.68,0l-5.93,6L1.57.15a.46.46,0,0,0-.68,0L.15.9a.48.48,0,0,0,0,.69L6,7.5.15,13.41a.48.48,0,0,0,0,.69l.74.75a.46.46,0,0,0,.68,0l5.93-6,5.93,6a.46.46,0,0,0,.68,0l.74-.75a.48.48,0,0,0,0-.69Z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 15 15"><path d="M9,7.5l5.83-5.91a.48.48,0,0,0,0-.69L14.11.15a.46.46,0,0,0-.68,0l-5.93,6L1.57.15a.46.46,0,0,0-.68,0L.15.9a.48.48,0,0,0,0,.69L6,7.5.15,13.41a.48.48,0,0,0,0,.69l.74.75a.46.46,0,0,0,.68,0l5.93-6,5.93,6a.46.46,0,0,0,.68,0l.74-.75a.48.48,0,0,0,0-.69Z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill-rule="evenodd"><path d="m8.411 1.012c-.136-.008-.273-.012-.411-.012-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7 3.866 0 7-3.134 7-7 0-.138-.004-.275-.012-.411-.464.201-.964.334-1.488.386 0 .008 0 .016 0 .025 0 3.038-2.462 5.5-5.5 5.5-3.038 0-5.5-2.462-5.5-5.5 0-3.038 2.462-5.5 5.5-5.5.008 0 .016 0 .025 0 .052-.524.185-1.024.386-1.488"/><path d="m12 2h-1.01c-.54 0-.991.448-.991 1 0 .556.444 1 .991 1h1.01v1.01c0 .54.448.991 1 .991.556 0 1-.444 1-.991v-1.01h1.01c.54 0 .991-.448.991-1 0-.556-.444-1-.991-1h-1.01v-1.01c0-.54-.448-.991-1-.991-.556 0-1 .444-1 .991v1.01m-5 4.01c0-.557.444-1.01 1-1.01.552 0 1 .443 1 1.01v1.981c0 .557-.444 1.01-1 1.01-.552 0-1-.443-1-1.01v-1.981m1 5.991c.552 0 1-.448 1-1 0-.552-.448-1-1-1-.552 0-1 .448-1 1 0 .552.448 1 1 1"/></g></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><g fill-rule="evenodd"><path d="m8.411 1.012c-.136-.008-.273-.012-.411-.012-3.866 0-7 3.134-7 7 0 3.866 3.134 7 7 7 3.866 0 7-3.134 7-7 0-.138-.004-.275-.012-.411-.464.201-.964.334-1.488.386 0 .008 0 .016 0 .025 0 3.038-2.462 5.5-5.5 5.5-3.038 0-5.5-2.462-5.5-5.5 0-3.038 2.462-5.5 5.5-5.5.008 0 .016 0 .025 0 .052-.524.185-1.024.386-1.488"/><path d="m12 2h-1.01c-.54 0-.991.448-.991 1 0 .556.444 1 .991 1h1.01v1.01c0 .54.448.991 1 .991.556 0 1-.444 1-.991v-1.01h1.01c.54 0 .991-.448.991-1 0-.556-.444-1-.991-1h-1.01v-1.01c0-.54-.448-.991-1-.991-.556 0-1 .444-1 .991v1.01m-5 4.01c0-.557.444-1.01 1-1.01.552 0 1 .443 1 1.01v1.981c0 .557-.444 1.01-1 1.01-.552 0-1-.443-1-1.01v-1.981m1 5.991c.552 0 1-.448 1-1 0-.552-.448-1-1-1-.552 0-1 .448-1 1 0 .552.448 1 1 1"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 11" class="icon-play"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 11" class="icon-play"><path fill-rule="evenodd" d="m9.283 6.47l-7.564 4.254c-.949.534-1.719.266-1.719-.576v-9.292c0-.852.756-1.117 1.719-.576l7.564 4.254c.949.534.963 1.392 0 1.934"/></svg>
<path fill-rule="evenodd" d="m9.283 6.47l-7.564 4.254c-.949.534-1.719.266-1.719-.576v-9.292c0-.852.756-1.117 1.719-.576l7.564 4.254c.949.534.963 1.392 0 1.934"/>
</svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 14" enable-background="new 0 0 12 14"><path d="m11.5 2.4l-1.3-1.1-1 1.1 1.4 1.1.9-1.1"/><path d="m6.8 2v-.5h.5v-1.5h-2.6v1.5h.5v.5c-2.9.4-5.2 2.9-5.2 6 0 3.3 2.7 6 6 6s6-2.7 6-6c0-3-2.3-5.6-5.2-6m-.8 10.5c-2.5 0-4.5-2-4.5-4.5s2-4.5 4.5-4.5 4.5 2 4.5 4.5-2 4.5-4.5 4.5"/><path d="m6.2 8.9h-.5c-.1 0-.2-.1-.2-.2v-3.5c0-.1.1-.2.2-.2h.5c.1 0 .2.1.2.2v3.5c0 .1-.1.2-.2.2"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 12 14" enable-background="new 0 0 12 14"><path d="m11.5 2.4l-1.3-1.1-1 1.1 1.4 1.1.9-1.1"/><path d="m6.8 2v-.5h.5v-1.5h-2.6v1.5h.5v.5c-2.9.4-5.2 2.9-5.2 6 0 3.3 2.7 6 6 6s6-2.7 6-6c0-3-2.3-5.6-5.2-6m-.8 10.5c-2.5 0-4.5-2-4.5-4.5s2-4.5 4.5-4.5 4.5 2 4.5 4.5-2 4.5-4.5 4.5"/><path d="m6.2 8.9h-.5c-.1 0-.2-.1-.2-.2v-3.5c0-.1.1-.2.2-.2h.5c.1 0 .2.1.2.2v3.5c0 .1-.1.2-.2.2"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><g fill="#8F8F8F" fill-rule="evenodd"><path d="M29.513 10.134A15.922 15.922 0 0 0 23 7.28V6h2.993C26.55 6 27 5.552 27 5V2a1 1 0 0 0-1.007-1H14.007C13.45 1 13 1.448 13 2v3a1 1 0 0 0 1.007 1H17v1.28C9.597 8.686 4 15.19 4 23c0 8.837 7.163 16 16 16s16-7.163 16-16c0-3.461-1.099-6.665-2.967-9.283l1.327-1.58a2.498 2.498 0 0 0-.303-3.53 2.499 2.499 0 0 0-3.528.315l-1.016 1.212zM20 34c6.075 0 11-4.925 11-11s-4.925-11-11-11S9 16.925 9 23s4.925 11 11 11z"/><path d="M19 21h-4.002c-.552 0-.998.452-.998 1.01v1.98c0 .567.447 1.01.998 1.01h7.004c.274 0 .521-.111.701-.291a.979.979 0 0 0 .297-.704v-8.01c0-.54-.452-.995-1.01-.995h-1.98a.997.997 0 0 0-1.01.995V21z"/></g></svg> <svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><g fill="#8F8F8F" fill-rule="evenodd"><path d="M29.513 10.134A15.922 15.922 0 0 0 23 7.28V6h2.993C26.55 6 27 5.552 27 5V2a1 1 0 0 0-1.007-1H14.007C13.45 1 13 1.448 13 2v3a1 1 0 0 0 1.007 1H17v1.28C9.597 8.686 4 15.19 4 23c0 8.837 7.163 16 16 16s16-7.163 16-16c0-3.461-1.099-6.665-2.967-9.283l1.327-1.58a2.498 2.498 0 0 0-.303-3.53 2.499 2.499 0 0 0-3.528.315l-1.016 1.212zM20 34c6.075 0 11-4.925 11-11s-4.925-11-11-11S9 16.925 9 23s4.925 11 11 11z"/><path d="M19 21h-4.002c-.552 0-.998.452-.998 1.01v1.98c0 .567.447 1.01.998 1.01h7.004c.274 0 .521-.111.701-.291a.979.979 0 0 0 .297-.704v-8.01c0-.54-.452-.995-1.01-.995h-1.98a.997.997 0 0 0-1.01.995V21z"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 168 107" xmlns:xlink="http://www.w3.org/1999/xlink"><g fill="#eee" fill-rule="evenodd"><path d="m4.01 2h1.102c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-1.102c-2.218 0-4.01 1.788-4.01 4 0 .552.448 1 1 1 .552 0 1-.448 1-1 0-1.108.892-2 2.01-2m12.702 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m8.088 0c.822 0 1.554.503 1.86 1.254.208.512.791.758 1.303.55.512-.208.758-.791.55-1.303-.609-1.497-2.069-2.5-3.712-2.5h-2.188c-.552 0-1 .448-1 1 0 .552.448 1 1 1h2.188m2.01 12.518c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 11.6c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 11.6c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 6.282c0 1.108-.892 2-2.01 2h-.72c-.552 0-1 .448-1 1 0 .552.448 1 1 1h.72c2.218 0 4.01-1.788 4.01-4v-.382c0-.552-.448-1-1-1-.552 0-1 .448-1 1v.382m-14.325 2c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-8.47 0c-.755 0-1.438-.424-1.782-1.085-.255-.49-.859-.681-1.349-.426-.49.255-.681.859-.426 1.349.684 1.316 2.046 2.162 3.556 2.162h2.57c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-2.57m-2.01-12.136c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-11.6c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-11.6c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-6.664c0-.552-.448-1-1-1-.552 0-1 .448-1 1v.764c0 .552.448 1 1 1 .552 0 1-.448 1-1v-.764" id="0"/><circle cx="21" cy="24" r="10"/><rect width="33" height="3" x="37" y="18" rx="1.5" id="1"/><rect width="53" height="3" x="37" y="27" rx="1.5" id="2"/><path d="m131 29c0 .552.447.999.996.999h22.01c.545 0 .996-.451.996-.999v-9c0-.552-.447-.999-.996-.999h-22.01c-.545 0-.996.451-.996.999v9m.996-12h22.01c1.655 0 2.996 1.344 2.996 2.999v9c0 1.657-1.35 2.999-2.996 2.999h-22.01c-1.655 0-2.996-1.344-2.996-2.999v-9c0-1.657 1.35-2.999 2.996-2.999" id="3"/><g transform="translate(0 59)"><use xlink:href="#0"/><circle cx="21" cy="24" r="10"/><use xlink:href="#1"/><use xlink:href="#2"/><use xlink:href="#3"/></g></g></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 168 107" xmlns:xlink="http://www.w3.org/1999/xlink"><g fill="#eee" fill-rule="evenodd"><path d="m4.01 2h1.102c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-1.102c-2.218 0-4.01 1.788-4.01 4 0 .552.448 1 1 1 .552 0 1-.448 1-1 0-1.108.892-2 2.01-2m12.702 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m11.6 0c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7m8.088 0c.822 0 1.554.503 1.86 1.254.208.512.791.758 1.303.55.512-.208.758-.791.55-1.303-.609-1.497-2.069-2.5-3.712-2.5h-2.188c-.552 0-1 .448-1 1 0 .552.448 1 1 1h2.188m2.01 12.518c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 11.6c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 11.6c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7m0 6.282c0 1.108-.892 2-2.01 2h-.72c-.552 0-1 .448-1 1 0 .552.448 1 1 1h.72c2.218 0 4.01-1.788 4.01-4v-.382c0-.552-.448-1-1-1-.552 0-1 .448-1 1v.382m-14.325 2c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-11.6 0c-.552 0-1 .448-1 1 0 .552.448 1 1 1h5.7c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-5.7m-8.47 0c-.755 0-1.438-.424-1.782-1.085-.255-.49-.859-.681-1.349-.426-.49.255-.681.859-.426 1.349.684 1.316 2.046 2.162 3.556 2.162h2.57c.552 0 1-.448 1-1 0-.552-.448-1-1-1h-2.57m-2.01-12.136c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-11.6c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-11.6c0-.552-.448-1-1-1-.552 0-1 .448-1 1v5.7c0 .552.448 1 1 1 .552 0 1-.448 1-1v-5.7m0-6.664c0-.552-.448-1-1-1-.552 0-1 .448-1 1v.764c0 .552.448 1 1 1 .552 0 1-.448 1-1v-.764" id="0"/><circle cx="21" cy="24" r="10"/><rect width="33" height="3" x="37" y="18" rx="1.5" id="1"/><rect width="53" height="3" x="37" y="27" rx="1.5" id="2"/><path d="m131 29c0 .552.447.999.996.999h22.01c.545 0 .996-.451.996-.999v-9c0-.552-.447-.999-.996-.999h-22.01c-.545 0-.996.451-.996.999v9m.996-12h22.01c1.655 0 2.996 1.344 2.996 2.999v9c0 1.657-1.35 2.999-2.996 2.999h-22.01c-1.655 0-2.996-1.344-2.996-2.999v-9c0-1.657 1.35-2.999 2.996-2.999" id="3"/><g transform="translate(0 59)"><use xlink:href="#0"/><circle cx="21" cy="24" r="10"/><use xlink:href="#1"/><use xlink:href="#2"/><use xlink:href="#3"/></g></g></svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="22px" height="16px" viewBox="0 0 22 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.7.2 (28276) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" fill="#7E7C7C">
<path d="M6.4357,11.8588 C7.1487,11.2798 7.8797,10.7808 8.5357,10.3708 C8.5837,10.3008 8.6187,10.2338 8.6187,10.1768 L8.6187,8.8088 C8.9197,8.5218 9.0927,8.1248 9.0927,7.7028 L9.0927,5.3748 C9.0927,3.9478 7.9187,2.7858 6.4757,2.7858 L5.9687,2.7858 C4.5247,2.7858 3.3507,3.9478 3.3507,5.3748 L3.3507,7.7028 C3.3507,8.1248 3.5247,8.5218 3.8247,8.8088 L3.8247,10.5838 C3.2537,10.8738 1.8797,11.6198 0.5967,12.6618 C0.2177,12.9698 -0.0003,13.4258 -0.0003,13.9138 L-0.0003,15.5088 C-0.0003,15.5438 0.0857,15.7668 0.3467,15.7778 C1.3257,15.8198 3.8417,15.8328 5.9617,15.9038 C5.8337,15.8148 5.7447,15.6748 5.7447,15.5088 L5.7447,13.5498 C5.7447,12.9848 5.9967,12.2158 6.4357,11.8588" id="Fill-1"></path>
<path d="M21.3092,12.1 C19.6932,10.787 17.9592,9.86 17.3042,9.53 L17.3042,7.235 C17.6722,6.9 17.8862,6.428 17.8862,5.925 L17.8862,3.066 C17.8862,1.376 16.4952,0 14.7852,0 L14.1632,0 C12.4532,0 11.0622,1.376 11.0622,3.066 L11.0622,5.925 C11.0622,6.428 11.2752,6.9 11.6442,7.235 L11.6442,9.53 C10.9892,9.86 9.2542,10.787 7.6392,12.1 C7.2002,12.457 6.9482,12.985 6.9482,13.55 L6.9482,15.509 C6.9482,15.78 7.1702,16 7.4442,16 L14.1172,16 L14.1172,11.704 C12.6812,11.595 11.5652,10.853 11.5652,9.945 C11.5652,9.804 11.5982,9.669 11.6482,9.538 C11.9502,10.326 13.0982,10.913 14.4762,10.913 C15.8532,10.913 17.0012,10.326 17.3032,9.538 C17.3532,9.669 17.3862,9.804 17.3862,9.945 C17.3862,10.793 16.4152,11.5 15.1172,11.679 L15.1172,16 L21.5032,16 C21.7772,16 22.0002,15.78 22.0002,15.509 L22.0002,13.55 C22.0002,12.985 21.7482,12.457 21.3092,12.1" id="Fill-4"></path>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="17px" viewBox="0 0 16 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.7.2 (28276) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" fill="#7E7C7C">
<path d="M15.1111,1 L0.8891,1 C0.3981,1 0.0001,1.446 0.0001,1.996 L0.0001,15.945 C0.0001,16.495 0.3981,16.941 0.8891,16.941 L15.1111,16.941 C15.6021,16.941 16.0001,16.495 16.0001,15.945 L16.0001,1.996 C16.0001,1.446 15.6021,1 15.1111,1 L15.1111,1 L15.1111,1 Z M14.0001,6.0002 L14.0001,14.949 L2.0001,14.949 L2.0001,6.0002 L14.0001,6.0002 Z M14.0001,4.0002 L14.0001,2.993 L2.0001,2.993 L2.0001,4.0002 L14.0001,4.0002 Z" id="Combined-Shape"></path>
<polygon id="Fill-11" points="3 2.0002 5 2.0002 5 0.0002 3 0.0002"></polygon>
<polygon id="Fill-16" points="11 2.0002 13 2.0002 13 0.0002 11 0.0002"></polygon>
<path d="M5.37709616,11.5511984 L6.92309616,12.7821984 C7.35112915,13.123019 7.97359761,13.0565604 8.32002627,12.6330535 L10.7740263,9.63305349 C11.1237073,9.20557058 11.0606364,8.57555475 10.6331535,8.22587373 C10.2056706,7.87619272 9.57565475,7.93926361 9.22597373,8.36674651 L6.77197373,11.3667465 L8.16890384,11.2176016 L6.62290384,9.98660159 C6.19085236,9.6425813 5.56172188,9.71394467 5.21770159,10.1459962 C4.8736813,10.5780476 4.94504467,11.2071781 5.37709616,11.5511984 L5.37709616,11.5511984 Z" id="Stroke-21"></path>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.7.2 (28276) - http://www.bohemiancoding.com/sketch -->
<title>Group</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Group" fill="#7E7C7C">
<path d="M15.1111,0 L0.8891,0 C0.3981,0 0.0001,0.446 0.0001,0.996 L0.0001,14.945 C0.0001,15.495 0.3981,15.941 0.8891,15.941 L15.1111,15.941 C15.6021,15.941 16.0001,15.495 16.0001,14.945 L16.0001,0.996 C16.0001,0.446 15.6021,0 15.1111,0 L15.1111,0 L15.1111,0 Z M2.0001,13.949 L14.0001,13.949 L14.0001,1.993 L2.0001,1.993 L2.0001,13.949 Z M2,5.0002 L14,5.0002 L14,3.0002 L2,3.0002 L2,5.0002 Z" id="Combined-Shape"></path>
<path d="M8.547,12.0002 L12,12.0002 L12,10.0002 L8.547,10.0002 L8.547,12.0002 Z M5.2029,12 L3.9999,10.867 L5.2029,9.501 L3.9999,8.181 L5.2029,7 L7.4529,9.499 L5.2029,12 Z" id="Combined-Shape"></path>
</g>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
<title>Pasted Image 246</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M12.5,14 C11.672,14 11,13.328 11,12.5 C11,11.672 11.672,11 12.5,11 C13.328,11 14,11.672 14,12.5 C14,13.328 13.328,14 12.5,14 M12.5,9 L3.5,9 C1.567,9 0,10.567 0,12.5 C0,14.433 1.567,16 3.5,16 L12.5,16 C14.433,16 16,14.433 16,12.5 C16,10.567 14.433,9 12.5,9 M3.5,2 C4.328,2 5,2.672 5,3.5 C5,4.328 4.328,5 3.5,5 C2.672,5 2,4.328 2,3.5 C2,2.672 2.672,2 3.5,2 M3.5,7 L12.5,7 C14.433,7 16,5.433 16,3.5 C16,1.567 14.433,0 12.5,0 L3.5,0 C1.567,0 0,1.567 0,3.5 C0,5.433 1.567,7 3.5,7" id="Pasted-Image-246" fill="#303030"></path>
</g>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 3.8.3 (29802) - http://www.bohemiancoding.com/sketch -->
<title>Pasted Image 241</title>
<desc>Created with Sketch.</desc>
<defs></defs>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<path d="M2.004,12.9999459 L3.939,12.9999459 L3.939,4.99994585 L2.004,4.99994585 L2.004,12.9999459 Z M7.017,9.99994585 L13.018,9.99994585 L13.018,8.99994585 L7.017,8.99994585 L7.017,9.99994585 Z M7.017,7.99994585 L13.018,7.99994585 L13.018,6.99994585 L7.017,6.99994585 L7.017,7.99994585 Z M7.017,5.99994585 L13.018,5.99994585 L13.018,4.99994585 L7.017,4.99994585 L7.017,5.99994585 Z M14.754,-5.41499267e-05 L4.938,-5.41499267e-05 C4.386,-5.41499267e-05 3.938,0.44794585 3.938,0.99994585 L3.938,2.99994585 L1,2.99994585 C0.448,2.99994585 0,3.44794585 0,3.99994585 L0,12.9999459 C0.037,13.4999459 -0.25,16.0509459 3.938,15.9999459 L12.408,15.9999459 C12.408,15.9999459 15.754,15.9169459 15.754,13.9999459 L15.754,0.99994585 C15.754,0.44794585 15.306,-5.41499267e-05 14.754,-5.41499267e-05 L14.754,-5.41499267e-05 Z" id="Pasted-Image-241" fill="#7E7D7D"></path>
</g>
</svg>
\ No newline at end of file
---
title: Added merge requests empty state
merge_request: 7342
author:
---
title: Set GIT_TERMINAL_PROMPT env variable in initializer
merge_request: 10372
author:
---
title: Fix project title validation, prevent clicking on disabled button
merge_request: 9931
author:
---
title: Fixes milestone/merge_requests endpoint to actually scope the result
merge_request:
author: Joren De Groof
---
title: Removed the duplicated search icon in the award emoji menu
merge_request:
author:
---
title: Improved UX for the environments metrics view
merge_request: 9946
author:
---
title: Fix Import/Export MR diffs not showing and missing forked MRs
merge_request:
author:
---
title: Create subgroups if they don't exist while importing projects
merge_request:
author:
---
title: Fix wiki commit message
merge_request: 10464
author: blackst0ne
---
title: Do not set closed_at to nil when issue is reopened
merge_request:
author:
---
title: Handle SSH keys that have multiple spaces between each marker
merge_request:
author:
...@@ -153,6 +153,7 @@ module Gitlab ...@@ -153,6 +153,7 @@ module Gitlab
# This is needed for gitlab-shell # This is needed for gitlab-shell
ENV['GITLAB_PATH_OUTSIDE_HOOK'] = ENV['PATH'] ENV['GITLAB_PATH_OUTSIDE_HOOK'] = ENV['PATH']
ENV['GIT_TERMINAL_PROMPT'] = '0'
# Gitlab Geo Middleware support # Gitlab Geo Middleware support
config.middleware.insert_after ActionDispatch::Flash, 'Gitlab::Middleware::ReadonlyGeo' config.middleware.insert_after ActionDispatch::Flash, 'Gitlab::Middleware::ReadonlyGeo'
......
...@@ -326,3 +326,21 @@ ...@@ -326,3 +326,21 @@
:why: https://github.com/domenic/opener/blob/1.4.3/LICENSE.txt :why: https://github.com/domenic/opener/blob/1.4.3/LICENSE.txt
:versions: [] :versions: []
:when: 2017-02-21 22:33:41.729629000 Z :when: 2017-02-21 22:33:41.729629000 Z
- - :approve
- jszip
- :who: Phil Hughes
:why: https://github.com/Stuk/jszip/blob/master/LICENSE.markdown
:versions: []
:when: 2017-04-05 10:38:46.275721000 Z
- - :approve
- jszip-utils
- :who: Phil Hughes
:why: https://github.com/Stuk/jszip-utils/blob/master/LICENSE.markdown
:versions: []
:when: 2017-04-05 10:39:32.676232000 Z
- - :approve
- pako
- :who: Phil Hughes
:why: https://github.com/nodeca/pako/blob/master/LICENSE
:versions: []
:when: 2017-04-05 10:43:45.897720000 Z
...@@ -40,6 +40,8 @@ var config = { ...@@ -40,6 +40,8 @@ var config = {
monitoring: './monitoring/monitoring_bundle.js', monitoring: './monitoring/monitoring_bundle.js',
network: './network/network_bundle.js', network: './network/network_bundle.js',
notebook_viewer: './blob/notebook_viewer.js', notebook_viewer: './blob/notebook_viewer.js',
sketch_viewer: './blob/sketch_viewer.js',
pdf_viewer: './blob/pdf_viewer.js',
profile: './profile/profile_bundle.js', profile: './profile/profile_bundle.js',
protected_branches: './protected_branches/protected_branches_bundle.js', protected_branches: './protected_branches/protected_branches_bundle.js',
snippet: './snippet/snippet_bundle.js', snippet: './snippet/snippet_bundle.js',
...@@ -67,7 +69,11 @@ var config = { ...@@ -67,7 +69,11 @@ var config = {
{ {
test: /\.svg$/, test: /\.svg$/,
use: 'raw-loader' use: 'raw-loader'
} }, {
test: /\.(worker.js|pdf)$/,
exclude: /node_modules/,
loader: 'file-loader',
},
] ]
}, },
...@@ -109,6 +115,7 @@ var config = { ...@@ -109,6 +115,7 @@ var config = {
'issuable', 'issuable',
'merge_conflicts', 'merge_conflicts',
'notebook_viewer', 'notebook_viewer',
'pdf_viewer',
'vue_pipelines', 'vue_pipelines',
'mr_widget_ee', 'mr_widget_ee',
], ],
......
...@@ -39,6 +39,12 @@ Instead you should use polling mechanism with ETag caching in Redis. ...@@ -39,6 +39,12 @@ Instead you should use polling mechanism with ETag caching in Redis.
1. If the `If-None-Match` header does not match the current value in Redis 1. If the `If-None-Match` header does not match the current value in Redis
we have to generate a new response, because the resource changed. we have to generate a new response, because the resource changed.
Do not use query parameters (for example `?scope=all`) for endpoints where you
want to enable ETag caching. The middleware takes into account only the request
path and ignores query parameters. All parameters should be included in the
request path. By doing this we avoid query parameter ordering problems and make
route matching easier.
For more information see: For more information see:
- [RFC 7232](https://tools.ietf.org/html/rfc7232) - [RFC 7232](https://tools.ietf.org/html/rfc7232)
- [ETag proposal](https://gitlab.com/gitlab-org/gitlab-ce/issues/26926) - [ETag proposal](https://gitlab.com/gitlab-org/gitlab-ce/issues/26926)
...@@ -129,6 +129,9 @@ If you want to run the database separately, expect a size of about 1 MB per user ...@@ -129,6 +129,9 @@ If you want to run the database separately, expect a size of about 1 MB per user
### PostgreSQL Requirements ### PostgreSQL Requirements
As of GitLab 9.0, PostgreSQL 9.6 is recommended. Lower versions of PostgreSQL
may work but primary testing and developement takes place using PostgreSQL 9.6.
Users using PostgreSQL must ensure the `pg_trgm` extension is loaded into every Users using PostgreSQL must ensure the `pg_trgm` extension is loaded into every
GitLab database. This extension can be enabled (using a PostgreSQL super user) GitLab database. This extension can be enabled (using a PostgreSQL super user)
by running the following query for every database: by running the following query for every database:
......
...@@ -63,7 +63,8 @@ Feature: Dashboard ...@@ -63,7 +63,8 @@ Feature: Dashboard
@javascript @javascript
Scenario: Visiting Project's merge requests after sorting Scenario: Visiting Project's merge requests after sorting
Given I visit dashboard merge requests page Given project "Shop" has a "Bugfix MR" merge request open
And I visit dashboard merge requests page
And I sort the list by "Oldest updated" And I sort the list by "Oldest updated"
And I visit project "Shop" merge requests page And I visit project "Shop" merge requests page
Then The list should be sorted by "Oldest updated" Then The list should be sorted by "Oldest updated"
...@@ -56,14 +56,16 @@ Feature: Project Issues ...@@ -56,14 +56,16 @@ Feature: Project Issues
@javascript @javascript
Scenario: Visiting Merge Requests after being sorted the list Scenario: Visiting Merge Requests after being sorted the list
Given I visit project "Shop" issues page Given project "Shop" has a "Bugfix MR" merge request open
And I visit project "Shop" issues page
And I sort the list by "Oldest updated" And I sort the list by "Oldest updated"
And I visit project "Shop" merge requests page And I visit project "Shop" merge requests page
Then The list should be sorted by "Oldest updated" Then The list should be sorted by "Oldest updated"
@javascript @javascript
Scenario: Visiting Merge Requests from a differente Project after sorting Scenario: Visiting Merge Requests from a differente Project after sorting
Given I visit project "Shop" merge requests page Given project "Shop" has a "Bugfix MR" merge request open
And I visit project "Shop" merge requests page
And I sort the list by "Oldest updated" And I sort the list by "Oldest updated"
And I visit dashboard merge requests page And I visit dashboard merge requests page
Then The list should be sorted by "Oldest updated" Then The list should be sorted by "Oldest updated"
......
...@@ -42,8 +42,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps ...@@ -42,8 +42,7 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
end end
step 'I click link "New merge request"' do step 'I click link "New merge request"' do
expect(page).to have_content(/new merge request/i) page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
click_link "New Merge Request"
end end
step 'I should see the new merge request page for my namespace' do step 'I should see the new merge request page for my namespace' do
......
...@@ -16,7 +16,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps ...@@ -16,7 +16,7 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
end end
step 'I click link "New Merge Request"' do step 'I click link "New Merge Request"' do
click_link "New Merge Request" page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
end end
step 'I should see merge request "Merge Request On Forked Project"' do step 'I should see merge request "Merge Request On Forked Project"' do
......
...@@ -24,7 +24,9 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps ...@@ -24,7 +24,9 @@ class Spinach::Features::AwardEmoji < Spinach::FeatureSteps
step 'I click to emoji in the picker' do step 'I click to emoji in the picker' do
page.within '.emoji-menu-content' do page.within '.emoji-menu-content' do
page.first('.js-emoji-btn').click emoji_button = page.first('.js-emoji-btn')
emoji_button.hover
emoji_button.click
end end
end end
......
...@@ -14,7 +14,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps ...@@ -14,7 +14,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end end
step 'I click link "New Merge Request"' do step 'I click link "New Merge Request"' do
click_link "New Merge Request" page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
end end
step 'I click link "Bug NS-04"' do step 'I click link "Bug NS-04"' do
......
...@@ -273,6 +273,10 @@ module SharedProject ...@@ -273,6 +273,10 @@ module SharedProject
@project.update(public_builds: false) @project.update(public_builds: false)
end end
step 'project "Shop" has a "Bugfix MR" merge request open' do
create(:merge_request, title: "Bugfix MR", target_project: project, source_project: project, author: project.users.first)
end
def user_owns_project(user_name:, project_name:, visibility: :private) def user_owns_project(user_name:, project_name:, visibility: :private)
user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore) user = user_exists(user_name, username: user_name.gsub(/\s/, '').underscore)
project = Project.find_by(name: project_name) project = Project.find_by(name: project_name)
......
...@@ -139,7 +139,7 @@ module API ...@@ -139,7 +139,7 @@ module API
finder_params = { finder_params = {
project_id: user_project.id, project_id: user_project.id,
milestone_id: milestone.id, milestone_title: milestone.title,
sort: 'position_asc' sort: 'position_asc'
} }
......
module Gitlab module Gitlab
module EtagCaching module EtagCaching
class Middleware class Middleware
RESERVED_WORDS = ProjectPathValidator::RESERVED.map { |word| "/#{word}/" }.join('|') RESERVED_WORDS = NamespaceValidator::WILDCARD_ROUTES.map { |word| "/#{word}/" }.join('|')
ROUTE_REGEXP = Regexp.union( ROUTE_REGEXP = Regexp.union(
%r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z) %r(^(?!.*(#{RESERVED_WORDS})).*/noteable/issue/\d+/notes\z)
) )
......
module Gitlab
module ImportExport
class HashUtil
def self.deep_symbolize_array!(array)
return if array.blank?
array.map! do |hash|
hash.deep_symbolize_keys!
yield(hash) if block_given?
hash
end
end
def self.deep_symbolize_array_with_date!(array)
self.deep_symbolize_array!(array) do |hash|
hash.select { |k, _v| k.to_s.end_with?('_date') }.each do |key, value|
hash[key] = Time.zone.parse(value)
end
end
end
end
end
end
...@@ -89,3 +89,5 @@ methods: ...@@ -89,3 +89,5 @@ methods:
- :type - :type
merge_request_diff: merge_request_diff:
- :utf8_st_diffs - :utf8_st_diffs
merge_requests:
- :diff_head_sha
...@@ -9,7 +9,7 @@ module Gitlab ...@@ -9,7 +9,7 @@ module Gitlab
end end
def execute def execute
if import_file && check_version! && [project_tree, avatar_restorer, repo_restorer, wiki_restorer, uploads_restorer].all?(&:restore) if import_file && check_version! && [repo_restorer, wiki_restorer, project_tree, avatar_restorer, uploads_restorer].all?(&:restore)
project_tree.restored_project project_tree.restored_project
else else
raise Projects::ImportService::Error.new(@shared.errors.join(', ')) raise Projects::ImportService::Error.new(@shared.errors.join(', '))
......
module Gitlab
module ImportExport
class MergeRequestParser
FORKED_PROJECT_ID = -1
def initialize(project, diff_head_sha, merge_request, relation_hash)
@project = project
@diff_head_sha = diff_head_sha
@merge_request = merge_request
@relation_hash = relation_hash
end
def parse!
if fork_merge_request? && @diff_head_sha
@merge_request.source_project_id = @relation_hash['project_id']
fetch_ref unless branch_exists?(@merge_request.source_branch)
create_target_branch unless branch_exists?(@merge_request.target_branch)
end
@merge_request
end
def create_target_branch
@project.repository.create_branch(@merge_request.target_branch, @merge_request.target_branch_sha)
end
def fetch_ref
@project.repository.fetch_ref(@project.repository.path, @diff_head_sha, @merge_request.source_branch)
end
def branch_exists?(branch_name)
@project.repository.branch_exists?(branch_name)
end
def fork_merge_request?
@relation_hash['source_project_id'] == FORKED_PROJECT_ID
end
end
end
end
...@@ -119,7 +119,7 @@ module Gitlab ...@@ -119,7 +119,7 @@ module Gitlab
relation_hash: parsed_relation_hash(relation_hash), relation_hash: parsed_relation_hash(relation_hash),
members_mapper: members_mapper, members_mapper: members_mapper,
user: @user, user: @user,
project_id: restored_project.id) project: restored_project)
end.compact end.compact
relation_hash_list.is_a?(Array) ? relation_array : relation_array.first relation_hash_list.is_a?(Array) ? relation_array : relation_array.first
......
...@@ -29,11 +29,12 @@ module Gitlab ...@@ -29,11 +29,12 @@ module Gitlab
new(*args).create new(*args).create
end end
def initialize(relation_sym:, relation_hash:, members_mapper:, user:, project_id:) def initialize(relation_sym:, relation_hash:, members_mapper:, user:, project:)
@relation_name = OVERRIDES[relation_sym] || relation_sym @relation_name = OVERRIDES[relation_sym] || relation_sym
@relation_hash = relation_hash.except('noteable_id').merge('project_id' => project_id) @relation_hash = relation_hash.except('noteable_id').merge('project_id' => project.id)
@members_mapper = members_mapper @members_mapper = members_mapper
@user = user @user = user
@project = project
@imported_object_retries = 0 @imported_object_retries = 0
end end
...@@ -66,7 +67,7 @@ module Gitlab ...@@ -66,7 +67,7 @@ module Gitlab
remove_encrypted_attributes! remove_encrypted_attributes!
@relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data'] @relation_hash['data'].deep_symbolize_keys! if @relation_name == :events && @relation_hash['data']
set_st_diffs if @relation_name == :merge_request_diff set_st_diff_commits if @relation_name == :merge_request_diff
end end
def update_user_references def update_user_references
...@@ -105,6 +106,8 @@ module Gitlab ...@@ -105,6 +106,8 @@ module Gitlab
imported_object do |object| imported_object do |object|
object.commit_id = nil object.commit_id = nil
end end
elsif @relation_name == :merge_requests
MergeRequestParser.new(@project, @relation_hash.delete('diff_head_sha'), imported_object, @relation_hash).parse!
else else
imported_object imported_object
end end
...@@ -115,7 +118,7 @@ module Gitlab ...@@ -115,7 +118,7 @@ module Gitlab
# If source and target are the same, populate them with the new project ID. # If source and target are the same, populate them with the new project ID.
if @relation_hash['source_project_id'] if @relation_hash['source_project_id']
@relation_hash['source_project_id'] = same_source_and_target? ? project_id : -1 @relation_hash['source_project_id'] = same_source_and_target? ? project_id : MergeRequestParser::FORKED_PROJECT_ID
end end
# project_id may not be part of the export, but we always need to populate it if required. # project_id may not be part of the export, but we always need to populate it if required.
...@@ -166,6 +169,7 @@ module Gitlab ...@@ -166,6 +169,7 @@ module Gitlab
def imported_object def imported_object
yield(existing_or_new_object) if block_given? yield(existing_or_new_object) if block_given?
existing_or_new_object.importing = true if existing_or_new_object.respond_to?(:importing) existing_or_new_object.importing = true if existing_or_new_object.respond_to?(:importing)
existing_or_new_object existing_or_new_object
rescue ActiveRecord::RecordNotUnique rescue ActiveRecord::RecordNotUnique
# as the operation is not atomic, retry in the unlikely scenario an INSERT is # as the operation is not atomic, retry in the unlikely scenario an INSERT is
...@@ -188,8 +192,11 @@ module Gitlab ...@@ -188,8 +192,11 @@ module Gitlab
relation_class: relation_class) relation_class: relation_class)
end end
def set_st_diffs def set_st_diff_commits
@relation_hash['st_diffs'] = @relation_hash.delete('utf8_st_diffs') @relation_hash['st_diffs'] = @relation_hash.delete('utf8_st_diffs')
HashUtil.deep_symbolize_array!(@relation_hash['st_diffs'])
HashUtil.deep_symbolize_array_with_date!(@relation_hash['st_commits'])
end end
def existing_or_new_object def existing_or_new_object
......
...@@ -35,7 +35,7 @@ module Gitlab ...@@ -35,7 +35,7 @@ module Gitlab
end end
def strip_key(key) def strip_key(key)
key.split(/ /)[0, 2].join(' ') key.split(/[ ]+/)[0, 2].join(' ')
end end
private private
......
...@@ -35,7 +35,8 @@ module Gitlab ...@@ -35,7 +35,8 @@ module Gitlab
feature_enabled = case action.to_s feature_enabled = case action.to_s
when 'git_receive_pack' when 'git_receive_pack'
Gitlab::GitalyClient.feature_enabled?(:post_receive_pack) # Disabled for now, see https://gitlab.com/gitlab-org/gitaly/issues/172
false
when 'git_upload_pack' when 'git_upload_pack'
Gitlab::GitalyClient.feature_enabled?(:post_upload_pack) Gitlab::GitalyClient.feature_enabled?(:post_upload_pack)
when 'info_refs' when 'info_refs'
...@@ -44,7 +45,12 @@ module Gitlab ...@@ -44,7 +45,12 @@ module Gitlab
raise "Unsupported action: #{action}" raise "Unsupported action: #{action}"
end end
params[:GitalySocketPath] = URI(address).path if feature_enabled if feature_enabled
params[:GitalyAddress] = address
# TODO deprecate GitalySocketPath once GITLAB_WORKHORSE_VERSION points
# to a version that supports GitalyAddress.
params[:GitalySocketPath] = URI(address).path
end
end end
params params
......
...@@ -200,5 +200,72 @@ describe Import::BitbucketController do ...@@ -200,5 +200,72 @@ describe Import::BitbucketController do
end end
end end
end end
context 'user has chosen an existing nested namespace and name for the project' do
let(:parent_namespace) { create(:namespace, name: 'foo', owner: user) }
let(:nested_namespace) { create(:namespace, name: 'bar', parent: parent_namespace, owner: user) }
let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do
expect(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).with(bitbucket_repo, test_name, nested_namespace, user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: nested_namespace.full_path, new_name: test_name, format: :js }
end
end
context 'user has chosen a non-existent nested namespaces and name for the project' do
let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do
expect(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js }
end
it 'creates the namespaces' do
allow(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
expect { post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js } }
.to change { Namespace.count }.by(2)
end
it 'new namespace has the right parent' do
allow(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: 'foo/bar', new_name: test_name, format: :js }
expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
end
end
context 'user has chosen existent and non-existent nested namespaces and name for the project' do
let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:namespace, name: 'foo', owner: user) }
it 'takes the selected namespace and name' do
expect(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js }
end
it 'creates the namespaces' do
allow(Gitlab::BitbucketImport::ProjectCreator).
to receive(:new).with(bitbucket_repo, test_name, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
expect { post :create, { target_namespace: 'foo/foobar/bar', new_name: test_name, format: :js } }
.to change { Namespace.count }.by(2)
end
end
end end
end end
...@@ -174,6 +174,72 @@ describe Import::GitlabController do ...@@ -174,6 +174,72 @@ describe Import::GitlabController do
end end
end end
end end
context 'user has chosen an existing nested namespace for the project' do
let(:parent_namespace) { create(:namespace, name: 'foo', owner: user) }
let(:nested_namespace) { create(:namespace, name: 'bar', parent: parent_namespace, owner: user) }
it 'takes the selected namespace and name' do
expect(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).with(gitlab_repo, nested_namespace, user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: nested_namespace.full_path, format: :js }
end
end
context 'user has chosen a non-existent nested namespaces for the project' do
let(:test_name) { 'test_name' }
it 'takes the selected namespace and name' do
expect(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: 'foo/bar', format: :js }
end
it 'creates the namespaces' do
allow(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
expect { post :create, { target_namespace: 'foo/bar', format: :js } }
.to change { Namespace.count }.by(2)
end
it 'new namespace has the right parent' do
allow(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: 'foo/bar', format: :js }
expect(Namespace.find_by_path_or_name('bar').parent.path).to eq('foo')
end
end
context 'user has chosen existent and non-existent nested namespaces and name for the project' do
let(:test_name) { 'test_name' }
let!(:parent_namespace) { create(:namespace, name: 'foo', owner: user) }
it 'takes the selected namespace and name' do
expect(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
post :create, { target_namespace: 'foo/foobar/bar', format: :js }
end
it 'creates the namespaces' do
allow(Gitlab::GitlabImport::ProjectCreator).
to receive(:new).with(gitlab_repo, kind_of(Namespace), user, access_params).
and_return(double(execute: true))
expect { post :create, { target_namespace: 'foo/foobar/bar', format: :js } }
.to change { Namespace.count }.by(2)
end
end
end end
end end
end end
...@@ -2,7 +2,6 @@ require 'spec_helper' ...@@ -2,7 +2,6 @@ require 'spec_helper'
feature "Admin Health Check", feature: true do feature "Admin Health Check", feature: true do
include StubENV include StubENV
include WaitForAjax
before do before do
stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false') stub_env('IN_MEMORY_APPLICATION_SETTINGS', 'false')
...@@ -24,11 +23,12 @@ feature "Admin Health Check", feature: true do ...@@ -24,11 +23,12 @@ feature "Admin Health Check", feature: true do
expect(page).to have_selector('#health-check-token', text: token) expect(page).to have_selector('#health-check-token', text: token)
end end
describe 'reload access token', js: true do describe 'reload access token' do
it 'changes the access token' do it 'changes the access token' do
orig_token = current_application_settings.health_check_access_token orig_token = current_application_settings.health_check_access_token
click_button 'Reset health check access token' click_button 'Reset health check access token'
wait_for_ajax
expect(page).to have_content('New health check access token has been generated!')
expect(find('#health-check-token').text).not_to eq orig_token expect(find('#health-check-token').text).not_to eq orig_token
end end
end end
......
require 'spec_helper'
describe 'Dashboard Merge Requests' do
let(:current_user) { create :user }
let(:project) do
create(:empty_project) do |project|
project.add_master(current_user)
end
end
before do
login_as(current_user)
end
it 'should show an empty state' do
visit merge_requests_dashboard_path(assignee_id: current_user.id)
expect(page).to have_selector('.empty-state')
end
context 'if there are merge requests' do
before do
create(:merge_request, assignee: current_user, source_project: project)
visit merge_requests_dashboard_path(assignee_id: current_user.id)
end
it 'should not show an empty state' do
expect(page).not_to have_selector('.empty-state')
end
end
end
require 'spec_helper'
feature 'Groups Merge Requests Empty States' do
let(:group) { create(:group) }
let(:user) { create(:group_member, :developer, user: create(:user), group: group ).user }
before do
login_as(user)
end
context 'group has a project' do
let(:project) { create(:empty_project, namespace: group) }
before do
project.add_master(user)
end
context 'the project has a merge request' do
before do
create(:merge_request, source_project: project)
visit merge_requests_group_path(group)
end
it 'should not display an empty state' do
expect(page).not_to have_selector('.empty-state')
end
end
context 'the project has no merge requests', :js do
before do
visit merge_requests_group_path(group)
end
it 'should display an empty state' do
expect(page).to have_selector('.empty-state')
end
it 'should show a new merge request button' do
within '.empty-state' do
expect(page).to have_content('New merge request')
end
end
it 'the new merge request button opens a project dropdown' do
within '.empty-state' do
find('.new-project-item-select-button').click
end
expect(page).to have_selector('.ajax-project-dropdown')
end
end
end
context 'group without a project' do
before do
visit merge_requests_group_path(group)
end
it 'should display an empty state' do
expect(page).to have_selector('.empty-state')
end
it 'should not show a new merge request button' do
within '.empty-state' do
expect(page).not_to have_link('New merge request')
end
end
end
end
require 'spec_helper' require 'spec_helper'
describe 'Filter issues', js: true, feature: true do describe 'Filter issues', js: true, feature: true do
include Devise::Test::IntegrationHelpers
include FilteredSearchHelpers include FilteredSearchHelpers
include WaitForAjax include WaitForAjax
...@@ -42,16 +43,17 @@ describe 'Filter issues', js: true, feature: true do ...@@ -42,16 +43,17 @@ describe 'Filter issues', js: true, feature: true do
project.team << [user2, :master] project.team << [user2, :master]
group.add_developer(user) group.add_developer(user)
group.add_developer(user2) group.add_developer(user2)
login_as(user)
create(:issue, project: project)
create(:issue, title: "Bug report 1", project: project) sign_in(user)
create(:issue, title: "Bug report 2", project: project)
create(:issue, title: "issue with 'single quotes'", project: project) create(:issue, project: project)
create(:issue, title: "issue with \"double quotes\"", project: project) create(:issue, project: project, title: "Bug report 1")
create(:issue, title: "issue with !@\#{$%^&*()-+", project: project) create(:issue, project: project, title: "Bug report 2")
create(:issue, title: "issue by assignee", project: project, milestone: milestone, author: user, assignee: user) create(:issue, project: project, title: "issue with 'single quotes'")
create(:issue, title: "issue by assignee with searchTerm", project: project, milestone: milestone, author: user, assignee: user) create(:issue, project: project, title: "issue with \"double quotes\"")
create(:issue, project: project, title: "issue with !@\#{$%^&*()-+")
create(:issue, project: project, title: "issue by assignee", milestone: milestone, author: user, assignee: user)
create(:issue, project: project, title: "issue by assignee with searchTerm", milestone: milestone, author: user, assignee: user)
issue = create(:issue, issue = create(:issue,
title: "Bug 2", title: "Bug 2",
......
...@@ -15,7 +15,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -15,7 +15,7 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'selects the source branch sha when a tag with the same name exists' do it 'selects the source branch sha when a tag with the same name exists' do
visit namespace_project_merge_requests_path(project.namespace, project) visit namespace_project_merge_requests_path(project.namespace, project)
click_link 'New Merge Request' click_link 'New merge request'
expect(page).to have_content('Source branch') expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch') expect(page).to have_content('Target branch')
...@@ -27,8 +27,8 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -27,8 +27,8 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'selects the target branch sha when a tag with the same name exists' do it 'selects the target branch sha when a tag with the same name exists' do
visit namespace_project_merge_requests_path(project.namespace, project) visit namespace_project_merge_requests_path(project.namespace, project)
click_link 'New Merge Request' click_link 'New merge request'
expect(page).to have_content('Source branch') expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch') expect(page).to have_content('Target branch')
...@@ -42,7 +42,7 @@ feature 'Create New Merge Request', feature: true, js: true do ...@@ -42,7 +42,7 @@ feature 'Create New Merge Request', feature: true, js: true do
it 'generates a diff for an orphaned branch' do it 'generates a diff for an orphaned branch' do
visit namespace_project_merge_requests_path(project.namespace, project) visit namespace_project_merge_requests_path(project.namespace, project)
click_link 'New Merge Request' page.has_link?('New Merge Request') ? click_link("New Merge Request") : click_link('New merge request')
expect(page).to have_content('Source branch') expect(page).to have_content('Source branch')
expect(page).to have_content('Target branch') expect(page).to have_content('Target branch')
......
...@@ -69,12 +69,8 @@ feature 'Import/Export - project import integration test', feature: true, js: tr ...@@ -69,12 +69,8 @@ feature 'Import/Export - project import integration test', feature: true, js: tr
select2(namespace.id, from: '#project_namespace_id') select2(namespace.id, from: '#project_namespace_id')
# click on disabled element # Check for tooltip disabled import button
find(:link, 'GitLab export').trigger('click') expect(find('.import_gitlab_project')['title']).to eq('Please enter a valid project name.')
page.within('.flash-container') do
expect(page).to have_content('Please enter path and name')
end
end end
end end
......
...@@ -17,4 +17,28 @@ feature 'Merge Requests List' do ...@@ -17,4 +17,28 @@ feature 'Merge Requests List' do
expect(page).not_to have_selector('.js-new-board-list') expect(page).not_to have_selector('.js-new-board-list')
end end
it 'should show an empty state' do
visit namespace_project_merge_requests_path(project.namespace, project)
expect(page).to have_selector('.empty-state')
end
it 'empty state should have a create merge request button' do
visit namespace_project_merge_requests_path(project.namespace, project)
expect(page).to have_link 'New merge request', href: new_namespace_project_merge_request_path(project.namespace, project)
end
context 'if there are merge requests' do
before do
create(:merge_request, assignee: user, source_project: project)
visit namespace_project_merge_requests_path(project.namespace, project)
end
it 'should not show an empty state' do
expect(page).not_to have_selector('.empty-state')
end
end
end end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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