Commit 3cc76aa8 authored by Nick Thomas's avatar Nick Thomas

Merge remote-tracking branch 'ce/master' into ce-to-ee

parents ae674f38 88d38963
......@@ -427,6 +427,7 @@ entry.
- Speed up group milestone index by passing group_id to IssuesFinder. !8363
- Ensure issuable state changes only fire webhooks once.
<<<<<<< HEAD
## 8.14.7 (2017-01-21)
- Ensure export files are removed after a namespace is deleted.
......@@ -435,6 +436,8 @@ entry.
- Prevent users from deleting system deploy keys via the project deploy key API.
- Upgrade omniauth gem to 1.3.2.
=======
>>>>>>> ce/master
## 8.14.6 (2017-01-10)
- Update the gitlab-markup gem to the version 1.5.1. !8509
......
......@@ -80,11 +80,9 @@ the remaining issues on the GitHub issue tracker.
## I want to contribute!
If you want to contribute to GitLab, but are not sure where to start,
look for [issues with the label `up-for-grabs`][up-for-grabs]. These issues
will be of reasonable size and challenge, for anyone to start contributing to
GitLab.
This was inspired by [an article by Kent C. Dodds][medium-up-for-grabs].
look for [issues with the label `Accepting Merge Requests` and weight < 5][accepting-mrs-weight].
These issues will be of reasonable size and challenge, for anyone to start
contributing to GitLab.
## Implement design & UI elements
......@@ -214,16 +212,19 @@ associated with in the description of the issue.
## Merge requests
We welcome merge requests with fixes and improvements to GitLab code, tests,
and/or documentation. The features we would really like a merge request for are
listed with the label [`Accepting Merge Requests` on our issue tracker for CE][accepting-mrs-ce]
and [EE][accepting-mrs-ee] but other improvements are also welcome. Please note
that if an issue is marked for the current milestone either before or while you
are working on it, a team member may take over the merge request in order to
ensure the work is finished before the release date.
and/or documentation. The issues that are specifically suitable for
community contributions are listed with the label
[`Accepting Merge Requests` on our issue tracker for CE][accepting-mrs-ce]
and [EE][accepting-mrs-ee], but you are free to contribute to any other issue
you want.
Please note that if an issue is marked for the current milestone either before
or while you are working on it, a team member may take over the merge request
in order to ensure the work is finished before the release date.
If you want to add a new feature that is not labeled it is best to first create
a feedback issue (if there isn't one already) and leave a comment asking for it
to be marked as `Accepting merge requests`. Please include screenshots or
to be marked as `Accepting Merge Requests`. Please include screenshots or
wireframes if the feature will also change the UI.
Merge requests should be opened at [GitLab.com][gitlab-mr-tracker].
......@@ -450,8 +451,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[core team]: https://about.gitlab.com/core-team/
[getting-help]: https://about.gitlab.com/getting-help/
[codetriage]: http://www.codetriage.com/gitlabhq/gitlabhq
[up-for-grabs]: https://gitlab.com/gitlab-org/gitlab-ce/issues?label_name=up-for-grabs
[medium-up-for-grabs]: https://medium.com/@kentcdodds/first-timers-only-78281ea47455
[accepting-mrs-weight]: https://gitlab.com/gitlab-org/gitlab-ce/issues?assignee_id=0&label_name[]=Accepting%20Merge%20Requests&sort=weight_asc
[ce-tracker]: https://gitlab.com/gitlab-org/gitlab-ce/issues
[ee-tracker]: https://gitlab.com/gitlab-org/gitlab-ee/issues
[google-group]: https://groups.google.com/forum/#!forum/gitlabhq
......
This diff is collapsed.
......@@ -367,9 +367,14 @@
return $input.trigger('keyup');
},
isLoading(data) {
if (!data || !data.length) return false;
if (Array.isArray(data)) data = data[0];
return data === this.defaultLoadingData[0] || data.name === this.defaultLoadingData[0];
var dataToInspect = data;
if (data && data.length > 0) {
dataToInspect = data[0];
}
var loadingState = this.defaultLoadingData[0];
return dataToInspect &&
(dataToInspect === loadingState || dataToInspect.name === loadingState);
}
};
}).call(this);
......@@ -651,18 +651,14 @@
isMarking = false;
el.removeClass(ACTIVE_CLASS);
if (field && field.length) {
if (isInput) {
field.val('');
} else {
field.remove();
}
this.clearField(field, isInput);
}
} else if (el.hasClass(INDETERMINATE_CLASS)) {
isMarking = true;
el.addClass(ACTIVE_CLASS);
el.removeClass(INDETERMINATE_CLASS);
if (field && field.length && value == null) {
field.remove();
this.clearField(field, isInput);
}
if ((!field || !field.length) && fieldName) {
this.addInput(fieldName, value, selectedObject);
......@@ -676,7 +672,7 @@
}
}
if (field && field.length && value == null) {
field.remove();
this.clearField(field, isInput);
}
// Toggle active class for the tick mark
el.addClass(ACTIVE_CLASS);
......@@ -826,6 +822,10 @@
return $(this.el).find(".dropdown-toggle-text").text(this.options.toggleLabel(selected, el, instance));
};
GitLabDropdown.prototype.clearField = function(field, isInput) {
return isInput ? field.val('') : field.remove();
};
return GitLabDropdown;
})();
......
......@@ -336,7 +336,11 @@
.removeClass('is-active');
}
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
if ($dropdown.hasClass('js-issuable-form-dropdown')) {
return;
}
if ($dropdown.hasClass('js-filter-bulk-update')) {
_this.enableBulkLabelDropdown();
_this.setDropdownData($dropdown, isMarking, this.id(label));
return;
......
......@@ -160,6 +160,62 @@
return decodeURIComponent(results[2].replace(/\+/g, ' '));
};
w.gl.utils.getSelectedFragment = () => {
const selection = window.getSelection();
const documentFragment = selection.getRangeAt(0).cloneContents();
if (documentFragment.textContent.length === 0) return null;
return documentFragment;
};
w.gl.utils.insertText = (target, text) => {
// Firefox doesn't support `document.execCommand('insertText', false, text)` on textareas
const selectionStart = target.selectionStart;
const selectionEnd = target.selectionEnd;
const value = target.value;
const textBefore = value.substring(0, selectionStart);
const textAfter = value.substring(selectionEnd, value.length);
const newText = textBefore + text + textAfter;
target.value = newText;
target.selectionStart = target.selectionEnd = selectionStart + text.length;
// Trigger autosave
$(target).trigger('input');
// Trigger autosize
var event = document.createEvent('Event');
event.initEvent('autosize:update', true, false);
target.dispatchEvent(event);
};
w.gl.utils.nodeMatchesSelector = (node, selector) => {
const matches = Element.prototype.matches ||
Element.prototype.matchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.oMatchesSelector ||
Element.prototype.webkitMatchesSelector;
if (matches) {
return matches.call(node, selector);
}
// IE11 doesn't support `node.matches(selector)`
let parentNode = node.parentNode;
if (!parentNode) {
parentNode = document.createElement('div');
node = node.cloneNode(true);
parentNode.appendChild(node);
}
const matchingNodes = parentNode.querySelectorAll(selector);
return Array.prototype.indexOf.call(matchingNodes, node) !== -1;
};
/**
this will take in the headers from an API response and normalize them
this way we don't run into production issues when nginx gives us lowercased header keys
......
......@@ -69,12 +69,17 @@
search: {
fields: ['text']
},
id: this.getSearchText,
data: this.getData.bind(this),
selectable: true,
clicked: this.onClick.bind(this)
});
}
getSearchText(selectedObject, el) {
return selectedObject.id ? selectedObject.text : '';
}
getData(term, callback) {
var _this, contents, jqXHR;
_this = this;
......@@ -364,7 +369,7 @@
onClick(item, $el, e) {
if (location.pathname.indexOf(item.url) !== -1) {
e.preventDefault();
if (!e.metaKey) e.preventDefault();
if (!this.badgePresent) {
if (item.category === 'Projects') {
this.projectInputEl.val(item.id);
......
......@@ -39,29 +39,39 @@
}
ShortcutsIssuable.prototype.replyWithSelectedText = function() {
var quote, replyField, selected, separator;
if (window.getSelection) {
selected = window.getSelection().toString();
replyField = $('.js-main-target-form #note_note');
if (selected.trim() === "") {
return;
}
// Put a '>' character before each non-empty line in the selection
quote = _.map(selected.split("\n"), function(val) {
if (val.trim() !== '') {
return "> " + val + "\n";
}
});
// If replyField already has some content, add a newline before our quote
separator = replyField.val().trim() !== "" && "\n" || '';
replyField.val(function(_, current) {
return current + separator + quote.join('') + "\n";
});
// Trigger autosave for the added text
replyField.trigger('input');
// Focus the input field
return replyField.focus();
var quote, replyField, documentFragment, selected, separator;
documentFragment = window.gl.utils.getSelectedFragment();
if (!documentFragment) return;
// If the documentFragment contains more than just Markdown, don't copy as GFM.
if (documentFragment.querySelector('.md, .wiki')) return;
selected = window.gl.CopyAsGFM.nodeToGFM(documentFragment);
replyField = $('.js-main-target-form #note_note');
if (selected.trim() === "") {
return;
}
quote = _.map(selected.split("\n"), function(val) {
return ("> " + val).trim() + "\n";
});
// If replyField already has some content, add a newline before our quote
separator = replyField.val().trim() !== "" && "\n\n" || '';
replyField.val(function(_, current) {
return current + separator + quote.join('') + "\n";
});
// Trigger autosave
replyField.trigger('input');
// Trigger autosize
var event = document.createEvent('Event');
event.initEvent('autosize:update', true, false);
replyField.get(0).dispatchEvent(event);
// Focus the input field
return replyField.focus();
};
ShortcutsIssuable.prototype.editIssue = function() {
......
......@@ -13,6 +13,8 @@ $dark-main-bg: #1d1f21;
$dark-main-color: #1d1f21;
$dark-line-color: #c5c8c6;
$dark-line-num-color: rgba(255, 255, 255, 0.3);
$dark-line-num-color-new: #627165;
$dark-line-num-color-old: #806565;
$dark-diff-not-empty-bg: #557;
$dark-highlight-bg: #ffe792;
$dark-highlight-color: $black;
......@@ -89,7 +91,6 @@ $dark-il: #de935f;
.diff-line-num,
.diff-line-num a {
color: $dark-main-color;
color: $dark-line-num-color;
}
......@@ -121,11 +122,21 @@ $dark-il: #de935f;
.diff-line-num.new,
.line_content.new {
@include diff_background($dark-new-bg, $dark-new-idiff, $dark-border);
&::before,
a {
color: $dark-line-num-color-new;
}
}
.diff-line-num.old,
.line_content.old {
@include diff_background($dark-old-bg, $dark-old-idiff, $dark-border);
&::before,
a {
color: $dark-line-num-color-old;
}
}
.line_content.match {
......
......@@ -7,6 +7,8 @@ $monokai-bg: #272822;
$monokai-border: #555;
$monokai-text-color: #f8f8f2;
$monokai-line-num-color: rgba(255, 255, 255, 0.3);
$monokai-line-num-color-new: #707565;
$monokai-line-num-color-old: #7e736f;
$monokai-line-empty-bg: #49483e;
$monokai-line-empty-border: darken($monokai-line-empty-bg, 15%);
$monokai-diff-border: #808080;
......@@ -120,11 +122,21 @@ $monokai-gi: #a6e22e;
.diff-line-num.new,
.line_content.new {
@include diff_background($monokai-new-bg, $monokai-new-idiff, $monokai-diff-border);
&::before,
a {
color: $monokai-line-num-color-new;
}
}
.diff-line-num.old,
.line_content.old {
@include diff_background($monokai-old-bg, $monokai-old-idiff, $monokai-diff-border);
&::before,
a {
color: $monokai-line-num-color-old;
}
}
.line_content.match {
......
......@@ -13,6 +13,8 @@ $solarized-dark-pre-color: #93a1a1;
$solarized-dark-pre-border: #113b46;
$solarized-dark-line-bg: #002b36;
$solarized-dark-line-color: rgba(255, 255, 255, 0.3);
$solarized-dark-line-color-new: #5a766c;
$solarized-dark-line-color-old: #7a6c71;
$solarized-dark-highlight: #094554;
$solarized-dark-hll-bg: #174652;
$solarized-dark-c: #586e75;
......@@ -124,11 +126,21 @@ $solarized-dark-il: #2aa198;
.diff-line-num.new,
.line_content.new {
@include diff_background($solarized-dark-new-bg, $solarized-dark-new-idiff, $solarized-dark-border);
&::before,
a {
color: $solarized-dark-line-color-new;
}
}
.diff-line-num.old,
.line_content.old {
@include diff_background($solarized-dark-old-bg, $solarized-dark-old-idiff, $solarized-dark-border);
&::before,
a {
color: $solarized-dark-line-color-old;
}
}
.line_content.match {
......
......@@ -13,6 +13,9 @@ $solarized-light-pre-bg: #002b36;
$solarized-light-pre-bg: #fdf6e3;
$solarized-light-pre-color: #586e75;
$solarized-light-line-bg: #fdf6e3;
$solarized-light-line-color: rgba(0, 0, 0, 0.3);
$solarized-light-line-color-new: #a1a080;
$solarized-light-line-color-old: #ad9186;
$solarized-light-highlight: #eee8d5;
$solarized-light-hll-bg: #ddd8c5;
$solarized-light-c: #93a1a1;
......@@ -98,7 +101,7 @@ $solarized-light-il: #2aa198;
.diff-line-num,
.diff-line-num a {
color: $black-transparent;
color: $solarized-light-line-color;
}
// Code itself
......@@ -130,11 +133,21 @@ $solarized-light-il: #2aa198;
.line_content.new {
@include diff_background($solarized-light-new-bg,
$solarized-light-new-idiff, $solarized-light-border);
&::before,
a {
color: $solarized-light-line-color-new;
}
}
.diff-line-num.old,
.line_content.old {
@include diff_background($solarized-light-old-bg, $solarized-light-old-idiff, $solarized-light-border);
&::before,
a {
color: $solarized-light-line-color-old;
}
}
.line_content.match {
......
......@@ -108,11 +108,19 @@ $white-gc-bg: #eaf2f5;
&.old {
background-color: $line-number-old;
border-color: $line-removed-dark;
a {
color: scale-color($line-number-old,$red: -30%, $green: -30%, $blue: -30%);
}
}
&.new {
background-color: $line-number-new;
border-color: $line-added-dark;
a {
color: scale-color($line-number-new,$red: -30%, $green: -30%, $blue: -30%);
}
}
&.hll:not(.empty-cell) {
......@@ -125,6 +133,10 @@ $white-gc-bg: #eaf2f5;
&.old {
background-color: $line-removed;
&::before {
color: scale-color($line-number-old,$red: -30%, $green: -30%, $blue: -30%);
}
span.idiff {
background-color: $line-removed-dark;
}
......@@ -133,6 +145,10 @@ $white-gc-bg: #eaf2f5;
&.new {
background-color: $line-added;
&::before {
color: scale-color($line-number-new,$red: -30%, $green: -30%, $blue: -30%);
}
span.idiff {
background-color: $line-added-dark;
}
......
......@@ -203,6 +203,10 @@
position: relative;
margin-right: 6px;
.tooltip {
white-space: nowrap;
}
.tooltip-inner {
padding: 3px 4px;
}
......
......@@ -32,6 +32,10 @@
.last-commit {
@include str-truncated(506px);
.fa-angle-right {
margin-left: 5px;
}
@media (min-width: $screen-md-min) and (max-width: $screen-md-max) {
@include str-truncated(450px);
}
......
......@@ -109,12 +109,14 @@ class Projects::GitHttpClientController < Projects::ApplicationController
end
def repository
wiki? ? project.wiki.repository : project.repository
end
def wiki?
return @wiki if defined?(@wiki)
_, suffix = project_id_with_suffix
if suffix == '.wiki.git'
project.wiki.repository
else
project.repository
end
@wiki = suffix == '.wiki.git'
end
def render_not_found
......
......@@ -86,7 +86,7 @@ class Projects::GitHttpController < Projects::GitHttpClientController
end
def access
@access ||= Gitlab::GitAccess.new(user, project, 'http', authentication_abilities: authentication_abilities)
@access ||= access_klass.new(user, project, 'http', authentication_abilities: authentication_abilities)
end
def access_check
......@@ -105,7 +105,12 @@ class Projects::GitHttpController < Projects::GitHttpClientController
access_check.allowed?
end
<<<<<<< HEAD
def log_user_activity
Users::ActivityService.new(user, 'pull').execute
=======
def access_klass
@access_klass ||= wiki? ? Gitlab::GitAccessWiki : Gitlab::GitAccess
>>>>>>> ce/master
end
end
......@@ -11,10 +11,10 @@ module Taskable
INCOMPLETE = 'incomplete'.freeze
ITEM_PATTERN = /
^
\s*(?:[-+*]|(?:\d+\.))? # optional list prefix
\s* # optional whitespace prefix
(\[\s\]|\[[xX]\]) # checkbox
(\s.+) # followed by whitespace and some text.
\s*(?:[-+*]|(?:\d+\.)) # list prefix required - task item has to be always in a list
\s+ # whitespace prefix has to be always presented for a list item
(\[\s\]|\[[xX]\]) # checkbox
(\s.+) # followed by whitespace and some text.
/x
def self.get_tasks(content)
......
......@@ -16,7 +16,10 @@ class ProjectGroupLink < ActiveRecord::Base
validates :group_access, inclusion: { in: Gitlab::Access.values }, presence: true
validate :different_group
<<<<<<< HEAD
before_destroy :delete_branch_protection
=======
>>>>>>> ce/master
after_commit :refresh_group_members_authorized_projects
def self.access_options
......
module ApplicationSettings
class UpdateService < ApplicationSettings::BaseService
def execute
<<<<<<< HEAD
# Repository size limit comes as MB from the view
limit = @params.delete(:repository_size_limit)
@application_setting.repository_size_limit = (limit.to_i.megabytes if limit.present?)
=======
>>>>>>> ce/master
@application_setting.update(@params)
end
end
......
......@@ -3,10 +3,18 @@ module Ci
# proper pending build to runner on runner API request
class RegisterBuildService
include Gitlab::CurrentSettings
<<<<<<< HEAD
prepend EE::Ci::RegisterBuildService
attr_reader :runner
=======
attr_reader :runner
Result = Struct.new(:build, :valid?)
>>>>>>> ce/master
def initialize(runner)
@runner = runner
end
......@@ -30,10 +38,10 @@ module Ci
build.run!
end
build
Result.new(build, true)
rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError
nil
Result.new(build, false)
end
private
......
......@@ -22,9 +22,12 @@ module Projects
return @project
end
<<<<<<< HEAD
# Repository size limit comes as MB from the view
set_repository_size_limit_as_bytes
=======
>>>>>>> ce/master
set_project_name_from_path
# get namespace id
......@@ -145,11 +148,14 @@ module Projects
end
end
<<<<<<< HEAD
def set_repository_size_limit_as_bytes
limit = params.delete(:repository_size_limit)
@project.repository_size_limit = (limit.to_i.megabytes if limit.present?)
end
=======
>>>>>>> ce/master
def set_project_name_from_path
# Set project name from path
if @project.name.present? && @project.path.present?
......
......@@ -23,7 +23,7 @@
= markdown_toolbar_button({ icon: "list-ol fw", data: { "md-tag" => "1. ", "md-prepend" => true }, title: "Add a numbered list" })
= markdown_toolbar_button({ icon: "check-square-o fw", data: { "md-tag" => "* [ ] ", "md-prepend" => true }, title: "Add a task list" })
.toolbar-group
%button.toolbar-btn.js-zen-enter.has-tooltip.hidden-xs{ type: "button", tabindex: -1, aria: { label: "Go full screen" }, title: "Go full screen", data: { container: "body" } }
%button.toolbar-btn.js-zen-enter.has-tooltip{ type: "button", tabindex: -1, aria: { label: "Go full screen" }, title: "Go full screen", data: { container: "body" } }
= icon("arrows-alt fw")
.md-write-holder
......
......@@ -8,7 +8,7 @@
%br
%span.descr
Builds need to be configured to enable this feature.
= link_to icon('question-circle'), help_page_path('user/project/merge_requests/merge_when_build_succeeds', anchor: 'only-allow-merge-requests-to-be-merged-if-the-build-succeeds')
= link_to icon('question-circle'), help_page_path('user/project/merge_requests/merge_when_pipeline_succeeds', anchor: 'only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds')
.checkbox
= form.label :only_allow_merge_if_all_discussions_are_resolved do
= form.check_box :only_allow_merge_if_all_discussions_are_resolved
......
......@@ -18,12 +18,15 @@
- if @project.protected_branch? branch.name
%span.label.label-success
protected
<<<<<<< HEAD
- if @project.mirror_ever_updated_successfully? && @repository.diverged_from_upstream?(branch.name)
%span.label.label-danger.has-tooltip{ data: { html: "true", title: branch_diverged_tooltip_message } }
= icon('exclamation-triangle')
diverged from upstream
=======
>>>>>>> ce/master
.controls.hidden-xs<
- if merge_project && create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-default' do
......
.page-content-header
.header-main-content
%strong
%strong Commit #{@commit.short_id}
= clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard")
= @commit.short_id
%span.hidden-xs authored
#{time_ago_with_tooltip(@commit.authored_date)}
%span by
......
......@@ -14,7 +14,7 @@
- left_line_code = diff_file.line_code(left)
- left_position = diff_file.position(left)
%td.old_line.diff-line-num{ id: left_line_code, class: left.type, data: { linenumber: left.old_pos } }
%a{ href: "##{left_line_code}" }= raw(left.old_pos)
%a{ href: "##{left_line_code}", data: { linenumber: left.old_pos } }
%td.line_content.parallel.noteable_line{ class: left.type, data: diff_view_line_data(left_line_code, left_position, 'old') }= diff_line_content(left.text)
- else
%td.old_line.diff-line-num.empty-cell
......@@ -27,7 +27,7 @@
- right_line_code = diff_file.line_code(right)
- right_position = diff_file.position(right)
%td.new_line.diff-line-num{ id: right_line_code, class: right.type, data: { linenumber: right.new_pos } }
%a{ href: "##{right_line_code}" }= raw(right.new_pos)
%a{ href: "##{right_line_code}", data: { linenumber: right.new_pos } }
%td.line_content.parallel.noteable_line{ class: right.type, data: diff_view_line_data(right_line_code, right_position, 'new') }= diff_line_content(right.text)
- else
%td.old_line.diff-line-num.empty-cell
......
......@@ -7,10 +7,17 @@
.project-edit-errors
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
%fieldset.append-bottom-0
.form-group
= f.label :name, class: 'label-light' do
Project name
= f.text_field :name, class: "form-control", id: "project_name_edit"
.row
.form-group.col-md-9
= f.label :name, class: 'label-light' do
Project name
= f.text_field :name, class: "form-control", id: "project_name_edit"
.form-group.col-md-3
= f.label :id, class: 'label-light' do
Project ID
= f.text_field :id, class: 'form-control', readonly: true
.form-group
= f.label :description, class: 'label-light' do
Project description
......
......@@ -7,10 +7,12 @@
%th.hidden-xs
.pull-left Last commit
.last-commit.hidden-sm.pull-left
%i.fa.fa-angle-right
%small.light
= clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard")
= link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
= clipboard_button(clipboard_text: @commit.id, title: "Copy commit SHA to clipboard")
= time_ago_with_tooltip(@commit.committed_date)
\-
= @commit.full_title
%small.commit-history-link-spacer &#124;
= lock_file_link(html_options: {class: 'pull-right prepend-left-10 path-lock'})
......
---
title: Prevent removal of input fields if it is the parent dropdown element
merge_request: 8397
author:
---
title: Don’t count tasks that are not defined as list items correctly
merge_request: 8526
author:
---
title: Color + and - signs in diffs to increase code legibility
merge_request:
author:
---
title: Fix autocomplete initial undefined state
merge_request:
author:
---
title: Fix commit title bar and repository view copy clipboard button order on last commit in repository view
merge_request:
author:
---
title: Fix mini-pipeline stage tooltip text wrapping
merge_request:
author:
---
title: Prevent copying of line numbers in parallel diff view
merge_request: 8706
author:
---
title: Updated builds info link on the project settings page
merge_request:
author: Ryan Harris
---
title: Copying a rendered issue/comment will paste into GFM textareas as actual GFM
merge_request:
author:
---
title: Display project ID in project settings
merge_request: 8572
author: winniehell
---
title: Fix access to the wiki code via HTTP when repository feature disabled
merge_request: 8758
author:
---
title: Fixed label dropdown toggle text not correctly updating
merge_request:
author:
---
title: Display fullscreen button on small screens
merge_request: 5302
author: winniehell
......@@ -30,14 +30,13 @@ class Spinach::Features::RevertMergeRequests < Spinach::FeatureSteps
end
step 'I am signed in as a developer of the project' do
@user = create(:user) { |u| @project.add_developer(u) }
login_as(@user)
end
step 'There is an open Merge Request' do
@user = create(:user)
@project = create(:project, :public, :repository)
@project_member = create(:project_member, :developer, user: @user, project: @project)
@merge_request = create(:merge_request, :with_diffs, :simple, source_project: @project)
@merge_request = create(:merge_request, :with_diffs, :simple)
@project = @merge_request.source_project
end
step 'I should see a revert error' do
......
......@@ -14,7 +14,11 @@ if ENV['CI']
Knapsack::Adapters::SpinachAdapter.bind
end
<<<<<<< HEAD
%w(select2_helper test_env repo_helpers license wait_for_ajax sidekiq).each do |f|
=======
%w(select2_helper test_env repo_helpers wait_for_ajax sidekiq).each do |f|
>>>>>>> ce/master
require Rails.root.join('spec', 'support', f)
end
......
......@@ -153,7 +153,7 @@ module Banzai
title = object_link_title(object)
klass = reference_class(object_sym)
data = data_attributes_for(link_content || match, project, object)
data = data_attributes_for(link_content || match, project, object, link: !!link_content)
if matches.names.include?("url") && matches[:url]
url = matches[:url]
......@@ -172,9 +172,10 @@ module Banzai
end
end
def data_attributes_for(text, project, object)
def data_attributes_for(text, project, object, link: false)
data_attribute(
original: text,
link: link,
project: project.id,
object_sym => object.id
)
......
......@@ -62,7 +62,7 @@ module Banzai
end
end
def data_attributes_for(text, project, object)
def data_attributes_for(text, project, object, link: false)
if object.is_a?(ExternalIssue)
data_attribute(
project: project.id,
......
......@@ -20,17 +20,19 @@ module Banzai
code = node.text
css_classes = "code highlight"
lexer = lexer_for(language)
lang = lexer.tag
begin
code = format(lex(lexer, code))
css_classes << " js-syntax-highlight #{lexer.tag}"
css_classes << " js-syntax-highlight #{lang}"
rescue
lang = nil
# Gracefully handle syntax highlighter bugs/errors to ensure
# users can still access an issue/comment/etc.
end
highlighted = %(<pre class="#{css_classes}" v-pre="true"><code>#{code}</code></pre>)
highlighted = %(<pre class="#{css_classes}" lang="#{lang}" v-pre="true"><code>#{code}</code></pre>)
# Extracted to a method to measure it
replace_parent_pre_element(node, highlighted)
......
......@@ -35,7 +35,8 @@ module Banzai
src: element['src'],
width: '400',
controls: true,
'data-setup' => '{}')
'data-setup' => '{}',
'data-title' => element['title'] || element['alt'])
link = doc.document.create_element(
'a',
......
module Banzai
module Pipeline
class GfmPipeline < BasePipeline
# These filters convert GitLab Flavored Markdown (GFM) to HTML.
# The handlers defined in app/assets/javascripts/copy_as_gfm.js.es6
# consequently convert that same HTML to GFM to be copied to the clipboard.
# Every filter that generates HTML from GFM should have a handler in
# app/assets/javascripts/copy_as_gfm.js.es6, in reverse order.
# The GFM-to-HTML-to-GFM cycle is tested in spec/features/copy_as_gfm_spec.rb.
def self.filters
@filters ||= FilterArray[
Filter::SyntaxHighlightFilter,
......
......@@ -18,24 +18,35 @@ module Ci
if current_runner.is_runner_queue_value_latest?(params[:last_update])
header 'X-GitLab-Last-Update', params[:last_update]
Gitlab::Metrics.add_event(:build_not_found_cached)
return build_not_found!
end
new_update = current_runner.ensure_runner_queue_value
<<<<<<< HEAD
build = Ci::RegisterBuildService.new(current_runner).execute
=======
result = Ci::RegisterBuildService.new(current_runner).execute
>>>>>>> ce/master
if build
Gitlab::Metrics.add_event(:build_found,
project: build.project.path_with_namespace)
if result.valid?
if result.build
Gitlab::Metrics.add_event(:build_found,
project: result.build.project.path_with_namespace)
present build, with: Entities::BuildDetails
else
Gitlab::Metrics.add_event(:build_not_found)
present result.build, with: Entities::BuildDetails
else
Gitlab::Metrics.add_event(:build_not_found)
header 'X-GitLab-Last-Update', new_update
header 'X-GitLab-Last-Update', new_update
build_not_found!
build_not_found!
end
else
# We received build that is invalid due to concurrency conflict
Gitlab::Metrics.add_event(:build_invalid)
conflict!
end
end
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Admin::GroupsController do
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
let(:project) { create(:empty_project, namespace: group) }
let(:admin) { create(:admin) }
before do
......
require 'spec_helper'
describe Admin::ProjectsController do
let!(:project) { create(:project, visibility_level: Gitlab::VisibilityLevel::PUBLIC) }
let!(:project) { create(:empty_project, :public) }
before do
sign_in(create(:admin))
......
require 'spec_helper'
describe AutocompleteController do
let!(:project) { create(:project) }
let!(:project) { create(:empty_project) }
let!(:user) { create(:user) }
context 'GET users' do
......
require 'spec_helper'
describe Projects::BlobController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Ci::ProjectsController do
let(:visibility) { :public }
let!(:project) { create(:project, visibility, ci_id: 1) }
let!(:project) { create(:empty_project, visibility, ci_id: 1) }
let(:ci_id) { project.ci_id }
describe '#index' do
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Dashboard::TodosController do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:todo_service) { TodoService.new }
describe 'GET #index' do
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Groups::MilestonesController do
let(:group) { create(:group) }
let(:project) { create(:project, group: group) }
let(:project) { create(:empty_project, group: group) }
let(:project2) { create(:empty_project, group: group) }
let(:user) { create(:user) }
let(:title) { '肯定不是中文的问题' }
......
......@@ -3,7 +3,7 @@ require 'rails_helper'
describe GroupsController do
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:project) { create(:project, namespace: group) }
let(:project) { create(:empty_project, namespace: group) }
let!(:group_member) { create(:group_member, group: group, user: user) }
describe 'GET #index' do
......
......@@ -52,7 +52,7 @@ describe Import::BitbucketController do
end
it "assigns variables" do
@project = create(:project, import_type: 'bitbucket', creator_id: user.id)
@project = create(:empty_project, import_type: 'bitbucket', creator_id: user.id)
allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo])
get :status
......@@ -63,7 +63,7 @@ describe Import::BitbucketController do
end
it "does not show already added project" do
@project = create(:project, import_type: 'bitbucket', creator_id: user.id, import_source: 'asd/vim')
@project = create(:empty_project, import_type: 'bitbucket', creator_id: user.id, import_source: 'asd/vim')
allow_any_instance_of(Bitbucket::Client).to receive(:repos).and_return([@repo])
get :status
......
......@@ -16,7 +16,7 @@ describe Import::FogbugzController do
end
it 'assigns variables' do
@project = create(:project, import_type: 'fogbugz', creator_id: user.id)
@project = create(:empty_project, import_type: 'fogbugz', creator_id: user.id)
stub_client(repos: [@repo])
get :status
......@@ -26,7 +26,7 @@ describe Import::FogbugzController do
end
it 'does not show already added project' do
@project = create(:project, import_type: 'fogbugz', creator_id: user.id, import_source: 'vim')
@project = create(:empty_project, import_type: 'fogbugz', creator_id: user.id, import_source: 'vim')
stub_client(repos: [@repo])
get :status
......
......@@ -36,7 +36,7 @@ describe Import::GitlabController do
end
it "assigns variables" do
@project = create(:project, import_type: 'gitlab', creator_id: user.id)
@project = create(:empty_project, import_type: 'gitlab', creator_id: user.id)
stub_client(projects: [@repo])
get :status
......@@ -46,7 +46,7 @@ describe Import::GitlabController do
end
it "does not show already added project" do
@project = create(:project, import_type: 'gitlab', creator_id: user.id, import_source: 'asd/vim')
@project = create(:empty_project, import_type: 'gitlab', creator_id: user.id, import_source: 'asd/vim')
stub_client(projects: [@repo])
get :status
......
......@@ -27,7 +27,7 @@ describe Import::GoogleCodeController do
end
it "assigns variables" do
@project = create(:project, import_type: 'google_code', creator_id: user.id)
@project = create(:empty_project, import_type: 'google_code', creator_id: user.id)
stub_client(repos: [@repo], incompatible_repos: [])
get :status
......@@ -38,7 +38,7 @@ describe Import::GoogleCodeController do
end
it "does not show already added project" do
@project = create(:project, import_type: 'google_code', creator_id: user.id, import_source: 'vim')
@project = create(:empty_project, import_type: 'google_code', creator_id: user.id, import_source: 'vim')
stub_client(repos: [@repo], incompatible_repos: [])
get :status
......
......@@ -93,7 +93,7 @@ describe NotificationSettingsController do
end
context 'not authorized' do
let(:private_project) { create(:project, :private) }
let(:private_project) { create(:empty_project, :private) }
before { sign_in(user) }
it 'returns 404' do
......
require 'spec_helper'
describe Projects::AvatarsController do
let(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
let(:project) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
let(:user) { create(:user) }
before do
......
require 'spec_helper'
describe Projects::BlameController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
require 'rails_helper'
describe Projects::BlobController do
let(:project) { create(:project, :public) }
let(:project) { create(:project, :public, :repository) }
let(:user) { create(:user) }
before do
......
require 'spec_helper'
describe Projects::BranchesController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:developer) { create(:user) }
......
require 'spec_helper'
describe Projects::CommitController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:commit) { project.commit("master") }
let(:pipeline) { create(:ci_pipeline, project: project, commit: commit) }
......
require 'spec_helper'
describe Projects::CommitsController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
require 'spec_helper'
describe Projects::CompareController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:ref_from) { "improve%2Fawesome" }
let(:ref_to) { "feature" }
......
require 'spec_helper'
describe Projects::CycleAnalyticsController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
require 'spec_helper'
describe Projects::DiscussionsController do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:user) { create(:user) }
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.source_project }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
let(:discussion) { note.discussion }
......
require 'spec_helper'
describe Projects::FindFileController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::ForksController do
let(:user) { create(:user) }
let(:project) { create(:project, :public) }
let(:project) { create(:project, :public, :repository) }
let(:forked_project) { Projects::ForkService.new(project, user).execute }
let(:group) { create(:group, owner: forked_project.creator) }
......
require 'spec_helper'
describe Projects::GraphsController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
......@@ -3,7 +3,7 @@ require 'spec_helper'
describe Projects::GroupLinksController do
let(:group) { create(:group, :private) }
let(:group2) { create(:group, :private) }
let(:project) { create(:project, :private, group: group2) }
let(:project) { create(:empty_project, :private, group: group2) }
let(:user) { create(:user) }
before do
......
......@@ -98,7 +98,7 @@ describe Projects::IssuesController do
end
it 'fills in an issue for a merge request' do
project_with_repository = create(:project)
project_with_repository = create(:project, :repository)
project_with_repository.team << [user, :developer]
mr = create(:merge_request_with_diff_notes, source_project: project_with_repository)
......@@ -124,7 +124,7 @@ describe Projects::IssuesController do
describe 'PUT #update' do
context 'when moving issue to another private project' do
let(:another_project) { create(:project, :private) }
let(:another_project) { create(:empty_project, :private) }
before do
sign_in(user)
......@@ -466,7 +466,7 @@ describe Projects::IssuesController do
context "when the user is owner" do
let(:owner) { create(:user) }
let(:namespace) { create(:namespace, owner: owner) }
let(:project) { create(:project, namespace: namespace) }
let(:project) { create(:empty_project, namespace: namespace) }
before { sign_in(owner) }
......
require 'spec_helper'
describe Projects::MilestonesController do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:milestone) { create(:milestone, project: project) }
let(:issue) { create(:issue, project: project, milestone: milestone) }
......
......@@ -2,7 +2,7 @@ require 'spec_helper'
describe Projects::NotesController do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:issue) { create(:issue, project: project) }
let(:note) { create(:note, noteable: issue, project: project) }
......@@ -16,6 +16,7 @@ describe Projects::NotesController do
describe 'POST create' do
let(:merge_request) { create(:merge_request) }
let(:project) { merge_request.source_project }
let(:request_params) do
{
note: { note: 'some note', noteable_id: merge_request.id, noteable_type: 'MergeRequest' },
......@@ -88,6 +89,7 @@ describe Projects::NotesController do
end
describe "resolving and unresolving" do
let(:project) { create(:project, :repository) }
let(:merge_request) { create(:merge_request, source_project: project) }
let(:note) { create(:diff_note_on_merge_request, noteable: merge_request, project: project) }
......
......@@ -143,7 +143,7 @@ describe Projects::ProjectMembersController do
end
context 'and is an owner' do
let(:project) { create(:project, namespace: user.namespace) }
let(:project) { create(:empty_project, namespace: user.namespace) }
before { project.team << [user, :master] }
......@@ -234,7 +234,7 @@ describe Projects::ProjectMembersController do
end
describe 'POST apply_import' do
let(:another_project) { create(:project, :private) }
let(:another_project) { create(:empty_project, :private) }
let(:member) { create(:user) }
before do
......
require 'spec_helper'
describe Projects::RawController do
let(:public_project) { create(:project, :public) }
let(:public_project) { create(:project, :public, :repository) }
describe "#show" do
context 'regular filename' do
......
require 'spec_helper'
describe Projects::RefsController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
require 'spec_helper'
describe Projects::ReleasesController do
let!(:project) { create(:project) }
let!(:project) { create(:project, :repository) }
let!(:user) { create(:user) }
let!(:release) { create(:release, project: project) }
let!(:tag) { release.tag }
......
require "spec_helper"
describe Projects::RepositoriesController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
describe "GET archive" do
context 'as a guest' do
......
require 'spec_helper'
describe Projects::ServicesController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:service) { create(:service, project: project) }
......
require 'spec_helper'
describe Projects::Settings::IntegrationsController do
let(:project) { create(:project, :public) }
let(:project) { create(:empty_project, :public) }
let(:user) { create(:user) }
before do
......
require 'spec_helper'
describe Projects::TagsController do
let(:project) { create(:project, :public) }
let(:project) { create(:project, :public, :repository) }
let!(:release) { create(:release, project: project) }
let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') }
......
require 'spec_helper'
describe Projects::TemplatesController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:file_path_1) { '.gitlab/issue_templates/bug.md' }
......
require 'spec_helper'
describe Projects::TreeController do
let(:project) { create(:project) }
let(:project) { create(:project, :repository) }
let(:user) { create(:user) }
before do
......
require('spec_helper')
describe Projects::UploadsController do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
......
require('spec_helper')
describe ProjectsController do
let(:project) { create(:project) }
let(:public_project) { create(:project, :public) }
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
let(:project) { create(:empty_project) }
let(:public_project) { create(:empty_project, :public) }
let(:user) { create(:user) }
let(:jpg) { fixture_file_upload(Rails.root + 'spec/fixtures/rails_sample.jpg', 'image/jpg') }
let(:txt) { fixture_file_upload(Rails.root + 'spec/fixtures/doc_sample.txt', 'text/plain') }
describe 'GET index' do
context 'as a user' do
......@@ -32,7 +32,7 @@ describe ProjectsController do
before { sign_in(user) }
context "user does not have access to project" do
let(:private_project) { create(:project, :private) }
let(:private_project) { create(:empty_project, :private) }
it "does not initialize notification setting" do
get :show, namespace_id: private_project.namespace.path, id: private_project.path
......@@ -146,6 +146,8 @@ describe ProjectsController do
end
context "rendering default project view" do
let(:public_project) { create(:project, :public, :repository) }
render_views
it "renders the activity view" do
......@@ -211,25 +213,11 @@ describe ProjectsController do
expect(assigns(:project)).to eq(public_project)
expect(response).to redirect_to("/#{public_project.path_with_namespace}")
end
# MySQL queries are case insensitive by default, so this spec would fail.
if Gitlab::Database.postgresql?
context "when there is also a match with the same casing" do
let!(:other_project) { create(:project, :public, namespace: public_project.namespace, path: public_project.path.upcase) }
it "loads the exactly matched project" do
get :show, namespace_id: public_project.namespace.path, id: public_project.path.upcase
expect(assigns(:project)).to eq(other_project)
expect(response).to have_http_status(200)
end
end
end
end
end
context "when the url contains .atom" do
let(:public_project_with_dot_atom) { build(:project, :public, name: 'my.atom', path: 'my.atom') }
let(:public_project_with_dot_atom) { build(:empty_project, :public, name: 'my.atom', path: 'my.atom') }
it 'expects an error creating the project' do
expect(public_project_with_dot_atom).not_to be_valid
......@@ -238,7 +226,7 @@ describe ProjectsController do
context 'when the project is pending deletions' do
it 'renders a 404 error' do
project = create(:project, pending_delete: true)
project = create(:empty_project, pending_delete: true)
sign_in(user)
get :show, namespace_id: project.namespace.path, id: project.path
......@@ -254,6 +242,7 @@ describe ProjectsController do
let(:admin) { create(:admin) }
it "sets the repository to the right path after a rename" do
project = create(:project, :repository)
new_path = 'renamed_path'
project_params = { path: new_path }
controller.instance_variable_set(:@project, project)
......@@ -405,6 +394,8 @@ describe ProjectsController do
end
describe "GET refs" do
let(:public_project) { create(:project, :public) }
it "gets a list of branches and tags" do
get :refs, namespace_id: public_project.namespace.path, id: public_project.path
......
......@@ -41,7 +41,7 @@ describe UploadsController do
end
context "when viewing a project avatar" do
let!(:project) { create(:project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
let!(:project) { create(:empty_project, avatar: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png")) }
context "when the project is public" do
before do
......
......@@ -73,7 +73,7 @@ describe UsersController do
end
context 'forked project' do
let(:project) { create(:project) }
let(:project) { create(:empty_project) }
let(:forked_project) { Projects::ForkService.new(project, user).execute }
before do
......@@ -91,7 +91,7 @@ describe UsersController do
end
describe 'GET #calendar_activities' do
let!(:project) { create(:project) }
let!(:project) { create(:empty_project) }
let!(:user) { create(:user) }
before do
......
FactoryGirl.define do
factory :deploy_keys_project do
deploy_key
project
project factory: :empty_project
end
end
FactoryGirl.define do
factory :event do
project
project factory: :empty_project
author factory: :user
factory :closed_issue_event do
......
FactoryGirl.define do
factory :file_uploader do
project
project factory: :empty_project
secret nil
transient do
......
......@@ -6,7 +6,7 @@ FactoryGirl.define do
factory :issue do
title
author
project
project factory: :empty_project
trait :confidential do
confidential true
......
......@@ -2,7 +2,7 @@ FactoryGirl.define do
factory :label, class: ProjectLabel do
sequence(:title) { |n| "label#{n}" }
color "#990000"
project
project factory: :empty_project
transient do
priority nil
......
......@@ -2,7 +2,7 @@ FactoryGirl.define do
factory :merge_request do
title
author
source_project factory: :project
association :source_project, :repository, factory: :project
target_project { source_project }
# $ git log --pretty=oneline feature..master
......
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.
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