Commit 1ed0673c authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into refactor-realtime-issue

parents 584ea586 4067dd4f
...@@ -494,7 +494,13 @@ Style/TrailingBlankLines: ...@@ -494,7 +494,13 @@ Style/TrailingBlankLines:
# This cop checks for trailing comma in array and hash literals. # This cop checks for trailing comma in array and hash literals.
Style/TrailingCommaInLiteral: Style/TrailingCommaInLiteral:
Enabled: false Enabled: true
EnforcedStyleForMultiline: no_comma
# This cop checks for trailing comma in argument lists.
Style/TrailingCommaInArguments:
Enabled: true
EnforcedStyleForMultiline: no_comma
# Checks for %W when interpolation is not needed. # Checks for %W when interpolation is not needed.
Style/UnneededCapitalW: Style/UnneededCapitalW:
......
...@@ -369,13 +369,6 @@ Style/SymbolProc: ...@@ -369,13 +369,6 @@ Style/SymbolProc:
Style/TernaryParentheses: Style/TernaryParentheses:
Enabled: false Enabled: false
# Offense count: 53
# Cop supports --auto-correct.
# Configuration parameters: EnforcedStyleForMultiline, SupportedStylesForMultiline.
# SupportedStylesForMultiline: comma, consistent_comma, no_comma
Style/TrailingCommaInArguments:
Enabled: false
# Offense count: 18 # Offense count: 18
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowNamedUnderscoreVariables. # Configuration parameters: AllowNamedUnderscoreVariables.
......
...@@ -8,7 +8,10 @@ export default class BlobViewer { ...@@ -8,7 +8,10 @@ export default class BlobViewer {
this.richViewer = document.querySelector('.blob-viewer[data-type="rich"]'); this.richViewer = document.querySelector('.blob-viewer[data-type="rich"]');
this.$fileHolder = $('.file-holder'); this.$fileHolder = $('.file-holder');
let initialViewerName = document.querySelector('.blob-viewer:not(.hidden)').getAttribute('data-type'); const initialViewer = document.querySelector('.blob-viewer:not(.hidden)');
if (!initialViewer) return;
let initialViewerName = initialViewer.getAttribute('data-type');
this.initBindings(); this.initBindings();
......
...@@ -36,6 +36,9 @@ gl.issueBoards.BoardSidebar = Vue.extend({ ...@@ -36,6 +36,9 @@ gl.issueBoards.BoardSidebar = Vue.extend({
}, },
assigneeId() { assigneeId() {
return this.issue.assignee ? this.issue.assignee.id : 0; return this.issue.assignee ? this.issue.assignee.id : 0;
},
milestoneTitle() {
return this.issue.milestone ? this.issue.milestone.title : 'No Milestone';
} }
}, },
watch: { watch: {
......
...@@ -246,6 +246,7 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -246,6 +246,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
new NotificationsForm(); new NotificationsForm();
if ($('#tree-slider').length) { if ($('#tree-slider').length) {
new TreeView(); new TreeView();
new BlobViewer();
} }
break; break;
case 'projects:pipelines:builds': case 'projects:pipelines:builds':
...@@ -300,6 +301,7 @@ const ShortcutsBlob = require('./shortcuts_blob'); ...@@ -300,6 +301,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
case 'projects:tree:show': case 'projects:tree:show':
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new TreeView(); new TreeView();
new BlobViewer();
gl.TargetBranchDropDown.bootstrap(); gl.TargetBranchDropDown.bootstrap();
break; break;
case 'projects:find_file:show': case 'projects:find_file:show':
......
const AjaxCache = { class AjaxCache {
internalStorage: { }, constructor() {
this.internalStorage = { };
this.pendingRequests = { };
}
get(endpoint) { get(endpoint) {
return this.internalStorage[endpoint]; return this.internalStorage[endpoint];
}, }
hasData(endpoint) { hasData(endpoint) {
return Object.prototype.hasOwnProperty.call(this.internalStorage, endpoint); return Object.prototype.hasOwnProperty.call(this.internalStorage, endpoint);
}, }
purge(endpoint) {
remove(endpoint) {
delete this.internalStorage[endpoint]; delete this.internalStorage[endpoint];
}, }
retrieve(endpoint) { retrieve(endpoint) {
if (AjaxCache.hasData(endpoint)) { if (this.hasData(endpoint)) {
return Promise.resolve(AjaxCache.get(endpoint)); return Promise.resolve(this.get(endpoint));
} }
return new Promise((resolve, reject) => { let pendingRequest = this.pendingRequests[endpoint];
$.ajax(endpoint) // eslint-disable-line promise/catch-or-return
.then(data => resolve(data), if (!pendingRequest) {
(jqXHR, textStatus, errorThrown) => { pendingRequest = new Promise((resolve, reject) => {
const error = new Error(`${endpoint}: ${errorThrown}`); // jQuery 2 is not Promises/A+ compatible (missing catch)
error.textStatus = textStatus; $.ajax(endpoint) // eslint-disable-line promise/catch-or-return
reject(error); .then(data => resolve(data),
}, (jqXHR, textStatus, errorThrown) => {
); const error = new Error(`${endpoint}: ${errorThrown}`);
}) error.textStatus = textStatus;
.then((data) => { this.internalStorage[endpoint] = data; }) reject(error);
.then(() => AjaxCache.get(endpoint)); },
}, );
}; })
.then((data) => {
export default AjaxCache; this.internalStorage[endpoint] = data;
delete this.pendingRequests[endpoint];
})
.catch((error) => {
delete this.pendingRequests[endpoint];
throw error;
});
this.pendingRequests[endpoint] = pendingRequest;
}
return pendingRequest.then(() => this.get(endpoint));
}
}
export default new AjaxCache();
...@@ -18,12 +18,11 @@ ...@@ -18,12 +18,11 @@
} }
$els.each(function(i, dropdown) { $els.each(function(i, dropdown) {
var $block, $dropdown, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, collapsedSidebarLabelTemplate, defaultLabel, issuableId, issueUpdateURL, milestoneLinkNoneTemplate, milestoneLinkTemplate, milestonesUrl, projectId, selectedMilestone, showAny, showNo, showUpcoming, showStarted, useId, showMenuAbove; var $block, $dropdown, $loading, $selectbox, $sidebarCollapsedValue, $value, abilityName, collapsedSidebarLabelTemplate, defaultLabel, defaultNo, issuableId, issueUpdateURL, milestoneLinkNoneTemplate, milestoneLinkTemplate, milestonesUrl, projectId, selectedMilestone, selectedMilestoneDefault, showAny, showNo, showUpcoming, showStarted, useId, showMenuAbove;
$dropdown = $(dropdown); $dropdown = $(dropdown);
projectId = $dropdown.data('project-id'); projectId = $dropdown.data('project-id');
milestonesUrl = $dropdown.data('milestones'); milestonesUrl = $dropdown.data('milestones');
issueUpdateURL = $dropdown.data('issueUpdate'); issueUpdateURL = $dropdown.data('issueUpdate');
selectedMilestone = $dropdown.data('selected');
showNo = $dropdown.data('show-no'); showNo = $dropdown.data('show-no');
showAny = $dropdown.data('show-any'); showAny = $dropdown.data('show-any');
showMenuAbove = $dropdown.data('showMenuAbove'); showMenuAbove = $dropdown.data('showMenuAbove');
...@@ -31,6 +30,7 @@ ...@@ -31,6 +30,7 @@
showStarted = $dropdown.data('show-started'); showStarted = $dropdown.data('show-started');
useId = $dropdown.data('use-id'); useId = $dropdown.data('use-id');
defaultLabel = $dropdown.data('default-label'); defaultLabel = $dropdown.data('default-label');
defaultNo = $dropdown.data('default-no');
issuableId = $dropdown.data('issuable-id'); issuableId = $dropdown.data('issuable-id');
abilityName = $dropdown.data('ability-name'); abilityName = $dropdown.data('ability-name');
$selectbox = $dropdown.closest('.selectbox'); $selectbox = $dropdown.closest('.selectbox');
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
$sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon'); $sidebarCollapsedValue = $block.find('.sidebar-collapsed-icon');
$value = $block.find('.value'); $value = $block.find('.value');
$loading = $block.find('.block-loading').fadeOut(); $loading = $block.find('.block-loading').fadeOut();
selectedMilestoneDefault = (showAny ? '' : null);
selectedMilestoneDefault = (showNo && defaultNo ? 'No Milestone' : selectedMilestoneDefault);
selectedMilestone = $dropdown.data('selected') || selectedMilestoneDefault;
if (issueUpdateURL) { if (issueUpdateURL) {
milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>'); milestoneLinkTemplate = _.template('<a href="/<%- full_path %>/milestones/<%- iid %>" class="bold has-tooltip" data-container="body" title="<%- remaining %>"><%- title %></a>');
milestoneLinkNoneTemplate = '<span class="no-value">None</span>'; milestoneLinkNoneTemplate = '<span class="no-value">None</span>';
...@@ -86,8 +89,18 @@ ...@@ -86,8 +89,18 @@
if (showMenuAbove) { if (showMenuAbove) {
$dropdown.data('glDropdown').positionMenuAbove(); $dropdown.data('glDropdown').positionMenuAbove();
} }
$(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
}); });
}, },
renderRow: function(milestone) {
return `
<li data-milestone-id="${milestone.name}">
<a href='#' class='dropdown-menu-milestone-link'>
${_.escape(milestone.title)}
</a>
</li>
`;
},
filterable: true, filterable: true,
search: { search: {
fields: ['title'] fields: ['title']
...@@ -120,15 +133,24 @@ ...@@ -120,15 +133,24 @@
// display:block overrides the hide-collapse rule // display:block overrides the hide-collapse rule
return $value.css('display', ''); return $value.css('display', '');
}, },
opened: function(e) {
const $el = $(e.currentTarget);
if ($dropdown.hasClass('js-issue-board-sidebar')) {
selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault;
}
$('a.is-active', $el).removeClass('is-active');
$(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active');
},
vue: $dropdown.hasClass('js-issue-board-sidebar'), vue: $dropdown.hasClass('js-issue-board-sidebar'),
clicked: function(options) { clicked: function(options) {
const { $el, e } = options; const { $el, e } = options;
let selected = options.selectedObj; let selected = options.selectedObj;
var data, isIssueIndex, isMRIndex, isSelecting, page, boardsStore;
var data, isIssueIndex, isMRIndex, page, boardsStore;
page = $('body').data('page'); page = $('body').data('page');
isIssueIndex = page === 'projects:issues:index'; isIssueIndex = page === 'projects:issues:index';
isMRIndex = (page === page && page === 'projects:merge_requests:index'); isMRIndex = (page === page && page === 'projects:merge_requests:index');
isSelecting = (selected.name !== selectedMilestone);
selectedMilestone = isSelecting ? selected.name : selectedMilestoneDefault;
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) { if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {
e.preventDefault(); e.preventDefault();
return; return;
...@@ -142,16 +164,11 @@ ...@@ -142,16 +164,11 @@
boardsStore[$dropdown.data('field-name')] = selected.name; boardsStore[$dropdown.data('field-name')] = selected.name;
e.preventDefault(); e.preventDefault();
} else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) {
if (selected.name != null) {
selectedMilestone = selected.name;
} else {
selectedMilestone = '';
}
return Issuable.filterResults($dropdown.closest('form')); return Issuable.filterResults($dropdown.closest('form'));
} else if ($dropdown.hasClass('js-filter-submit')) { } else if ($dropdown.hasClass('js-filter-submit')) {
return $dropdown.closest('form').submit(); return $dropdown.closest('form').submit();
} else if ($dropdown.hasClass('js-issue-board-sidebar')) { } else if ($dropdown.hasClass('js-issue-board-sidebar')) {
if (selected.id !== -1) { if (selected.id !== -1 && isSelecting) {
gl.issueBoards.boardStoreIssueSet('milestone', new ListMilestone({ gl.issueBoards.boardStoreIssueSet('milestone', new ListMilestone({
id: selected.id, id: selected.id,
title: selected.name title: selected.name
......
...@@ -312,7 +312,7 @@ ...@@ -312,7 +312,7 @@
} }
.empty-state { .empty-state {
margin: 100px 0 0; margin: 5% auto 0;
.text-content { .text-content {
max-width: 460px; max-width: 460px;
...@@ -335,27 +335,12 @@ ...@@ -335,27 +335,12 @@
} }
.btn { .btn {
margin: $btn-side-margin $btn-side-margin 0 0; margin: $btn-side-margin 5px;
}
@media(max-width: $screen-xs-max) {
margin-top: 50px;
text-align: center;
.btn { @media(max-width: $screen-xs-max) {
width: 100%; width: 100%;
} }
} }
@media(min-width: $screen-xs-max) {
&.merge-requests .text-content {
margin-top: 40px;
}
&.labels .text-content {
margin-top: 70px;
}
}
} }
.flex-container-block { .flex-container-block {
......
...@@ -51,6 +51,7 @@ ul.related-merge-requests > li { ...@@ -51,6 +51,7 @@ ul.related-merge-requests > li {
display: -ms-flexbox; display: -ms-flexbox;
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
align-items: center;
.merge-request-id { .merge-request-id {
flex-shrink: 0; flex-shrink: 0;
...@@ -59,6 +60,14 @@ ul.related-merge-requests > li { ...@@ -59,6 +60,14 @@ ul.related-merge-requests > li {
.merge-request-info { .merge-request-info {
margin-left: 5px; margin-left: 5px;
} }
.row_title {
vertical-align: bottom;
}
gl-emoji {
font-size: 1em;
}
} }
.merge-requests-title, .merge-requests-title,
...@@ -114,7 +123,6 @@ ul.related-merge-requests > li { ...@@ -114,7 +123,6 @@ ul.related-merge-requests > li {
.related-merge-requests { .related-merge-requests {
.ci-status-link { .ci-status-link {
display: block; display: block;
margin-top: 3px;
margin-right: 5px; margin-right: 5px;
} }
......
...@@ -8,10 +8,6 @@ ...@@ -8,10 +8,6 @@
white-space: nowrap; white-space: nowrap;
} }
.empty-state {
margin: 5% auto 0;
}
.table-holder { .table-holder {
width: 100%; width: 100%;
......
...@@ -41,7 +41,7 @@ class AutocompleteController < ApplicationController ...@@ -41,7 +41,7 @@ class AutocompleteController < ApplicationController
no_project = { no_project = {
id: 0, id: 0,
name_with_namespace: 'No project', name_with_namespace: 'No project'
} }
projects.unshift(no_project) unless params[:offset_id].present? projects.unshift(no_project) unless params[:offset_id].present?
......
...@@ -23,7 +23,7 @@ module LfsRequest ...@@ -23,7 +23,7 @@ module LfsRequest
render( render(
json: { json: {
message: 'Git LFS is not enabled on this GitLab server, contact your admin.', message: 'Git LFS is not enabled on this GitLab server, contact your admin.',
documentation_url: help_url, documentation_url: help_url
}, },
status: 501 status: 501
) )
...@@ -48,7 +48,7 @@ module LfsRequest ...@@ -48,7 +48,7 @@ module LfsRequest
render( render(
json: { json: {
message: 'Access forbidden. Check your access level.', message: 'Access forbidden. Check your access level.',
documentation_url: help_url, documentation_url: help_url
}, },
content_type: "application/vnd.git-lfs+json", content_type: "application/vnd.git-lfs+json",
status: 403 status: 403
...@@ -59,7 +59,7 @@ module LfsRequest ...@@ -59,7 +59,7 @@ module LfsRequest
render( render(
json: { json: {
message: 'Not found.', message: 'Not found.',
documentation_url: help_url, documentation_url: help_url
}, },
content_type: "application/vnd.git-lfs+json", content_type: "application/vnd.git-lfs+json",
status: 404 status: 404
......
class Dashboard::SnippetsController < Dashboard::ApplicationController class Dashboard::SnippetsController < Dashboard::ApplicationController
def index def index
@snippets = SnippetsFinder.new.execute( @snippets = SnippetsFinder.new(
current_user, current_user,
filter: :by_user, author: current_user,
user: current_user,
scope: params[:scope] scope: params[:scope]
) ).execute
@snippets = @snippets.page(params[:page]) @snippets = @snippets.page(params[:page])
end end
end end
class Explore::GroupsController < Explore::ApplicationController class Explore::GroupsController < Explore::ApplicationController
def index def index
@groups = GroupsFinder.new.execute(current_user) @groups = GroupsFinder.new(current_user).execute
@groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present? @groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present?
@groups = @groups.sort(@sort = params[:sort]) @groups = @groups.sort(@sort = params[:sort])
@groups = @groups.page(params[:page]) @groups = @groups.page(params[:page])
......
class Explore::SnippetsController < Explore::ApplicationController class Explore::SnippetsController < Explore::ApplicationController
def index def index
@snippets = SnippetsFinder.new.execute(current_user, filter: :all) @snippets = SnippetsFinder.new(current_user).execute
@snippets = @snippets.page(params[:page]) @snippets = @snippets.page(params[:page])
end end
end end
...@@ -64,7 +64,7 @@ class GroupsController < Groups::ApplicationController ...@@ -64,7 +64,7 @@ class GroupsController < Groups::ApplicationController
end end
def subgroups def subgroups
@nested_groups = group.children @nested_groups = GroupsFinder.new(current_user, parent: group).execute
@nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present? @nested_groups = @nested_groups.search(params[:filter_groups]) if params[:filter_groups].present?
end end
......
...@@ -5,7 +5,7 @@ class HealthController < ActionController::Base ...@@ -5,7 +5,7 @@ class HealthController < ActionController::Base
CHECKS = [ CHECKS = [
Gitlab::HealthChecks::DbCheck, Gitlab::HealthChecks::DbCheck,
Gitlab::HealthChecks::RedisCheck, Gitlab::HealthChecks::RedisCheck,
Gitlab::HealthChecks::FsShardsCheck, Gitlab::HealthChecks::FsShardsCheck
].freeze ].freeze
def readiness def readiness
......
...@@ -4,7 +4,7 @@ class JwtController < ApplicationController ...@@ -4,7 +4,7 @@ class JwtController < ApplicationController
before_action :authenticate_project_or_user before_action :authenticate_project_or_user
SERVICES = { SERVICES = {
Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService, Auth::ContainerRegistryAuthenticationService::AUDIENCE => Auth::ContainerRegistryAuthenticationService
}.freeze }.freeze
def auth def auth
......
...@@ -33,7 +33,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController ...@@ -33,7 +33,7 @@ class Profiles::PreferencesController < Profiles::ApplicationController
:color_scheme_id, :color_scheme_id,
:layout, :layout,
:dashboard, :dashboard,
:project_view, :project_view
) )
end end
end end
...@@ -6,7 +6,7 @@ class Projects::DeploymentsController < Projects::ApplicationController ...@@ -6,7 +6,7 @@ class Projects::DeploymentsController < Projects::ApplicationController
deployments = environment.deployments.reorder(created_at: :desc) deployments = environment.deployments.reorder(created_at: :desc)
deployments = deployments.where('created_at > ?', params[:after].to_time) if params[:after]&.to_time deployments = deployments.where('created_at > ?', params[:after].to_time) if params[:after]&.to_time
render json: { deployments: DeploymentSerializer.new(user: @current_user, project: project) render json: { deployments: DeploymentSerializer.new(project: project)
.represent_concise(deployments) } .represent_concise(deployments) }
end end
......
...@@ -208,7 +208,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -208,7 +208,7 @@ class Projects::IssuesController < Projects::ApplicationController
description: view_context.markdown_field(@issue, :description), description: view_context.markdown_field(@issue, :description),
description_text: @issue.description, description_text: @issue.description,
task_status: @issue.task_status, task_status: @issue.task_status,
updated_at: @issue.updated_at, updated_at: @issue.updated_at
} }
end end
...@@ -268,7 +268,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -268,7 +268,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue_params def issue_params
params.require(:issue).permit( params.require(:issue).permit(
:title, :assignee_id, :position, :description, :confidential, :title, :assignee_id, :position, :description, :confidential,
:milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: [], assignee_ids: [], :milestone_id, :due_date, :state_event, :task_num, :lock_version, label_ids: [], assignee_ids: []
) )
end end
......
...@@ -22,7 +22,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController ...@@ -22,7 +22,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
render( render(
json: { json: {
message: 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.', message: 'Server supports batch API only, please update your Git LFS client to version 1.0.1 and up.',
documentation_url: "#{Gitlab.config.gitlab.url}/help", documentation_url: "#{Gitlab.config.gitlab.url}/help"
}, },
status: 501 status: 501
) )
...@@ -55,7 +55,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController ...@@ -55,7 +55,7 @@ class Projects::LfsApiController < Projects::GitHttpClientController
else else
object[:error] = { object[:error] = {
code: 404, code: 404,
message: "Object does not exist on the server or you don't have permissions to access it", message: "Object does not exist on the server or you don't have permissions to access it"
} }
end end
end end
......
...@@ -44,7 +44,7 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -44,7 +44,7 @@ class Projects::PipelinesController < Projects::ApplicationController
all: @pipelines_count, all: @pipelines_count,
running: @running_count, running: @running_count,
pending: @pending_count, pending: @pending_count,
finished: @finished_count, finished: @finished_count
} }
} }
end end
......
...@@ -23,12 +23,11 @@ class Projects::SnippetsController < Projects::ApplicationController ...@@ -23,12 +23,11 @@ class Projects::SnippetsController < Projects::ApplicationController
respond_to :html respond_to :html
def index def index
@snippets = SnippetsFinder.new.execute( @snippets = SnippetsFinder.new(
current_user, current_user,
filter: :by_project,
project: @project, project: @project,
scope: params[:scope] scope: params[:scope]
) ).execute
@snippets = @snippets.page(params[:page]) @snippets = @snippets.page(params[:page])
if @snippets.out_of_range? && @snippets.total_pages != 0 if @snippets.out_of_range? && @snippets.total_pages != 0
redirect_to namespace_project_snippets_path(page: @snippets.total_pages) redirect_to namespace_project_snippets_path(page: @snippets.total_pages)
......
...@@ -38,6 +38,8 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -38,6 +38,8 @@ class Projects::TagsController < Projects::ApplicationController
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name) redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
else else
@error = result[:message] @error = result[:message]
@message = params[:message]
@release_description = params[:release_description]
render action: 'new' render action: 'new'
end end
end end
......
...@@ -48,7 +48,7 @@ class Projects::TreeController < Projects::ApplicationController ...@@ -48,7 +48,7 @@ class Projects::TreeController < Projects::ApplicationController
@dir_name = File.join(@path, params[:dir_name]) @dir_name = File.join(@path, params[:dir_name])
@commit_params = { @commit_params = {
file_path: @dir_name, file_path: @dir_name,
commit_message: params[:commit_message], commit_message: params[:commit_message]
} }
end end
end end
...@@ -220,7 +220,7 @@ class ProjectsController < Projects::ApplicationController ...@@ -220,7 +220,7 @@ class ProjectsController < Projects::ApplicationController
branches = BranchesFinder.new(@repository, params).execute.map(&:name) branches = BranchesFinder.new(@repository, params).execute.map(&:name)
options = { options = {
'Branches' => branches.take(100), 'Branches' => branches.take(100)
} }
unless @repository.tag_count.zero? unless @repository.tag_count.zero?
......
...@@ -27,12 +27,8 @@ class SnippetsController < ApplicationController ...@@ -27,12 +27,8 @@ class SnippetsController < ApplicationController
return render_404 unless @user return render_404 unless @user
@snippets = SnippetsFinder.new.execute(current_user, { @snippets = SnippetsFinder.new(current_user, author: @user, scope: params[:scope])
filter: :by_user, .execute.page(params[:page])
user: @user,
scope: params[:scope]
})
.page(params[:page])
render 'index' render 'index'
else else
...@@ -103,20 +99,20 @@ class SnippetsController < ApplicationController ...@@ -103,20 +99,20 @@ class SnippetsController < ApplicationController
protected protected
def snippet def snippet
@snippet ||= if current_user @snippet ||= PersonalSnippet.find_by(id: params[:id])
PersonalSnippet.where("author_id = ? OR visibility_level IN (?)",
current_user.id,
[Snippet::PUBLIC, Snippet::INTERNAL]).
find(params[:id])
else
PersonalSnippet.find(params[:id])
end
end end
alias_method :awardable, :snippet alias_method :awardable, :snippet
alias_method :spammable, :snippet alias_method :spammable, :snippet
def authorize_read_snippet! def authorize_read_snippet!
authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet) return if can?(current_user, :read_personal_snippet, @snippet)
if current_user
render_404
else
authenticate_user!
end
end end
def authorize_update_snippet! def authorize_update_snippet!
......
...@@ -128,12 +128,11 @@ class UsersController < ApplicationController ...@@ -128,12 +128,11 @@ class UsersController < ApplicationController
end end
def load_snippets def load_snippets
@snippets = SnippetsFinder.new.execute( @snippets = SnippetsFinder.new(
current_user, current_user,
filter: :by_user, author: user,
user: user,
scope: params[:scope] scope: params[:scope]
).page(params[:page]) ).execute.page(params[:page])
end end
def projects_for_current_user def projects_for_current_user
......
class GroupsFinder < UnionFinder class GroupsFinder < UnionFinder
def execute(current_user = nil) def initialize(current_user = nil, params = {})
segments = all_groups(current_user) @current_user = current_user
@params = params
end
find_union(segments, Group).with_route.order_id_desc def execute
groups = find_union(all_groups, Group).with_route.order_id_desc
by_parent(groups)
end end
private private
def all_groups(current_user) attr_reader :current_user, :params
def all_groups
groups = [] groups = []
groups << current_user.authorized_groups if current_user groups << current_user.authorized_groups if current_user
...@@ -15,4 +21,10 @@ class GroupsFinder < UnionFinder ...@@ -15,4 +21,10 @@ class GroupsFinder < UnionFinder
groups groups
end end
def by_parent(groups)
return groups unless params[:parent]
groups.where(parent: params[:parent])
end
end end
...@@ -67,7 +67,7 @@ class NotesFinder ...@@ -67,7 +67,7 @@ class NotesFinder
when "merge_request" when "merge_request"
MergeRequestsFinder.new(@current_user, project_id: @project.id).execute MergeRequestsFinder.new(@current_user, project_id: @project.id).execute
when "snippet", "project_snippet" when "snippet", "project_snippet"
SnippetsFinder.new.execute(@current_user, filter: :by_project, project: @project) SnippetsFinder.new(@current_user, project: @project).execute
when "personal_snippet" when "personal_snippet"
PersonalSnippet.all PersonalSnippet.all
else else
......
class SnippetsFinder class SnippetsFinder < UnionFinder
def execute(current_user, params = {}) attr_accessor :current_user, :params
filter = params[:filter]
user = params.fetch(:user, current_user) def initialize(current_user, params = {})
@current_user = current_user
case filter @params = params
when :all then end
snippets(current_user).fresh
when :public then def execute
Snippet.are_public.fresh items = init_collection
when :by_user then items = by_project(items)
by_user(current_user, user, params[:scope]) items = by_author(items)
when :by_project items = by_visibility(items)
by_project(current_user, params[:project], params[:scope])
end items.fresh
end end
private private
def snippets(current_user) def init_collection
if current_user items = Snippet.all
Snippet.public_and_internal
else accessible(items)
# Not authenticated
#
# Return only:
# public snippets
Snippet.are_public
end
end end
def by_user(current_user, user, scope) def accessible(items)
snippets = user.snippets.fresh segments = []
segments << items.public_to_user(current_user)
segments << authorized_to_user(items) if current_user
if current_user find_union(segments, Snippet)
include_private = user == current_user
by_scope(snippets, scope, include_private)
else
snippets.are_public
end
end end
def by_project(current_user, project, scope) def authorized_to_user(items)
snippets = project.snippets.fresh items.where(
'author_id = :author_id
OR project_id IN (:project_ids)',
author_id: current_user.id,
project_ids: current_user.authorized_projects.select(:id))
end
if current_user def by_visibility(items)
include_private = project.team.member?(current_user) || current_user.admin? visibility = params[:visibility] || visibility_from_scope
by_scope(snippets, scope, include_private)
else return items unless visibility
snippets.are_public
end items.where(visibility_level: visibility)
end
def by_author(items)
return items unless params[:author]
items.where(author_id: params[:author].id)
end
def by_project(items)
return items unless params[:project]
items.where(project_id: params[:project].id)
end end
def by_scope(snippets, scope = nil, include_private = false) def visibility_from_scope
case scope.to_s case params[:scope].to_s
when 'are_private' when 'are_private'
include_private ? snippets.are_private : Snippet.none Snippet::PRIVATE
when 'are_internal' when 'are_internal'
snippets.are_internal Snippet::INTERNAL
when 'are_public' when 'are_public'
snippets.are_public Snippet::PUBLIC
else else
include_private ? snippets : snippets.public_and_internal nil
end end
end end
end end
...@@ -98,7 +98,7 @@ module DiffHelper ...@@ -98,7 +98,7 @@ module DiffHelper
[ [
content_tag(:span, link_to(truncate(blob.name, length: 40), tree)), content_tag(:span, link_to(truncate(blob.name, length: 40), tree)),
'@', '@',
content_tag(:span, commit_id, class: 'monospace'), content_tag(:span, commit_id, class: 'monospace')
].join(' ').html_safe ].join(' ').html_safe
end end
......
...@@ -12,7 +12,7 @@ module EmailsHelper ...@@ -12,7 +12,7 @@ module EmailsHelper
"action" => { "action" => {
"@type" => "ViewAction", "@type" => "ViewAction",
"name" => name, "name" => name,
"url" => url, "url" => url
} }
} }
......
...@@ -41,7 +41,7 @@ module EventsHelper ...@@ -41,7 +41,7 @@ module EventsHelper
link_opts = { link_opts = {
class: "event-filter-link", class: "event-filter-link",
id: "#{key}_event_filter", id: "#{key}_event_filter",
title: "Filter by #{tooltip.downcase}", title: "Filter by #{tooltip.downcase}"
} }
content_tag :li, class: active do content_tag :li, class: active do
......
...@@ -10,7 +10,7 @@ module ExploreHelper ...@@ -10,7 +10,7 @@ module ExploreHelper
personal: params[:personal], personal: params[:personal],
archived: params[:archived], archived: params[:archived],
shared: params[:shared], shared: params[:shared],
namespace_id: params[:namespace_id], namespace_id: params[:namespace_id]
} }
options = exist_opts.merge(options).delete_if { |key, value| value.blank? } options = exist_opts.merge(options).delete_if { |key, value| value.blank? }
......
...@@ -32,7 +32,7 @@ module MarkupHelper ...@@ -32,7 +32,7 @@ module MarkupHelper
context = { context = {
project: @project, project: @project,
current_user: (current_user if defined?(current_user)), current_user: (current_user if defined?(current_user)),
pipeline: :single_line, pipeline: :single_line
} }
gfm_body = Banzai.render(body, context) gfm_body = Banzai.render(body, context)
...@@ -116,13 +116,13 @@ module MarkupHelper ...@@ -116,13 +116,13 @@ module MarkupHelper
if gitlab_markdown?(file_name) if gitlab_markdown?(file_name)
markdown_unsafe(text, context) markdown_unsafe(text, context)
elsif asciidoc?(file_name) elsif asciidoc?(file_name)
asciidoc_unsafe(text) asciidoc_unsafe(text, context)
elsif plain?(file_name) elsif plain?(file_name)
content_tag :pre, class: 'plain-readme' do content_tag :pre, class: 'plain-readme' do
text text
end end
else else
other_markup_unsafe(file_name, text) other_markup_unsafe(file_name, text, context)
end end
rescue RuntimeError rescue RuntimeError
simple_format(text) simple_format(text)
...@@ -217,12 +217,12 @@ module MarkupHelper ...@@ -217,12 +217,12 @@ module MarkupHelper
Banzai.render(text, context) Banzai.render(text, context)
end end
def asciidoc_unsafe(text) def asciidoc_unsafe(text, context = {})
Gitlab::Asciidoc.render(text) Gitlab::Asciidoc.render(text, context)
end end
def other_markup_unsafe(file_name, text) def other_markup_unsafe(file_name, text, context = {})
Gitlab::OtherMarkup.render(file_name, text) Gitlab::OtherMarkup.render(file_name, text, context)
end end
def prepare_for_rendering(html, context = {}) def prepare_for_rendering(html, context = {})
......
...@@ -54,7 +54,7 @@ module MergeRequestsHelper ...@@ -54,7 +54,7 @@ module MergeRequestsHelper
source_project_id: merge_request.source_project_id, source_project_id: merge_request.source_project_id,
target_project_id: merge_request.target_project_id, target_project_id: merge_request.target_project_id,
source_branch: merge_request.source_branch, source_branch: merge_request.source_branch,
target_branch: merge_request.target_branch, target_branch: merge_request.target_branch
}, },
change_branches: true change_branches: true
) )
......
...@@ -19,7 +19,7 @@ module NotesHelper ...@@ -19,7 +19,7 @@ module NotesHelper
id: noteable.id, id: noteable.id,
class: noteable.class.name, class: noteable.class.name,
resources: noteable.class.table_name, resources: noteable.class.table_name,
project_id: noteable.project.id, project_id: noteable.project.id
}.to_json }.to_json
end end
...@@ -34,7 +34,7 @@ module NotesHelper ...@@ -34,7 +34,7 @@ module NotesHelper
data = { data = {
line_code: line_code, line_code: line_code,
line_type: line_type, line_type: line_type
} }
if @use_legacy_diff_notes if @use_legacy_diff_notes
......
...@@ -42,7 +42,7 @@ module SearchHelper ...@@ -42,7 +42,7 @@ module SearchHelper
{ category: "Settings", label: "User settings", url: profile_path }, { category: "Settings", label: "User settings", url: profile_path },
{ category: "Settings", label: "SSH Keys", url: profile_keys_path }, { category: "Settings", label: "SSH Keys", url: profile_keys_path },
{ category: "Settings", label: "Dashboard", url: root_path }, { category: "Settings", label: "Dashboard", url: root_path },
{ category: "Settings", label: "Admin Section", url: admin_root_path }, { category: "Settings", label: "Admin Section", url: admin_root_path }
] ]
end end
...@@ -57,7 +57,7 @@ module SearchHelper ...@@ -57,7 +57,7 @@ module SearchHelper
{ category: "Help", label: "SSH Keys Help", url: help_page_path("ssh/README") }, { category: "Help", label: "SSH Keys Help", url: help_page_path("ssh/README") },
{ category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks/system_hooks") }, { category: "Help", label: "System Hooks Help", url: help_page_path("system_hooks/system_hooks") },
{ category: "Help", label: "Webhooks Help", url: help_page_path("user/project/integrations/webhooks") }, { category: "Help", label: "Webhooks Help", url: help_page_path("user/project/integrations/webhooks") },
{ category: "Help", label: "Workflow Help", url: help_page_path("workflow/README") }, { category: "Help", label: "Workflow Help", url: help_page_path("workflow/README") }
] ]
end end
...@@ -76,7 +76,7 @@ module SearchHelper ...@@ -76,7 +76,7 @@ module SearchHelper
{ category: "Current Project", label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) }, { category: "Current Project", label: "Milestones", url: namespace_project_milestones_path(@project.namespace, @project) },
{ category: "Current Project", label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) }, { category: "Current Project", label: "Snippets", url: namespace_project_snippets_path(@project.namespace, @project) },
{ category: "Current Project", label: "Members", url: namespace_project_settings_members_path(@project.namespace, @project) }, { category: "Current Project", label: "Members", url: namespace_project_settings_members_path(@project.namespace, @project) },
{ category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) }, { category: "Current Project", label: "Wiki", url: namespace_project_wikis_path(@project.namespace, @project) }
] ]
else else
[] []
......
...@@ -67,7 +67,7 @@ module SelectsHelper ...@@ -67,7 +67,7 @@ module SelectsHelper
current_user: opts[:current_user] || false, current_user: opts[:current_user] || false,
"push-code-to-protected-branches" => opts[:push_code_to_protected_branches], "push-code-to-protected-branches" => opts[:push_code_to_protected_branches],
author_id: opts[:author_id] || '', author_id: opts[:author_id] || '',
skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil, skip_users: opts[:skip_users] ? opts[:skip_users].map(&:id) : nil
} }
end end
end end
...@@ -58,7 +58,7 @@ module SortingHelper ...@@ -58,7 +58,7 @@ module SortingHelper
sort_value_due_date_soon => sort_title_due_date_soon, sort_value_due_date_soon => sort_title_due_date_soon,
sort_value_due_date_later => sort_title_due_date_later, sort_value_due_date_later => sort_title_due_date_later,
sort_value_start_date_soon => sort_title_start_date_soon, sort_value_start_date_soon => sort_title_start_date_soon,
sort_value_start_date_later => sort_title_start_date_later, sort_value_start_date_later => sort_title_start_date_later
} }
end end
......
module SubmoduleHelper module SubmoduleHelper
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
VALID_SUBMODULE_PROTOCOLS = %w[http https git ssh].freeze
# links to files listing for submodule if submodule is a project on this server # links to files listing for submodule if submodule is a project on this server
def submodule_links(submodule_item, ref = nil, repository = @repository) def submodule_links(submodule_item, ref = nil, repository = @repository)
url = repository.submodule_url_for(ref, submodule_item.path) url = repository.submodule_url_for(ref, submodule_item.path)
return url, nil unless url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/ if url =~ /([^\/:]+)\/([^\/]+(?:\.git)?)\Z/
namespace, project = $1, $2
namespace = $1 project.sub!(/\.git\z/, '')
project = $2
project.chomp!('.git')
if self_url?(url, namespace, project) if self_url?(url, namespace, project)
return namespace_project_path(namespace, project), [namespace_project_path(namespace, project),
namespace_project_tree_path(namespace, project, namespace_project_tree_path(namespace, project, submodule_item.id)]
submodule_item.id) elsif relative_self_url?(url)
elsif relative_self_url?(url) relative_self_links(url, submodule_item.id)
relative_self_links(url, submodule_item.id) elsif github_dot_com_url?(url)
elsif github_dot_com_url?(url) standard_links('github.com', namespace, project, submodule_item.id)
standard_links('github.com', namespace, project, submodule_item.id) elsif gitlab_dot_com_url?(url)
elsif gitlab_dot_com_url?(url) standard_links('gitlab.com', namespace, project, submodule_item.id)
standard_links('gitlab.com', namespace, project, submodule_item.id) else
[sanitize_submodule_url(url), nil]
end
else else
return url, nil [sanitize_submodule_url(url), nil]
end end
end end
...@@ -73,4 +75,16 @@ module SubmoduleHelper ...@@ -73,4 +75,16 @@ module SubmoduleHelper
namespace_project_tree_path(namespace, base, commit) namespace_project_tree_path(namespace, base, commit)
] ]
end end
def sanitize_submodule_url(url)
uri = URI.parse(url)
if uri.scheme.in?(VALID_SUBMODULE_PROTOCOLS)
uri.to_s
else
nil
end
rescue URI::InvalidURIError
nil
end
end end
...@@ -63,7 +63,7 @@ module TodosHelper ...@@ -63,7 +63,7 @@ module TodosHelper
project_id: params[:project_id], project_id: params[:project_id],
author_id: params[:author_id], author_id: params[:author_id],
type: params[:type], type: params[:type],
action_id: params[:action_id], action_id: params[:action_id]
} }
end end
......
...@@ -33,7 +33,7 @@ class Blob < SimpleDelegator ...@@ -33,7 +33,7 @@ class Blob < SimpleDelegator
BlobViewer::PDF, BlobViewer::PDF,
BlobViewer::BinarySTL, BlobViewer::BinarySTL,
BlobViewer::TextSTL, BlobViewer::TextSTL
].freeze ].freeze
BINARY_VIEWERS = RICH_VIEWERS.select(&:binary?).freeze BINARY_VIEWERS = RICH_VIEWERS.select(&:binary?).freeze
......
...@@ -124,8 +124,8 @@ module Ci ...@@ -124,8 +124,8 @@ module Ci
success? || failed? || canceled? success? || failed? || canceled?
end end
def retried? def latest?
!self.pipeline.statuses.latest.include?(self) !retried?
end end
def expanded_environment_name def expanded_environment_name
......
...@@ -49,7 +49,7 @@ class Commit ...@@ -49,7 +49,7 @@ class Commit
def max_diff_options def max_diff_options
{ {
max_files: DIFF_HARD_LIMIT_FILES, max_files: DIFF_HARD_LIMIT_FILES,
max_lines: DIFF_HARD_LIMIT_LINES, max_lines: DIFF_HARD_LIMIT_LINES
} }
end end
......
...@@ -18,13 +18,7 @@ class CommitStatus < ActiveRecord::Base ...@@ -18,13 +18,7 @@ class CommitStatus < ActiveRecord::Base
validates :name, presence: true validates :name, presence: true
alias_attribute :author, :user alias_attribute :author, :user
scope :latest, -> do
max_id = unscope(:select).select("max(#{quoted_table_name}.id)")
where(id: max_id.group(:name, :commit_id))
end
scope :failed_but_allowed, -> do scope :failed_but_allowed, -> do
where(allow_failure: true, status: [:failed, :canceled]) where(allow_failure: true, status: [:failed, :canceled])
end end
...@@ -37,7 +31,8 @@ class CommitStatus < ActiveRecord::Base ...@@ -37,7 +31,8 @@ class CommitStatus < ActiveRecord::Base
false, all_state_names - [:failed, :canceled, :manual]) false, all_state_names - [:failed, :canceled, :manual])
end end
scope :retried, -> { where.not(id: latest) } scope :latest, -> { where(retried: [false, nil]) }
scope :retried, -> { where(retried: true) }
scope :ordered, -> { order(:name) } scope :ordered, -> { order(:name) }
scope :latest_ordered, -> { latest.ordered.includes(project: :namespace) } scope :latest_ordered, -> { latest.ordered.includes(project: :namespace) }
scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) } scope :retried_ordered, -> { retried.ordered.includes(project: :namespace) }
......
...@@ -39,7 +39,7 @@ class DiffDiscussion < Discussion ...@@ -39,7 +39,7 @@ class DiffDiscussion < Discussion
def reply_attributes def reply_attributes
super.merge( super.merge(
original_position: original_position.to_json, original_position: original_position.to_json,
position: position.to_json, position: position.to_json
) )
end end
end end
...@@ -62,7 +62,7 @@ class Environment < ActiveRecord::Base ...@@ -62,7 +62,7 @@ class Environment < ActiveRecord::Base
def predefined_variables def predefined_variables
[ [
{ key: 'CI_ENVIRONMENT_NAME', value: name, public: true }, { key: 'CI_ENVIRONMENT_NAME', value: name, public: true },
{ key: 'CI_ENVIRONMENT_SLUG', value: slug, public: true }, { key: 'CI_ENVIRONMENT_SLUG', value: slug, public: true }
] ]
end end
......
...@@ -31,7 +31,7 @@ class WebHook < ActiveRecord::Base ...@@ -31,7 +31,7 @@ class WebHook < ActiveRecord::Base
post_url = url.gsub("#{parsed_url.userinfo}@", '') post_url = url.gsub("#{parsed_url.userinfo}@", '')
auth = { auth = {
username: CGI.unescape(parsed_url.user), username: CGI.unescape(parsed_url.user),
password: CGI.unescape(parsed_url.password), password: CGI.unescape(parsed_url.password)
} }
response = WebHook.post(post_url, response = WebHook.post(post_url,
body: data.to_json, body: data.to_json,
......
...@@ -74,7 +74,7 @@ class Key < ActiveRecord::Base ...@@ -74,7 +74,7 @@ class Key < ActiveRecord::Base
GitlabShellWorker.perform_async( GitlabShellWorker.perform_async(
:remove_key, :remove_key,
shell_id, shell_id,
key, key
) )
end end
......
...@@ -56,7 +56,7 @@ class Namespace < ActiveRecord::Base ...@@ -56,7 +56,7 @@ class Namespace < ActiveRecord::Base
'COALESCE(SUM(ps.storage_size), 0) AS storage_size', 'COALESCE(SUM(ps.storage_size), 0) AS storage_size',
'COALESCE(SUM(ps.repository_size), 0) AS repository_size', 'COALESCE(SUM(ps.repository_size), 0) AS repository_size',
'COALESCE(SUM(ps.lfs_objects_size), 0) AS lfs_objects_size', 'COALESCE(SUM(ps.lfs_objects_size), 0) AS lfs_objects_size',
'COALESCE(SUM(ps.build_artifacts_size), 0) AS build_artifacts_size', 'COALESCE(SUM(ps.build_artifacts_size), 0) AS build_artifacts_size'
) )
end end
......
...@@ -967,7 +967,7 @@ class Project < ActiveRecord::Base ...@@ -967,7 +967,7 @@ class Project < ActiveRecord::Base
namespace: namespace.name, namespace: namespace.name,
visibility_level: visibility_level, visibility_level: visibility_level,
path_with_namespace: path_with_namespace, path_with_namespace: path_with_namespace,
default_branch: default_branch, default_branch: default_branch
} }
# Backward compatibility # Backward compatibility
......
...@@ -52,7 +52,7 @@ class BambooService < CiService ...@@ -52,7 +52,7 @@ class BambooService < CiService
placeholder: 'Bamboo build plan key like KEY' }, placeholder: 'Bamboo build plan key like KEY' },
{ type: 'text', name: 'username', { type: 'text', name: 'username',
placeholder: 'A user with API access, if applicable' }, placeholder: 'A user with API access, if applicable' },
{ type: 'password', name: 'password' }, { type: 'password', name: 'password' }
] ]
end end
......
...@@ -39,7 +39,7 @@ class ChatNotificationService < Service ...@@ -39,7 +39,7 @@ class ChatNotificationService < Service
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" }, { type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
{ type: 'text', name: 'username', placeholder: 'e.g. GitLab' }, { type: 'text', name: 'username', placeholder: 'e.g. GitLab' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'checkbox', name: 'notify_only_default_branch' }, { type: 'checkbox', name: 'notify_only_default_branch' }
] ]
end end
......
...@@ -47,7 +47,7 @@ class EmailsOnPushService < Service ...@@ -47,7 +47,7 @@ class EmailsOnPushService < Service
help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." }, help: "Send notifications from the committer's email address if the domain is part of the domain GitLab is running on (e.g. #{domains})." },
{ type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs", { type: 'checkbox', name: 'disable_diffs', title: "Disable code diffs",
help: "Don't include possibly sensitive code diffs in notification body." }, help: "Don't include possibly sensitive code diffs in notification body." },
{ type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }, { type: 'textarea', name: 'recipients', placeholder: 'Emails separated by whitespace' }
] ]
end end
end end
...@@ -19,7 +19,7 @@ class ExternalWikiService < Service ...@@ -19,7 +19,7 @@ class ExternalWikiService < Service
def fields def fields
[ [
{ type: 'text', name: 'external_wiki_url', placeholder: 'The URL of the external Wiki' }, { type: 'text', name: 'external_wiki_url', placeholder: 'The URL of the external Wiki' }
] ]
end end
......
...@@ -37,7 +37,7 @@ class FlowdockService < Service ...@@ -37,7 +37,7 @@ class FlowdockService < Service
repo: project.repository.path_to_repo, repo: project.repository.path_to_repo,
repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}", repo_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}",
commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s", commit_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/%s",
diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s", diff_url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/compare/%s...%s"
) )
end end
end end
...@@ -41,7 +41,7 @@ class HipchatService < Service ...@@ -41,7 +41,7 @@ class HipchatService < Service
placeholder: 'Leave blank for default (v2)' }, placeholder: 'Leave blank for default (v2)' },
{ type: 'text', name: 'server', { type: 'text', name: 'server',
placeholder: 'Leave blank for default. https://hipchat.example.com' }, placeholder: 'Leave blank for default. https://hipchat.example.com' },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' }
] ]
end end
......
...@@ -58,7 +58,7 @@ class IrkerService < Service ...@@ -58,7 +58,7 @@ class IrkerService < Service
' want to use a password, you have to omit the "#" on the channel). If you ' \ ' want to use a password, you have to omit the "#" on the channel). If you ' \
' specify a default IRC URI to prepend before each recipient, you can just ' \ ' specify a default IRC URI to prepend before each recipient, you can just ' \
' give a channel name.' }, ' give a channel name.' },
{ type: 'checkbox', name: 'colorize_messages' }, { type: 'checkbox', name: 'colorize_messages' }
] ]
end end
......
...@@ -149,7 +149,7 @@ class JiraService < IssueTrackerService ...@@ -149,7 +149,7 @@ class JiraService < IssueTrackerService
data = { data = {
user: { user: {
name: author.name, name: author.name,
url: resource_url(user_path(author)), url: resource_url(user_path(author))
}, },
project: { project: {
name: self.project.path_with_namespace, name: self.project.path_with_namespace,
......
...@@ -73,7 +73,7 @@ class KubernetesService < DeploymentService ...@@ -73,7 +73,7 @@ class KubernetesService < DeploymentService
{ type: 'textarea', { type: 'textarea',
name: 'ca_pem', name: 'ca_pem',
title: 'Custom CA bundle', title: 'Custom CA bundle',
placeholder: 'Certificate Authority bundle (PEM format)' }, placeholder: 'Certificate Authority bundle (PEM format)' }
] ]
end end
......
...@@ -35,7 +35,7 @@ class MicrosoftTeamsService < ChatNotificationService ...@@ -35,7 +35,7 @@ class MicrosoftTeamsService < ChatNotificationService
[ [
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" }, { type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' }, { type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'checkbox', name: 'notify_only_default_branch' }, { type: 'checkbox', name: 'notify_only_default_branch' }
] ]
end end
......
...@@ -21,7 +21,7 @@ class MockCiService < CiService ...@@ -21,7 +21,7 @@ class MockCiService < CiService
[ [
{ type: 'text', { type: 'text',
name: 'mock_service_url', name: 'mock_service_url',
placeholder: 'http://localhost:4004' }, placeholder: 'http://localhost:4004' }
] ]
end end
......
...@@ -55,7 +55,7 @@ class PipelinesEmailService < Service ...@@ -55,7 +55,7 @@ class PipelinesEmailService < Service
name: 'recipients', name: 'recipients',
placeholder: 'Emails separated by comma' }, placeholder: 'Emails separated by comma' },
{ type: 'checkbox', { type: 'checkbox',
name: 'notify_only_broken_pipelines' }, name: 'notify_only_broken_pipelines' }
] ]
end end
......
...@@ -55,7 +55,7 @@ class PushoverService < Service ...@@ -55,7 +55,7 @@ class PushoverService < Service
['Pushover Echo (long)', 'echo'], ['Pushover Echo (long)', 'echo'],
['Up Down (long)', 'updown'], ['Up Down (long)', 'updown'],
['None (silent)', 'none'] ['None (silent)', 'none']
] }, ] }
] ]
end end
......
...@@ -55,7 +55,7 @@ class TeamcityService < CiService ...@@ -55,7 +55,7 @@ class TeamcityService < CiService
placeholder: 'Build configuration ID' }, placeholder: 'Build configuration ID' },
{ type: 'text', name: 'username', { type: 'text', name: 'username',
placeholder: 'A user with permissions to trigger a manual build' }, placeholder: 'A user with permissions to trigger a manual build' },
{ type: 'password', name: 'password' }, { type: 'password', name: 'password' }
] ]
end end
...@@ -78,7 +78,7 @@ class TeamcityService < CiService ...@@ -78,7 +78,7 @@ class TeamcityService < CiService
auth = { auth = {
username: username, username: username,
password: password, password: password
} }
branch = Gitlab::Git.ref_name(data[:ref]) branch = Gitlab::Git.ref_name(data[:ref])
......
class ReadmeBlob < SimpleDelegator
attr_reader :repository
def initialize(blob, repository)
@repository = repository
super(blob)
end
def rendered_markup
repository.rendered_readme
end
end
...@@ -518,7 +518,7 @@ class Repository ...@@ -518,7 +518,7 @@ class Repository
def readme def readme
if head = tree(:head) if head = tree(:head)
head.readme ReadmeBlob.new(head.readme, self)
end end
end end
...@@ -833,7 +833,7 @@ class Repository ...@@ -833,7 +833,7 @@ class Repository
actual_options = options.merge( actual_options = options.merge(
parents: [our_commit, their_commit], parents: [our_commit, their_commit],
tree: merge_index.write_tree(rugged), tree: merge_index.write_tree(rugged)
) )
commit_id = create_commit(actual_options) commit_id = create_commit(actual_options)
......
...@@ -39,7 +39,7 @@ class SentNotification < ActiveRecord::Base ...@@ -39,7 +39,7 @@ class SentNotification < ActiveRecord::Base
noteable_type: noteable.class.name, noteable_type: noteable.class.name,
noteable_id: noteable_id, noteable_id: noteable_id,
commit_id: commit_id, commit_id: commit_id
) )
create(attrs) create(attrs)
......
...@@ -152,18 +152,5 @@ class Snippet < ActiveRecord::Base ...@@ -152,18 +152,5 @@ class Snippet < ActiveRecord::Base
where(table[:content].matches(pattern)) where(table[:content].matches(pattern))
end end
def accessible_to(user)
return are_public unless user.present?
return all if user.admin?
where(
'visibility_level IN (:visibility_levels)
OR author_id = :author_id
OR project_id IN (:project_ids)',
visibility_levels: [Snippet::PUBLIC, Snippet::INTERNAL],
author_id: user.id,
project_ids: user.authorized_projects.select(:id))
end
end end
end end
...@@ -40,10 +40,7 @@ class Tree ...@@ -40,10 +40,7 @@ class Tree
readme_path = path == '/' ? readme_tree.name : File.join(path, readme_tree.name) readme_path = path == '/' ? readme_tree.name : File.join(path, readme_tree.name)
git_repo = repository.raw_repository @readme = repository.blob_at(sha, readme_path)
@readme = Gitlab::Git::Blob.find(git_repo, sha, readme_path)
@readme.load_all_data!(git_repo)
@readme
end end
def trees def trees
......
...@@ -13,7 +13,7 @@ class ProjectSnippetPolicy < BasePolicy ...@@ -13,7 +13,7 @@ class ProjectSnippetPolicy < BasePolicy
can! :read_project_snippet can! :read_project_snippet
end end
if @subject.private? && @subject.project.team.member?(@user) if @subject.project.team.member?(@user)
can! :read_project_snippet can! :read_project_snippet
end end
end end
......
...@@ -16,7 +16,7 @@ class AkismetService ...@@ -16,7 +16,7 @@ class AkismetService
created_at: DateTime.now, created_at: DateTime.now,
author: owner.name, author: owner.name,
author_email: owner.email, author_email: owner.email,
referrer: options[:referrer], referrer: options[:referrer]
} }
begin begin
......
...@@ -8,7 +8,7 @@ class AuditEventService ...@@ -8,7 +8,7 @@ class AuditEventService
with: @details[:with], with: @details[:with],
target_id: @author.id, target_id: @author.id,
target_type: 'User', target_type: 'User',
target_details: @author.name, target_details: @author.name
} }
self self
......
...@@ -38,7 +38,7 @@ module Boards ...@@ -38,7 +38,7 @@ module Boards
attrs.merge!( attrs.merge!(
add_label_ids: add_label_ids, add_label_ids: add_label_ids,
remove_label_ids: remove_label_ids, remove_label_ids: remove_label_ids,
state_event: issue_state, state_event: issue_state
) )
end end
......
...@@ -5,6 +5,8 @@ module Ci ...@@ -5,6 +5,8 @@ module Ci
def execute(pipeline) def execute(pipeline)
@pipeline = pipeline @pipeline = pipeline
update_retried
new_builds = new_builds =
stage_indexes_of_created_builds.map do |index| stage_indexes_of_created_builds.map do |index|
process_stage(index) process_stage(index)
...@@ -71,5 +73,23 @@ module Ci ...@@ -71,5 +73,23 @@ module Ci
def created_builds def created_builds
pipeline.builds.created pipeline.builds.created
end end
# This method is for compatibility and data consistency and should be removed with 9.3 version of GitLab
# This replicates what is db/post_migrate/20170416103934_upate_retried_for_ci_build.rb
# and ensures that functionality will not be broken before migration is run
# this updates only when there are data that needs to be updated, there are two groups with no retried flag
def update_retried
# find the latest builds for each name
latest_statuses = pipeline.statuses.latest
.group(:name)
.having('count(*) > 1')
.pluck('max(id)', 'name')
# mark builds that are retried
pipeline.statuses.latest
.where(name: latest_statuses.map(&:second))
.where.not(id: latest_statuses.map(&:first))
.update_all(retried: true) if latest_statuses.any?
end
end end
end end
...@@ -6,7 +6,7 @@ module Ci ...@@ -6,7 +6,7 @@ module Ci
description tag_list].freeze description tag_list].freeze
def execute(build) def execute(build)
reprocess(build).tap do |new_build| reprocess!(build).tap do |new_build|
build.pipeline.mark_as_processable_after_stage(build.stage_idx) build.pipeline.mark_as_processable_after_stage(build.stage_idx)
new_build.enqueue! new_build.enqueue!
...@@ -17,7 +17,7 @@ module Ci ...@@ -17,7 +17,7 @@ module Ci
end end
end end
def reprocess(build) def reprocess!(build)
unless can?(current_user, :update_build, build) unless can?(current_user, :update_build, build)
raise Gitlab::Access::AccessDeniedError raise Gitlab::Access::AccessDeniedError
end end
...@@ -28,7 +28,14 @@ module Ci ...@@ -28,7 +28,14 @@ module Ci
attributes.push([:user, current_user]) attributes.push([:user, current_user])
project.builds.create(Hash[attributes]) Ci::Build.transaction do
# mark all other builds of that name as retried
build.pipeline.builds.latest
.where(name: build.name)
.update_all(retried: true)
project.builds.create!(Hash[attributes])
end
end end
end end
end end
...@@ -11,7 +11,7 @@ module Ci ...@@ -11,7 +11,7 @@ module Ci
next unless can?(current_user, :update_build, build) next unless can?(current_user, :update_build, build)
Ci::RetryBuildService.new(project, current_user) Ci::RetryBuildService.new(project, current_user)
.reprocess(build) .reprocess!(build)
end end
pipeline.builds.latest.skipped.find_each do |skipped| pipeline.builds.latest.skipped.find_each do |skipped|
......
...@@ -298,7 +298,7 @@ class NotificationService ...@@ -298,7 +298,7 @@ class NotificationService
recipients ||= NotificationRecipientService.new(pipeline.project).build_pipeline_recipients( recipients ||= NotificationRecipientService.new(pipeline.project).build_pipeline_recipients(
pipeline, pipeline,
pipeline.user, pipeline.user,
action: pipeline.status, action: pipeline.status
).map(&:notification_email) ).map(&:notification_email)
if recipients.any? if recipients.any?
......
...@@ -27,7 +27,7 @@ module Projects ...@@ -27,7 +27,7 @@ module Projects
{ {
domain: domain.domain, domain: domain.domain,
certificate: domain.certificate, certificate: domain.certificate,
key: domain.key, key: domain.key
} }
end end
end end
......
...@@ -7,7 +7,7 @@ module Search ...@@ -7,7 +7,7 @@ module Search
end end
def execute def execute
snippets = Snippet.accessible_to(current_user) snippets = SnippetsFinder.new(current_user).execute
Gitlab::SnippetSearchResults.new(snippets, params[:search]) Gitlab::SnippetSearchResults.new(snippets, params[:search])
end end
......
...@@ -51,7 +51,7 @@ class SystemHooksService ...@@ -51,7 +51,7 @@ class SystemHooksService
path: model.path, path: model.path,
group_id: model.id, group_id: model.id,
owner_name: owner.respond_to?(:name) ? owner.name : nil, owner_name: owner.respond_to?(:name) ? owner.name : nil,
owner_email: owner.respond_to?(:email) ? owner.email : nil, owner_email: owner.respond_to?(:email) ? owner.email : nil
) )
when GroupMember when GroupMember
data.merge!(group_member_data(model)) data.merge!(group_member_data(model))
...@@ -113,7 +113,7 @@ class SystemHooksService ...@@ -113,7 +113,7 @@ class SystemHooksService
user_name: model.user.name, user_name: model.user.name,
user_email: model.user.email, user_email: model.user.email,
user_id: model.user.id, user_id: model.user.id,
group_access: model.human_access, group_access: model.human_access
} }
end end
end end
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.diff-file.file-holder .diff-file.file-holder
.js-file-title.file-title .js-file-title.file-title
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_path(discussion) = render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_path(discussion), show_toggle: false
.diff-content.code.js-syntax-highlight .diff-content.code.js-syntax-highlight
%table %table
......
...@@ -10,4 +10,4 @@ ...@@ -10,4 +10,4 @@
- else - else
:plain :plain
job = $("tr#repo_#{@repo_id}") job = $("tr#repo_#{@repo_id}")
job.find(".import-actions").html("<i class='fa fa-exclamation-circle'></i> Error saving project: #{escape_javascript(@project.errors.full_messages.join(','))}") job.find(".import-actions").html("<i class='fa fa-exclamation-circle'></i> Error saving project: #{escape_javascript(h(@project.errors.full_messages.join(',')))}")
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
%article.readme-holder %article.readme-holder
.pull-right .pull-right
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
= link_to icon('pencil'), namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)), class: 'light edit-project-readme' = link_to icon('pencil'), namespace_project_edit_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.path)), class: 'light edit-project-readme'
.file-content.wiki
= markup(readme.name, readme.data, rendered: @repository.rendered_readme) = render 'projects/blob/viewer', viewer: readme.rich_viewer, viewer_url: namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.path), viewer: :rich, format: :json)
- else - else
.row-content-block.second-block.center .row-content-block.second-block.center
%h3.page-title %h3.page-title
......
- @gfm_form = true - @gfm_form = true
- current_text ||= nil
- supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false) - supports_slash_commands = local_assigns.fetch(:supports_slash_commands, false)
.zen-backdrop .zen-backdrop
- classes << ' js-gfm-input js-autosize markdown-area' - classes << ' js-gfm-input js-autosize markdown-area'
- if defined?(f) && f - if defined?(f) && f
= f.text_area attr, class: classes, placeholder: placeholder, data: { supports_slash_commands: supports_slash_commands } = f.text_area attr, class: classes, placeholder: placeholder, data: { supports_slash_commands: supports_slash_commands }
- else - else
= text_area_tag attr, nil, class: classes, placeholder: placeholder = text_area_tag attr, current_text, class: classes, placeholder: placeholder
%a.zen-control.zen-control-leave.js-zen-leave{ href: "#" } %a.zen-control.zen-control-leave.js-zen-leave{ href: "#" }
= icon('compress') = icon('compress')
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
- render_error = viewer.render_error - render_error = viewer.render_error
- load_asynchronously = local_assigns.fetch(:load_asynchronously, viewer.server_side?) && render_error.nil? - load_asynchronously = local_assigns.fetch(:load_asynchronously, viewer.server_side?) && render_error.nil?
- url = url_for(params.merge(viewer: viewer.type, format: :json)) if load_asynchronously - viewer_url = local_assigns.fetch(:viewer_url) { url_for(params.merge(viewer: viewer.type, format: :json)) } if load_asynchronously
.blob-viewer{ data: { type: viewer.type, url: url }, class: ('hidden' if hidden) } .blob-viewer{ data: { type: viewer.type, url: viewer_url }, class: ('hidden' if hidden) }
- if load_asynchronously - if load_asynchronously
.text-center.prepend-top-default.append-bottom-default .text-center.prepend-top-default.append-bottom-default
= icon('spinner spin 2x', 'aria-hidden' => 'true', 'aria-label' => 'Loading content') = icon('spinner spin 2x', 'aria-hidden' => 'true', 'aria-label' => 'Loading content')
......
...@@ -16,7 +16,8 @@ ...@@ -16,7 +16,8 @@
name: "issue[milestone_id]", name: "issue[milestone_id]",
"v-if" => "issue.milestone" } "v-if" => "issue.milestone" }
.dropdown .dropdown
%button.dropdown-menu-toggle.js-milestone-select.js-issue-board-sidebar{ type: "button", data: { toggle: "dropdown", show_no: "true", field_name: "issue[milestone_id]", project_id: @project.id, milestones: namespace_project_milestones_path(@project.namespace, @project, :json), ability_name: "issue", use_id: "true" }, %button.dropdown-menu-toggle.js-milestone-select.js-issue-board-sidebar{ type: "button", data: { toggle: "dropdown", show_no: "true", field_name: "issue[milestone_id]", project_id: @project.id, milestones: namespace_project_milestones_path(@project.namespace, @project, :json), ability_name: "issue", use_id: "true", default_no: "true" },
":data-selected" => "milestoneTitle",
":data-issuable-id" => "issue.id", ":data-issuable-id" => "issue.id",
":data-issue-update" => "'#{namespace_project_issues_path(@project.namespace, @project)}/' + issue.id + '.json'" } ":data-issue-update" => "'#{namespace_project_issues_path(@project.namespace, @project)}/' + issue.id + '.json'" }
Milestone Milestone
......
...@@ -51,7 +51,7 @@ ...@@ -51,7 +51,7 @@
%ul %ul
%li.stage-header %li.stage-header
%span.stage-name %span.stage-name
{{ __('ProjectLifecycle|Stage') }} {{ s__('ProjectLifecycle|Stage') }}
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: _("The phase of the development lifecycle."), "aria-hidden" => "true" } %i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: _("The phase of the development lifecycle."), "aria-hidden" => "true" }
%li.median-header %li.median-header
%span.stage-name %span.stage-name
......
%i.fa.diff-toggle-caret.fa-fw - show_toggle = local_assigns.fetch(:show_toggle, true)
- if show_toggle
%i.fa.diff-toggle-caret.fa-fw
- if defined?(blob) && blob && diff_file.submodule? - if defined?(blob) && blob && diff_file.submodule?
%span %span
= icon('archive fw') = icon('archive fw')
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
.panel-body .panel-body
%pre %pre
:preserve :preserve
#{sanitize_repo_path(@project, @project.import_error)} #{h(sanitize_repo_path(@project, @project.import_error))}
= form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f| = form_for @project, url: namespace_project_import_path(@project.namespace, @project), method: :post, html: { class: 'form-horizontal' } do |f|
= render "shared/import_form", f: f = render "shared/import_form", f: f
......
...@@ -22,14 +22,14 @@ ...@@ -22,14 +22,14 @@
.form-group .form-group
= label_tag :message, nil, class: 'control-label' = label_tag :message, nil, class: 'control-label'
.col-sm-10 .col-sm-10
= text_area_tag :message, nil, required: false, tabindex: 3, class: 'form-control', rows: 5 = text_area_tag :message, @message, required: false, tabindex: 3, class: 'form-control', rows: 5
.help-block Optionally, add a message to the tag. .help-block Optionally, add a message to the tag.
%hr %hr
.form-group .form-group
= label_tag :release_description, 'Release notes', class: 'control-label' = label_tag :release_description, 'Release notes', class: 'control-label'
.col-sm-10 .col-sm-10
= render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do = render layout: 'projects/md_preview', locals: { url: preview_markdown_path(@project), referenced_users: true } do
= render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here..." = render 'projects/zen', attr: :release_description, classes: 'note-textarea', placeholder: "Write your release notes or drag files here...", current_text: @release_description
= render 'shared/notes/hints' = render 'shared/notes/hints'
.help-block Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page. .help-block Optionally, add release notes to the tag. They will be stored in the GitLab database and displayed on the tags page.
.form-actions .form-actions
......
%article.file-holder.readme-holder %article.file-holder.readme-holder
.js-file-title.file-title .js-file-title.file-title
= blob_icon readme.mode, readme.name = blob_icon readme.mode, readme.name
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, @path, readme.name)) do = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, readme.path)) do
%strong %strong
= readme.name = readme.name
.file-content.wiki
= markup(readme.name, readme.data) = render 'projects/blob/viewer', viewer: readme.rich_viewer, viewer_url: namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, readme.path), viewer: :rich, format: :json)
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
%h3 Clone your wiki %h3 Clone your wiki
%pre.dark %pre.dark
:preserve :preserve
git clone #{ content_tag(:span, default_url_to_repo(@project_wiki), class: 'clone')} git clone #{ content_tag(:span, h(default_url_to_repo(@project_wiki)), class: 'clone')}
cd #{h @project_wiki.path} cd #{h @project_wiki.path}
%h3 Start Gollum and edit locally %h3 Start Gollum and edit locally
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
- has_button = button_path || project_select_button - has_button = button_path || project_select_button
.row.empty-state .row.empty-state
.pull-right.col-xs-12{ class: "#{'col-sm-6' if has_button}" } .col-xs-12
.svg-content .svg-content
= render 'shared/empty_states/icons/issues.svg' = render 'shared/empty_states/icons/issues.svg'
.col-xs-12{ class: "#{'col-sm-6' if has_button}" } .col-xs-12.text-center
.text-content .text-content
- if has_button && current_user - if has_button && current_user
%h4 %h4
......
.row.empty-state.labels .row.empty-state.labels
.pull-right.col-xs-12.col-sm-6 .col-xs-12
.svg-content .svg-content
= render 'shared/empty_states/icons/labels.svg' = render 'shared/empty_states/icons/labels.svg'
.col-xs-12.col-sm-6 .col-xs-12.text-center
.text-content .text-content
%h4 Labels can be applied to issues and merge requests to categorize them. %h4 Labels can be applied to issues and merge requests to categorize them.
%p You can also star a label to make it a priority label. %p You can also star a label to make it a priority label.
......
...@@ -3,10 +3,10 @@ ...@@ -3,10 +3,10 @@
- has_button = button_path || project_select_button - has_button = button_path || project_select_button
.row.empty-state.merge-requests .row.empty-state.merge-requests
.col-xs-12{ class: "#{'col-sm-6 pull-right' if has_button}" } .col-xs-12
.svg-content .svg-content
= render 'shared/empty_states/icons/merge_requests.svg' = render 'shared/empty_states/icons/merge_requests.svg'
.col-xs-12{ class: "#{'col-sm-6' if has_button}" } .col-xs-12.text-center
.text-content .text-content
- if has_button - if has_button
%h4 %h4
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
- if selected.present? || params[:milestone_title].present? - if selected.present? || params[:milestone_title].present?
= hidden_field_tag(name, name == :milestone_title ? selected_text : selected.id) = hidden_field_tag(name, name == :milestone_title ? selected_text : selected.id)
= dropdown_tag(milestone_dropdown_label(selected_text), options: { title: dropdown_title, toggle_class: "js-milestone-select js-filter-submit #{extra_class}", filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone", = dropdown_tag(milestone_dropdown_label(selected_text), options: { title: dropdown_title, toggle_class: "js-milestone-select js-filter-submit #{extra_class}", filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone",
placeholder: "Search milestones", footer_content: project.present?, data: { show_no: true, show_menu_above: show_menu_above, show_any: show_any, show_upcoming: show_upcoming, show_started: show_started, field_name: name, selected: selected.try(:title), project_id: project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do placeholder: "Search milestones", footer_content: project.present?, data: { show_no: true, show_menu_above: show_menu_above, show_any: show_any, show_upcoming: show_upcoming, show_started: show_started, field_name: name, selected: selected_text, project_id: project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
- if project - if project
%ul.dropdown-footer-list %ul.dropdown-footer-list
- if can? current_user, :admin_milestone, project - if can? current_user, :admin_milestone, project
......
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.
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.
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.
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