Commit 58fe13ec authored by Phil Hughes's avatar Phil Hughes

Merge branch 'master' into '44453-performance-bar-modalbox'

# Conflicts:
#   app/assets/javascripts/performance_bar/components/detailed_metric.vue
parents b6a9a8ba 4718f22f
This diff is collapsed.
# --- Special code for migrating to Rails 5.0 ---
def rails5?
%w[1 true].include?(ENV["RAILS5"])
end
gem_versions = {}
gem_versions['activerecord_sane_schema_dumper'] = rails5? ? '1.0' : '0.2'
gem_versions['default_value_for'] = rails5? ? '~> 3.0.5' : '~> 3.0.0'
gem_versions['html-pipeline'] = rails5? ? '~> 2.6.0' : '~> 1.11.0'
gem_versions['rails'] = rails5? ? '5.0.6' : '4.2.10'
gem_versions['rails-i18n'] = rails5? ? '~> 5.1' : '~> 4.0.9'
# --- The end of special code for migrating to Rails 5.0 ---
source 'https://rubygems.org'
gem 'rails', '4.2.10'
gem 'rails', gem_versions['rails']
gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with
......@@ -9,7 +22,7 @@ gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.7.0'
# Default values for AR models
gem 'default_value_for', '~> 3.0.0'
gem 'default_value_for', gem_versions['default_value_for']
# Supported DBs
gem 'mysql2', '~> 0.4.10', group: :mysql
......@@ -24,7 +37,7 @@ gem 'faraday', '~> 0.12'
gem 'devise', '~> 4.2'
gem 'doorkeeper', '~> 4.3'
gem 'doorkeeper-openid_connect', '~> 1.3'
gem 'omniauth', '~> 1.4.2'
gem 'omniauth', '~> 1.8'
gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.9'
gem 'omniauth-cas3', '~> 1.1.4'
......@@ -122,7 +135,7 @@ gem 'unf', '~> 0.1.4'
gem 'seed-fu', '~> 2.3.7'
# Markdown and HTML processing
gem 'html-pipeline', '~> 1.11.0'
gem 'html-pipeline', gem_versions['html-pipeline']
gem 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.6.2'
gem 'redcarpet', '~> 3.4'
......@@ -266,7 +279,7 @@ gem 'premailer-rails', '~> 1.9.7'
# I18n
gem 'ruby_parser', '~> 3.8', require: false
gem 'rails-i18n', '~> 4.0.9'
gem 'rails-i18n', gem_versions['rails-i18n']
gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.3'
gem 'gettext', '~> 3.2.2', require: false, group: :development
......@@ -357,7 +370,7 @@ group :development, :test do
gem 'license_finder', '~> 3.1', require: false
gem 'knapsack', '~> 1.16'
gem 'activerecord_sane_schema_dumper', '0.2'
gem 'activerecord_sane_schema_dumper', gem_versions['activerecord_sane_schema_dumper']
gem 'stackprof', '~> 0.2.10', require: false
......
......@@ -524,8 +524,8 @@ GEM
rack (>= 1.2, < 3)
octokit (4.8.0)
sawyer (~> 0.8.0, >= 0.5.3)
omniauth (1.4.3)
hashie (>= 1.2, < 4)
omniauth (1.8.1)
hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3)
omniauth-auth0 (1.4.1)
omniauth-oauth2 (~> 1.1)
......@@ -1104,7 +1104,7 @@ DEPENDENCIES
nokogiri (~> 1.8.2)
oauth2 (~> 1.4)
octokit (~> 4.8)
omniauth (~> 1.4.2)
omniauth (~> 1.8)
omniauth-auth0 (~> 1.4.1)
omniauth-authentiq (~> 0.3.1)
omniauth-azure-oauth2 (~> 0.0.9)
......
# BUNDLE_GEMFILE=Gemfile.rails5 bundle install
ENV["RAILS5"] = "true"
gemfile = File.expand_path("../Gemfile", __FILE__)
eval(File.read(gemfile), nil, gemfile)
This diff is collapsed.
......@@ -4,4 +4,3 @@
#
web: RAILS_ENV=development bin/web start_foreground
worker: RAILS_ENV=development bin/background_jobs start_foreground
# mail_room: bundle exec mail_room -q -c config/mail_room.yml
10.6.0-pre
10.7.0-pre
......@@ -43,6 +43,7 @@ export default {
'file-open': this.isBlob && this.file.opened,
'file-active': this.isBlob && this.file.active,
folder: this.isTree,
'is-open': this.file.opened,
};
},
},
......
......@@ -54,7 +54,8 @@ const router = new VueRouter({
router.beforeEach((to, from, next) => {
if (to.params.namespace && to.params.project) {
store.dispatch('getProjectData', {
store
.dispatch('getProjectData', {
namespace: to.params.namespace,
projectId: to.params.project,
})
......@@ -67,26 +68,45 @@ router.beforeEach((to, from, next) => {
branchId: to.params.branch,
});
store.dispatch('getFiles', {
store
.dispatch('getFiles', {
projectId: fullProjectId,
branchId: to.params.branch,
})
.then(() => {
if (to.params[0]) {
const treeEntry = store.state.entries[to.params[0]];
const path =
to.params[0].slice(-1) === '/'
? to.params[0].slice(0, -1)
: to.params[0];
const treeEntry = store.state.entries[path];
if (treeEntry) {
store.dispatch('handleTreeEntryAction', treeEntry);
}
}
})
.catch((e) => {
flash('Error while loading the branch files. Please try again.', 'alert', document, null, false, true);
.catch(e => {
flash(
'Error while loading the branch files. Please try again.',
'alert',
document,
null,
false,
true,
);
throw e;
});
}
})
.catch((e) => {
flash('Error while loading the project data. Please try again.', 'alert', document, null, false, true);
.catch(e => {
flash(
'Error while loading the project data. Please try again.',
'alert',
document,
null,
false,
true,
);
throw e;
});
}
......
import {
decorateData,
sortTree,
} from '../utils';
import { decorateData, sortTree } from '../utils';
self.addEventListener('message', (e) => {
const { data, projectId, branchId, tempFile = false, content = '', base64 = false } = e.data;
self.addEventListener('message', e => {
const {
data,
projectId,
branchId,
tempFile = false,
content = '',
base64 = false,
} = e.data;
const treeList = [];
let file;
......@@ -15,7 +19,9 @@ self.addEventListener('message', (e) => {
if (pathSplit.length > 0) {
pathSplit.reduce((pathAcc, folderName) => {
const parentFolder = acc[pathAcc[pathAcc.length - 1]];
const folderPath = `${(parentFolder ? `${parentFolder.path}/` : '')}${folderName}`;
const folderPath = `${
parentFolder ? `${parentFolder.path}/` : ''
}${folderName}`;
const foundEntry = acc[folderPath];
if (!foundEntry) {
......@@ -25,9 +31,11 @@ self.addEventListener('message', (e) => {
id: folderPath,
name: folderName,
path: folderPath,
url: `/${projectId}/tree/${branchId}/${folderPath}`,
url: `/${projectId}/tree/${branchId}/${folderPath}/`,
type: 'tree',
parentTreeUrl: parentFolder ? parentFolder.url : `/${projectId}/tree/${branchId}/`,
parentTreeUrl: parentFolder
? parentFolder.url
: `/${projectId}/tree/${branchId}/`,
tempFile,
changed: tempFile,
opened: tempFile,
......@@ -62,7 +70,9 @@ self.addEventListener('message', (e) => {
path,
url: `/${projectId}/blob/${branchId}/${path}`,
type: 'blob',
parentTreeUrl: fileFolder ? fileFolder.url : `/${projectId}/blob/${branchId}`,
parentTreeUrl: fileFolder
? fileFolder.url
: `/${projectId}/blob/${branchId}`,
tempFile,
changed: tempFile,
content,
......
......@@ -1727,6 +1727,7 @@ export default class Notes {
// Get Form metadata
const $submitBtn = $(e.target);
$submitBtn.prop('disabled', true);
let $form = $submitBtn.parents('form');
const $closeBtn = $form.find('.js-note-target-close');
const isDiscussionNote =
......@@ -1761,7 +1762,6 @@ export default class Notes {
// If comment is to resolve discussion, disable submit buttons while
// comment posting is finished.
if (isDiscussionResolve) {
$submitBtn.disable();
$form.find('.js-comment-submit-button').disable();
}
......@@ -1816,6 +1816,7 @@ export default class Notes {
.then(res => {
const note = res.data;
$submitBtn.prop('disabled', false);
// Submission successful! remove placeholder
$notesContainer.find(`#${noteUniqueId}`).remove();
......@@ -1899,7 +1900,7 @@ export default class Notes {
.catch(() => {
// Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove();
$submitBtn.prop('disabled', false);
const blurEvent = new CustomEvent('blur.imageDiff', {
detail: e,
});
......
......@@ -27,12 +27,21 @@ export default {
required: true,
},
},
computed: {
metricDetails() {
return this.currentRequest.details[this.metric];
},
detailsList() {
return this.metricDetails[this.details];
},
},
};
</script>
<template>
<div
:id="`peek-view-${metric}`"
class="view"
v-if="currentRequest.details"
>
<button
:data-target="`#modal-peek-${metric}-details`"
......@@ -40,24 +49,21 @@ export default {
type="button"
data-toggle="modal"
>
<span
v-if="currentRequest.details"
class="bold"
>
{{ currentRequest.details[metric].duration }}
{{ metricDetails.duration }}
/
{{ currentRequest.details[metric].calls }}
</span>
{{ metricDetails.calls }}
</button>
<gl-modal
v-if="currentRequest.details"
:id="`modal-peek-${metric}-details`"
:header-title-text="header"
class="performance-bar-modal"
>
<table class="table">
<table
class="table"
>
<template v-if="detailsList.length">
<tr
v-for="(item, index) in currentRequest.details[metric][details]"
v-for="(item, index) in detailsList"
:key="index"
>
<td><strong>{{ item.duration }}ms</strong></td>
......@@ -69,6 +75,14 @@ export default {
{{ item[key] }}
</td>
</tr>
</template>
<template v-else>
<tr>
<td>
No {{ header.toLowerCase() }} for this request.
</td>
</tr>
</template>
</table>
<div slot="footer">
......
......@@ -113,27 +113,21 @@ export default {
id="js-peek"
:class="env"
>
<request-selector
<div
v-if="currentRequest"
:current-request="currentRequest"
:requests="requests"
@change-current-request="changeCurrentRequest"
/>
class="container-fluid container-limited"
>
<div
id="peek-view-host"
class="view prepend-left-5"
class="view"
>
<span
v-if="currentRequest && currentRequest.details"
v-if="currentRequest.details"
class="current-host"
>
{{ currentRequest.details.host.hostname }}
</span>
</div>
<div
v-if="currentRequest"
class="wrapper"
>
<upstream-performance-bar
v-if="initialRequest && currentRequest.details"
/>
......@@ -186,6 +180,12 @@ export default {
gc
</span>
</div>
<request-selector
v-if="currentRequest"
:current-request="currentRequest"
:requests="requests"
@change-current-request="changeCurrentRequest"
/>
</div>
</div>
</template>
......@@ -37,7 +37,7 @@ export default {
<template>
<div
id="peek-request-selector"
class="append-right-5 pull-right"
class="pull-right"
>
<select v-model="currentRequestId">
<option
......
......@@ -5,6 +5,8 @@ export default {
.getElementById('peek-view-performance-bar')
.cloneNode(true);
upstreamPerformanceBar.classList.remove('hidden');
this.$refs.wrapper.appendChild(upstreamPerformanceBar);
},
};
......
......@@ -4,9 +4,9 @@ import Vue from 'vue';
import performanceBarApp from './components/performance_bar_app.vue';
import PerformanceBarStore from './stores/performance_bar_store';
export default () =>
export default ({ container }) =>
new Vue({
el: '#js-peek',
el: container,
components: {
performanceBarApp,
},
......
import stopwatchSvg from 'icons/_icon_stopwatch.svg';
import { abbreviateTime } from '../../../lib/utils/pretty_time';
export default {
name: 'time-tracking-collapsed-state',
props: {
showComparisonState: {
type: Boolean,
required: true,
},
showSpentOnlyState: {
type: Boolean,
required: true,
},
showEstimateOnlyState: {
type: Boolean,
required: true,
},
showNoTimeTrackingState: {
type: Boolean,
required: true,
},
timeSpentHumanReadable: {
type: String,
required: false,
default: '',
},
timeEstimateHumanReadable: {
type: String,
required: false,
default: '',
},
},
computed: {
timeSpent() {
return this.abbreviateTime(this.timeSpentHumanReadable);
},
timeEstimate() {
return this.abbreviateTime(this.timeEstimateHumanReadable);
},
divClass() {
if (this.showComparisonState) {
return 'compare';
} else if (this.showEstimateOnlyState) {
return 'estimate-only';
} else if (this.showSpentOnlyState) {
return 'spend-only';
} else if (this.showNoTimeTrackingState) {
return 'no-tracking';
}
return '';
},
spanClass() {
if (this.showComparisonState) {
return '';
} else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
return 'bold';
} else if (this.showNoTimeTrackingState) {
return 'no-value';
}
return '';
},
text() {
if (this.showComparisonState) {
return `${this.timeSpent} / ${this.timeEstimate}`;
} else if (this.showEstimateOnlyState) {
return `-- / ${this.timeEstimate}`;
} else if (this.showSpentOnlyState) {
return `${this.timeSpent} / --`;
} else if (this.showNoTimeTrackingState) {
return 'None';
}
return '';
},
},
methods: {
abbreviateTime(timeStr) {
return abbreviateTime(timeStr);
},
},
template: `
<div class="sidebar-collapsed-icon">
${stopwatchSvg}
<div class="time-tracking-collapsed-summary">
<div :class="divClass">
<span :class="spanClass">
{{ text }}
</span>
</div>
</div>
</div>
`,
};
<script>
import icon from '../../../vue_shared/components/icon.vue';
import { abbreviateTime } from '../../../lib/utils/pretty_time';
export default {
name: 'TimeTrackingCollapsedState',
components: {
icon,
},
props: {
showComparisonState: {
type: Boolean,
required: true,
},
showSpentOnlyState: {
type: Boolean,
required: true,
},
showEstimateOnlyState: {
type: Boolean,
required: true,
},
showNoTimeTrackingState: {
type: Boolean,
required: true,
},
timeSpentHumanReadable: {
type: String,
required: false,
default: '',
},
timeEstimateHumanReadable: {
type: String,
required: false,
default: '',
},
},
computed: {
timeSpent() {
return this.abbreviateTime(this.timeSpentHumanReadable);
},
timeEstimate() {
return this.abbreviateTime(this.timeEstimateHumanReadable);
},
divClass() {
if (this.showComparisonState) {
return 'compare';
} else if (this.showEstimateOnlyState) {
return 'estimate-only';
} else if (this.showSpentOnlyState) {
return 'spend-only';
} else if (this.showNoTimeTrackingState) {
return 'no-tracking';
}
return '';
},
spanClass() {
if (this.showComparisonState) {
return '';
} else if (this.showEstimateOnlyState || this.showSpentOnlyState) {
return 'bold';
} else if (this.showNoTimeTrackingState) {
return 'no-value';
}
return '';
},
text() {
if (this.showComparisonState) {
return `${this.timeSpent} / ${this.timeEstimate}`;
} else if (this.showEstimateOnlyState) {
return `-- / ${this.timeEstimate}`;
} else if (this.showSpentOnlyState) {
return `${this.timeSpent} / --`;
} else if (this.showNoTimeTrackingState) {
return 'None';
}
return '';
},
},
methods: {
abbreviateTime(timeStr) {
return abbreviateTime(timeStr);
},
},
};
</script>
<template>
<div class="sidebar-collapsed-icon">
<icon name="timer" />
<div class="time-tracking-collapsed-summary">
<div :class="divClass">
<span :class="spanClass">
{{ text }}
</span>
</div>
</div>
</div>
</template>
<script>
import timeTrackingHelpState from './help_state';
import timeTrackingCollapsedState from './collapsed_state';
import TimeTrackingCollapsedState from './collapsed_state.vue';
import timeTrackingSpentOnlyPane from './spent_only_pane';
import timeTrackingNoTrackingPane from './no_tracking_pane';
import timeTrackingEstimateOnlyPane from './estimate_only_pane';
......@@ -11,7 +11,7 @@ import eventHub from '../../event_hub';
export default {
name: 'IssuableTimeTracker',
components: {
'time-tracking-collapsed-state': timeTrackingCollapsedState,
TimeTrackingCollapsedState,
'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane,
'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane,
......
......@@ -62,8 +62,7 @@
return `${gon.sprite_file_icons}#${iconName}`;
},
folderIconName() {
// We don't have a open folder icon yet
return this.opened ? 'folder' : 'folder';
return this.opened ? 'folder-open' : 'folder';
},
iconSizeClass() {
return this.size ? `s${this.size}` : '';
......
......@@ -43,12 +43,6 @@
}
}
.wrapper {
width: 80%;
height: $performance-bar-height;
margin: 0 auto;
}
// UI Elements
.bucket {
background: $perf-bar-bucket-bg;
......
......@@ -377,4 +377,11 @@ module IssuablesHelper
def parent
@project || @group
end
def issuable_milestone_tooltip_title(issuable)
if issuable.milestone
milestone_tooltip = milestone_tooltip_title(issuable.milestone)
_('Milestone') + (milestone_tooltip ? ': ' + milestone_tooltip : '')
end
end
end
......@@ -230,13 +230,13 @@ class Group < Namespace
end
GroupMember
.active_without_invites
.active_without_invites_and_requests
.where(source_id: source_ids)
end
def members_with_descendants
GroupMember
.active_without_invites
.active_without_invites_and_requests
.where(source_id: self_and_descendants.reorder(nil).select(:id))
end
......
......@@ -52,7 +52,7 @@ class Member < ActiveRecord::Base
end
# Like active, but without invites. For when a User is required.
scope :active_without_invites, -> do
scope :active_without_invites_and_requests, -> do
left_join_users
.where(users: { state: 'active' })
.non_request
......
......@@ -208,9 +208,9 @@ class NotificationService
def new_access_request(member)
return true unless member.notifiable?(:subscription)
recipients = member.source.members.active_without_invites.owners_and_masters
recipients = member.source.members.active_without_invites_and_requests.owners_and_masters
if fallback_to_group_owners_masters?(recipients, member)
recipients = member.source.group.members.active_without_invites.owners_and_masters
recipients = member.source.group.members.active_without_invites_and_requests.owners_and_masters
end
recipients.each { |recipient| deliver_access_request_email(recipient, member) }
......
......@@ -67,12 +67,8 @@
%td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" }
%img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/
%div
%a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications
&middot;
%a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help
%div
You're receiving this email because of your account on
= succeed "." do
%a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host
- manage_notifications_link = link_to(_("Manage all notifications"), profile_notifications_url, style: "color:#3777b0;text-decoration:none;")
- help_link = link_to(_("Help"), help_url, style: "color:#3777b0;text-decoration:none;")
= _("You're receiving this email because of your account on %{host}. %{manage_notifications_link} &middot; %{help_link}").html_safe % { host: Gitlab.config.gitlab.host, manage_notifications_link: manage_notifications_link, help_link: help_link }
= yield :additional_footer
......@@ -6,7 +6,7 @@
profile_url: url_for(params.merge(lineprofiler: 'true')) },
class: Peek.env }
#peek-view-performance-bar
#peek-view-performance-bar.hidden
= render_server_response_time
%span#serverstats
%ul.performance-bar
......@@ -7,6 +7,8 @@
.issue-main-info
.issue-title.title
%span.issue-title-text
- if issue.confidential?
%span.has-tooltip{ title: _('Confidential') }
= confidential_icon(issue)
= link_to issue.title, issue_path(issue)
- if issue.tasks?
......@@ -24,11 +26,11 @@
- if issue.milestone
%span.issuable-milestone.hidden-xs
&nbsp;
= link_to project_issues_path(issue.project, milestone_title: issue.milestone.title), data: { html: 1, toggle: 'tooltip', title: milestone_tooltip_title(issue.milestone) } do
= link_to project_issues_path(issue.project, milestone_title: issue.milestone.title), data: { html: 1, toggle: 'tooltip', title: issuable_milestone_tooltip_title(issue) } do
= icon('clock-o')
= issue.milestone.title
- if issue.due_date
%span.issuable-due-date.hidden-xs{ class: "#{'cred' if issue.overdue?}" }
%span.issuable-due-date.hidden-xs.has-tooltip{ class: "#{'cred' if issue.overdue?}", title: _('Due date') }
&nbsp;
= icon('calendar')
= issue.due_date.to_s(:medium)
......
......@@ -23,11 +23,11 @@
- if merge_request.milestone
%span.issuable-milestone.hidden-xs
&nbsp;
= link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title), data: { html: 1, toggle: 'tooltip', title: milestone_tooltip_title(merge_request.milestone) } do
= link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title), data: { html: 1, toggle: 'tooltip', title: issuable_milestone_tooltip_title(merge_request) } do
= icon('clock-o')
= merge_request.milestone.title
- if merge_request.target_project.default_branch != merge_request.target_branch
%span.project-ref-path
%span.project-ref-path.has-tooltip{ title: _('Target branch') }
&nbsp;
= link_to project_ref_path(merge_request.project, merge_request.target_branch), class: 'ref-name' do
= sprite_icon('fork', size: 12, css_class: 'fork-sprite')
......@@ -51,11 +51,11 @@
= render_pipeline_status(merge_request.head_pipeline)
- if merge_request.open? && merge_request.broken?
%li.issuable-pipeline-broken.hidden-xs
= link_to merge_request_path(merge_request), class: "has-tooltip", title: "Cannot be merged automatically", data: { container: 'body' } do
= link_to merge_request_path(merge_request), class: "has-tooltip", title: _('Cannot be merged automatically') do
= icon('exclamation-triangle')
- if merge_request.assignee
%li
= link_to_member(merge_request.source_project, merge_request.assignee, name: false, title: "Assigned to :name")
= link_to_member(merge_request.source_project, merge_request.assignee, name: false, title: _('Assigned to :name'))
= render 'shared/issuable_meta_data', issuable: merge_request
......
......@@ -77,7 +77,7 @@
= render 'projects/find_file_link'
= succeed " " do
= link_to ide_edit_path(@project, @id), class: 'btn btn-default' do
= link_to ide_edit_path(@project, @id, ""), class: 'btn btn-default' do
= _('Web IDE')
= render 'projects/buttons/download', project: @project, ref: @ref
......@@ -5,21 +5,21 @@
- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count
- if issuable_mr > 0
%li.issuable-mr.hidden-xs
%li.issuable-mr.hidden-xs.has-tooltip{ title: _('Related merge requests') }
= image_tag('icon-merge-request-unmerged.svg', class: 'icon-merge-request-unmerged')
= issuable_mr
- if upvotes > 0
%li.issuable-upvotes.hidden-xs
%li.issuable-upvotes.hidden-xs.has-tooltip{ title: _('Upvotes') }
= icon('thumbs-up')
= upvotes
- if downvotes > 0
%li.issuable-downvotes.hidden-xs
%li.issuable-downvotes.hidden-xs.has-tooltip{ title: _('Downvotes') }
= icon('thumbs-down')
= downvotes
%li.issuable-comments.hidden-xs
= link_to issuable_url, class: ('no-comments' if note_count.zero?) do
= link_to issuable_url, class: ['has-tooltip', ('no-comments' if note_count.zero?)], title: _('Comments') do
= icon('comments')
= note_count
......@@ -4,7 +4,7 @@
%header.board-header{ ":class" => '{ "has-border": list.label && list.label.color }', ":style" => "{ borderTopColor: (list.label && list.label.color ? list.label.color : null) }", "@click" => "toggleExpanded($event)" }
%h3.board-title.js-board-handle{ ":class" => '{ "user-can-drag": (!disabled && !list.preset) }' }
%i.fa.fa-fw.board-title-expandable-toggle{ "v-if": "list.isExpandable",
":class": "{ \"fa-caret-down\": list.isExpanded, \"fa-caret-right\": !list.isExpanded && list.position === -1, \"fa-caret-left\": !list.isExpanded && list.position !== -1 }",
":class": "{ \"fa-caret-down\": list.isExpanded, \"fa-caret-right\": !list.isExpanded }",
"aria-hidden": "true" }
%span.board-title-text.has-tooltip{ "v-if": "list.type !== \"label\"",
......
---
title: Add missing pagination on the commit diff endpoint
merge_request: 17203
author: Maxime Roussin-Bélanger
type: fixed
---
title: Moved o_auth/saml/ldap modules under gitlab/auth
merge_request: 17359
author: Horatiu Eugen Vlad
---
title: Update issue closing pattern to allow variations in punctuation
merge_request: 17198
author: Vicky Chijwani
type: changed
---
title: Clear the Labels dropdown search filter after a selection is made
merge_request: 17393
author: Andrew Torres
type: changed
---
title: Update to github-linguist 5.3.x
merge_request: 17241
author: Ken Ding
type: other
---
title: Group MRs on issue page by project and namespace.
merge_request: 8494
author: Jeff Stubler
---
title: Add project export API
merge_request: 15860
author: Travis Miller
type: added
---
title: Add verification for GitLab Pages custom domains
merge_request:
author:
type: security
---
title: Add email button to new issue by email
merge_request: 10942
author: Islam Wazery
---
title: Fix duplicate system notes when merging a merge request.
merge_request: 17035
author:
type: fixed
---
title: Allow installation of GitLab Runner with a single click
merge_request: 17134
author:
type: added
---
title: Fix Slack/Mattermost notifications not respecting `notify_only_default_branch` setting for pushes
merge_request: 17345
author:
type: fixed
---
title: remove avater underline
merge_request: 17219
author: Ken Ding
type: fixed
---
title: Fix Teleporting Emoji
merge_request: 16963
author: Jared Deckard <jared.deckard@gmail.com>
type: fixed
---
title: update toml-rb to 1.0.0
merge_request: 17259
author: Ken Ding
type: other
---
title: Display a link to external issue tracker when enabled
merge_request:
author:
type: changed
---
title: Handle empty state in Pipelines page
merge_request:
author:
type: fixed
---
title: Set margins around dropdown dividers to 4px
merge_request: 17517
author:
type: fixed
---
title: "Fix user avatar's vertical align on the issues and merge requests pages"
merge_request: 17072
author: Laszlo Karpati
type: fixed
---
title: Add overview of branches and a filter for active/stale branches
merge_request: 15402
author: Takuya Noguchi
type: added
---
title: Improve database response time for user activity listing.
merge_request: 17454
author:
type: performance
---
title: Sanitize extra blank spaces used when uploading a SSH key
merge_request: 40552
author:
type: fixed
title: Fix 404 when listing archived projects in a group where all projects have been archived
merge_request: 17077
author: Ashley Dumaine
type: fixed
---
title: Fix get a single pages domain when project path contains a period
merge_request: 17206
author: Travis Miller
type: fixed
---
title: 'Expose GITLAB_FEATURES as CI/CD variable (fixes #40994)'
merge_request:
author:
type: added
---
title: Adds updated_at filter to issues and merge_requests API
merge_request: 17417
author: Jacopo Beschi @jacopo-beschi
type: added
---
title: Render htmlentities correctly for links not supported by Rinku
merge_request:
author:
type: fixed
---
title: Include cycle time in usage ping data
merge_request: 16973
author:
type: added
---
title: Enables eslint in codeclimate job
merge_request: 17392
author:
type: other
---
title: API endpoint for importing a project export
merge_request: 17025
author:
type: added
---
title: expose more metrics in merge requests api
merge_request: 16589
author: haseebeqx
type: added
---
title: Remember assignee when moving an issue
merge_request:
author:
type: fixed
---
title: Add a button to deploy a runner to a Kubernetes cluster in the settings page
merge_request: 17278
author:
type: changed
---
title: Fix long list of recipients on group request membership email
merge_request: 17121
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Render modified icon for moved file in changes dropdown
merge_request:
author:
type: fixed
---
title: Fix 500 error being shown when diff has context marker with invalid encoding
merge_request:
author:
type: fixed
---
title: Add a button on the project page to set up a Kubernetes cluster and enable
Auto DevOps
merge_request: 16900
author:
type: added
---
title: Allow commits endpoint to work over all commits of a repository
merge_request: 17182
author:
type: added
---
title: Remove user notification settings for groups and projects when user leaves
merge_request: 16906
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Allow to call PUT /projects/:id API with only ci_config_path specified
merge_request: 17105
author: Laszlo Karpati
type: fixed
---
title: Allows the usage of /milestone quick action for group milestones
merge_request: 17239
author: Jacopo Beschi @jacopo-beschi
type: fixed
---
title: Display ingress IP address in the Kubernetes page
merge_request: 17052
author:
type: added
---
title: Add search param to Branches API
merge_request: 17005
author: bunufi
type: added
---
title: Use a user object in ApplicationHelper#avatar_icon where possible to avoid
N+1 queries.
merge_request: 42800
author:
type: performance
---
title: Fix "Remove source branch" button in Merge request widget during merge when pipeline
succeeds state
merge_request: 17192
author:
type: fixed
---
title: CI charts now include the current day
merge_request: 17032
author: Dakkaron
type: changed
---
title: Adds tooltip in environment names to increase readability
merge_request:
author:
type: fixed
---
title: Fix close button on issues not working on mobile
merge_request:
author:
type: fixed
---
title: Hide CI secret variable values after saving
merge_request: 17044
author:
type: changed
---
title: Update tooltip on pipeline cancel to Stop (#42946)
merge_request: 17444
author:
type: fixed
---
title: Improve performance of pipeline page by reducing DB queries
merge_request: 17168
author:
type: performance
---
title: Fix settings panels not expanding when fragment hash linked
merge_request: 17074
author:
type: fixed
---
title: Allows project rename after validation error
merge_request: 17150
author:
type: fixed
---
title: Keep "Import project" tab/form active when validation fails trying to import
"Repo by URL"
merge_request: 17136
author:
type: fixed
---
title: Remove duplicated error message on duplicate variable validation
merge_request: 17135
author:
type: fixed
---
title: Fixes gpg popover layout
merge_request: 17323
author:
type: fixed
---
title: Fix quick actions for users who cannot update issues and merge requests
merge_request: 17482
author:
type: fixed
---
title: Keep track of projects a user interacted with.
merge_request: 17327
author:
type: other
---
title: Display Runner IP Address
merge_request: 17286
author:
type: added
---
title: Do not persist Google Project verification flash errors after a page reload
merge_request: 17299
author:
type: fixed
---
title: Fix Group labels load failure when there are duplicate labels present
merge_request: 17353
author:
type: fixed
---
title: Enable filtering MR list based on clicked label in MR sidebar
merge_request: 17390
author:
type: fixed
---
title: Add a paragraph about security implications on Cluster's page
merge_request: 17486
author:
type: added
---
title: Add tooltips to icons in lists of issues and merge requests
merge_request: 17700
author:
type: changed
---
title: Enable privileged mode for GitLab Runner
merge_request: 17528
author:
type: added
---
title: Ensure foreign keys on clusters applications
merge_request: 17488
author:
type: other
---
title: Update SSH key link to include existing keys
merge_request:
author: Brendan O'Leary
type: changed
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