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' source 'https://rubygems.org'
gem 'rails', '4.2.10' gem 'rails', gem_versions['rails']
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with # Responders respond_to and respond_with
...@@ -9,7 +22,7 @@ gem 'responders', '~> 2.0' ...@@ -9,7 +22,7 @@ gem 'responders', '~> 2.0'
gem 'sprockets', '~> 3.7.0' gem 'sprockets', '~> 3.7.0'
# Default values for AR models # Default values for AR models
gem 'default_value_for', '~> 3.0.0' gem 'default_value_for', gem_versions['default_value_for']
# Supported DBs # Supported DBs
gem 'mysql2', '~> 0.4.10', group: :mysql gem 'mysql2', '~> 0.4.10', group: :mysql
...@@ -24,7 +37,7 @@ gem 'faraday', '~> 0.12' ...@@ -24,7 +37,7 @@ gem 'faraday', '~> 0.12'
gem 'devise', '~> 4.2' gem 'devise', '~> 4.2'
gem 'doorkeeper', '~> 4.3' gem 'doorkeeper', '~> 4.3'
gem 'doorkeeper-openid_connect', '~> 1.3' gem 'doorkeeper-openid_connect', '~> 1.3'
gem 'omniauth', '~> 1.4.2' gem 'omniauth', '~> 1.8'
gem 'omniauth-auth0', '~> 1.4.1' gem 'omniauth-auth0', '~> 1.4.1'
gem 'omniauth-azure-oauth2', '~> 0.0.9' gem 'omniauth-azure-oauth2', '~> 0.0.9'
gem 'omniauth-cas3', '~> 1.1.4' gem 'omniauth-cas3', '~> 1.1.4'
...@@ -122,7 +135,7 @@ gem 'unf', '~> 0.1.4' ...@@ -122,7 +135,7 @@ gem 'unf', '~> 0.1.4'
gem 'seed-fu', '~> 2.3.7' gem 'seed-fu', '~> 2.3.7'
# Markdown and HTML processing # 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 'deckar01-task_list', '2.0.0'
gem 'gitlab-markup', '~> 1.6.2' gem 'gitlab-markup', '~> 1.6.2'
gem 'redcarpet', '~> 3.4' gem 'redcarpet', '~> 3.4'
...@@ -266,7 +279,7 @@ gem 'premailer-rails', '~> 1.9.7' ...@@ -266,7 +279,7 @@ gem 'premailer-rails', '~> 1.9.7'
# I18n # I18n
gem 'ruby_parser', '~> 3.8', require: false 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', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.3' gem 'gettext_i18n_rails_js', '~> 1.3'
gem 'gettext', '~> 3.2.2', require: false, group: :development gem 'gettext', '~> 3.2.2', require: false, group: :development
...@@ -357,7 +370,7 @@ group :development, :test do ...@@ -357,7 +370,7 @@ group :development, :test do
gem 'license_finder', '~> 3.1', require: false gem 'license_finder', '~> 3.1', require: false
gem 'knapsack', '~> 1.16' 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 gem 'stackprof', '~> 0.2.10', require: false
......
...@@ -524,8 +524,8 @@ GEM ...@@ -524,8 +524,8 @@ GEM
rack (>= 1.2, < 3) rack (>= 1.2, < 3)
octokit (4.8.0) octokit (4.8.0)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
omniauth (1.4.3) omniauth (1.8.1)
hashie (>= 1.2, < 4) hashie (>= 3.4.6, < 3.6.0)
rack (>= 1.6.2, < 3) rack (>= 1.6.2, < 3)
omniauth-auth0 (1.4.1) omniauth-auth0 (1.4.1)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
...@@ -1104,7 +1104,7 @@ DEPENDENCIES ...@@ -1104,7 +1104,7 @@ DEPENDENCIES
nokogiri (~> 1.8.2) nokogiri (~> 1.8.2)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.8) octokit (~> 4.8)
omniauth (~> 1.4.2) omniauth (~> 1.8)
omniauth-auth0 (~> 1.4.1) omniauth-auth0 (~> 1.4.1)
omniauth-authentiq (~> 0.3.1) omniauth-authentiq (~> 0.3.1)
omniauth-azure-oauth2 (~> 0.0.9) 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 @@ ...@@ -4,4 +4,3 @@
# #
web: RAILS_ENV=development bin/web start_foreground web: RAILS_ENV=development bin/web start_foreground
worker: RAILS_ENV=development bin/background_jobs 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 { ...@@ -43,6 +43,7 @@ export default {
'file-open': this.isBlob && this.file.opened, 'file-open': this.isBlob && this.file.opened,
'file-active': this.isBlob && this.file.active, 'file-active': this.isBlob && this.file.active,
folder: this.isTree, folder: this.isTree,
'is-open': this.file.opened,
}; };
}, },
}, },
......
...@@ -54,7 +54,8 @@ const router = new VueRouter({ ...@@ -54,7 +54,8 @@ const router = new VueRouter({
router.beforeEach((to, from, next) => { router.beforeEach((to, from, next) => {
if (to.params.namespace && to.params.project) { if (to.params.namespace && to.params.project) {
store.dispatch('getProjectData', { store
.dispatch('getProjectData', {
namespace: to.params.namespace, namespace: to.params.namespace,
projectId: to.params.project, projectId: to.params.project,
}) })
...@@ -67,26 +68,45 @@ router.beforeEach((to, from, next) => { ...@@ -67,26 +68,45 @@ router.beforeEach((to, from, next) => {
branchId: to.params.branch, branchId: to.params.branch,
}); });
store.dispatch('getFiles', { store
.dispatch('getFiles', {
projectId: fullProjectId, projectId: fullProjectId,
branchId: to.params.branch, branchId: to.params.branch,
}) })
.then(() => { .then(() => {
if (to.params[0]) { 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) { if (treeEntry) {
store.dispatch('handleTreeEntryAction', treeEntry); store.dispatch('handleTreeEntryAction', treeEntry);
} }
} }
}) })
.catch((e) => { .catch(e => {
flash('Error while loading the branch files. Please try again.', 'alert', document, null, false, true); flash(
'Error while loading the branch files. Please try again.',
'alert',
document,
null,
false,
true,
);
throw e; throw e;
}); });
} }
}) })
.catch((e) => { .catch(e => {
flash('Error while loading the project data. Please try again.', 'alert', document, null, false, true); flash(
'Error while loading the project data. Please try again.',
'alert',
document,
null,
false,
true,
);
throw e; throw e;
}); });
} }
......
import { import { decorateData, sortTree } from '../utils';
decorateData,
sortTree,
} from '../utils';
self.addEventListener('message', (e) => { self.addEventListener('message', e => {
const { data, projectId, branchId, tempFile = false, content = '', base64 = false } = e.data; const {
data,
projectId,
branchId,
tempFile = false,
content = '',
base64 = false,
} = e.data;
const treeList = []; const treeList = [];
let file; let file;
...@@ -15,7 +19,9 @@ self.addEventListener('message', (e) => { ...@@ -15,7 +19,9 @@ self.addEventListener('message', (e) => {
if (pathSplit.length > 0) { if (pathSplit.length > 0) {
pathSplit.reduce((pathAcc, folderName) => { pathSplit.reduce((pathAcc, folderName) => {
const parentFolder = acc[pathAcc[pathAcc.length - 1]]; const parentFolder = acc[pathAcc[pathAcc.length - 1]];
const folderPath = `${(parentFolder ? `${parentFolder.path}/` : '')}${folderName}`; const folderPath = `${
parentFolder ? `${parentFolder.path}/` : ''
}${folderName}`;
const foundEntry = acc[folderPath]; const foundEntry = acc[folderPath];
if (!foundEntry) { if (!foundEntry) {
...@@ -25,9 +31,11 @@ self.addEventListener('message', (e) => { ...@@ -25,9 +31,11 @@ self.addEventListener('message', (e) => {
id: folderPath, id: folderPath,
name: folderName, name: folderName,
path: folderPath, path: folderPath,
url: `/${projectId}/tree/${branchId}/${folderPath}`, url: `/${projectId}/tree/${branchId}/${folderPath}/`,
type: 'tree', type: 'tree',
parentTreeUrl: parentFolder ? parentFolder.url : `/${projectId}/tree/${branchId}/`, parentTreeUrl: parentFolder
? parentFolder.url
: `/${projectId}/tree/${branchId}/`,
tempFile, tempFile,
changed: tempFile, changed: tempFile,
opened: tempFile, opened: tempFile,
...@@ -62,7 +70,9 @@ self.addEventListener('message', (e) => { ...@@ -62,7 +70,9 @@ self.addEventListener('message', (e) => {
path, path,
url: `/${projectId}/blob/${branchId}/${path}`, url: `/${projectId}/blob/${branchId}/${path}`,
type: 'blob', type: 'blob',
parentTreeUrl: fileFolder ? fileFolder.url : `/${projectId}/blob/${branchId}`, parentTreeUrl: fileFolder
? fileFolder.url
: `/${projectId}/blob/${branchId}`,
tempFile, tempFile,
changed: tempFile, changed: tempFile,
content, content,
......
...@@ -1727,6 +1727,7 @@ export default class Notes { ...@@ -1727,6 +1727,7 @@ export default class Notes {
// Get Form metadata // Get Form metadata
const $submitBtn = $(e.target); const $submitBtn = $(e.target);
$submitBtn.prop('disabled', true);
let $form = $submitBtn.parents('form'); let $form = $submitBtn.parents('form');
const $closeBtn = $form.find('.js-note-target-close'); const $closeBtn = $form.find('.js-note-target-close');
const isDiscussionNote = const isDiscussionNote =
...@@ -1761,7 +1762,6 @@ export default class Notes { ...@@ -1761,7 +1762,6 @@ export default class Notes {
// If comment is to resolve discussion, disable submit buttons while // If comment is to resolve discussion, disable submit buttons while
// comment posting is finished. // comment posting is finished.
if (isDiscussionResolve) { if (isDiscussionResolve) {
$submitBtn.disable();
$form.find('.js-comment-submit-button').disable(); $form.find('.js-comment-submit-button').disable();
} }
...@@ -1816,6 +1816,7 @@ export default class Notes { ...@@ -1816,6 +1816,7 @@ export default class Notes {
.then(res => { .then(res => {
const note = res.data; const note = res.data;
$submitBtn.prop('disabled', false);
// Submission successful! remove placeholder // Submission successful! remove placeholder
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
...@@ -1899,7 +1900,7 @@ export default class Notes { ...@@ -1899,7 +1900,7 @@ export default class Notes {
.catch(() => { .catch(() => {
// Submission failed, remove placeholder note and show Flash error message // Submission failed, remove placeholder note and show Flash error message
$notesContainer.find(`#${noteUniqueId}`).remove(); $notesContainer.find(`#${noteUniqueId}`).remove();
$submitBtn.prop('disabled', false);
const blurEvent = new CustomEvent('blur.imageDiff', { const blurEvent = new CustomEvent('blur.imageDiff', {
detail: e, detail: e,
}); });
......
...@@ -27,12 +27,21 @@ export default { ...@@ -27,12 +27,21 @@ export default {
required: true, required: true,
}, },
}, },
computed: {
metricDetails() {
return this.currentRequest.details[this.metric];
},
detailsList() {
return this.metricDetails[this.details];
},
},
}; };
</script> </script>
<template> <template>
<div <div
:id="`peek-view-${metric}`" :id="`peek-view-${metric}`"
class="view" class="view"
v-if="currentRequest.details"
> >
<button <button
:data-target="`#modal-peek-${metric}-details`" :data-target="`#modal-peek-${metric}-details`"
...@@ -40,24 +49,21 @@ export default { ...@@ -40,24 +49,21 @@ export default {
type="button" type="button"
data-toggle="modal" data-toggle="modal"
> >
<span {{ metricDetails.duration }}
v-if="currentRequest.details"
class="bold"
>
{{ currentRequest.details[metric].duration }}
/ /
{{ currentRequest.details[metric].calls }} {{ metricDetails.calls }}
</span>
</button> </button>
<gl-modal <gl-modal
v-if="currentRequest.details"
:id="`modal-peek-${metric}-details`" :id="`modal-peek-${metric}-details`"
:header-title-text="header" :header-title-text="header"
class="performance-bar-modal" class="performance-bar-modal"
> >
<table class="table"> <table
class="table"
>
<template v-if="detailsList.length">
<tr <tr
v-for="(item, index) in currentRequest.details[metric][details]" v-for="(item, index) in detailsList"
:key="index" :key="index"
> >
<td><strong>{{ item.duration }}ms</strong></td> <td><strong>{{ item.duration }}ms</strong></td>
...@@ -69,6 +75,14 @@ export default { ...@@ -69,6 +75,14 @@ export default {
{{ item[key] }} {{ item[key] }}
</td> </td>
</tr> </tr>
</template>
<template v-else>
<tr>
<td>
No {{ header.toLowerCase() }} for this request.
</td>
</tr>
</template>
</table> </table>
<div slot="footer"> <div slot="footer">
......
...@@ -113,27 +113,21 @@ export default { ...@@ -113,27 +113,21 @@ export default {
id="js-peek" id="js-peek"
:class="env" :class="env"
> >
<request-selector <div
v-if="currentRequest" v-if="currentRequest"
:current-request="currentRequest" class="container-fluid container-limited"
:requests="requests" >
@change-current-request="changeCurrentRequest"
/>
<div <div
id="peek-view-host" id="peek-view-host"
class="view prepend-left-5" class="view"
> >
<span <span
v-if="currentRequest && currentRequest.details" v-if="currentRequest.details"
class="current-host" class="current-host"
> >
{{ currentRequest.details.host.hostname }} {{ currentRequest.details.host.hostname }}
</span> </span>
</div> </div>
<div
v-if="currentRequest"
class="wrapper"
>
<upstream-performance-bar <upstream-performance-bar
v-if="initialRequest && currentRequest.details" v-if="initialRequest && currentRequest.details"
/> />
...@@ -186,6 +180,12 @@ export default { ...@@ -186,6 +180,12 @@ export default {
gc gc
</span> </span>
</div> </div>
<request-selector
v-if="currentRequest"
:current-request="currentRequest"
:requests="requests"
@change-current-request="changeCurrentRequest"
/>
</div> </div>
</div> </div>
</template> </template>
...@@ -37,7 +37,7 @@ export default { ...@@ -37,7 +37,7 @@ export default {
<template> <template>
<div <div
id="peek-request-selector" id="peek-request-selector"
class="append-right-5 pull-right" class="pull-right"
> >
<select v-model="currentRequestId"> <select v-model="currentRequestId">
<option <option
......
...@@ -5,6 +5,8 @@ export default { ...@@ -5,6 +5,8 @@ export default {
.getElementById('peek-view-performance-bar') .getElementById('peek-view-performance-bar')
.cloneNode(true); .cloneNode(true);
upstreamPerformanceBar.classList.remove('hidden');
this.$refs.wrapper.appendChild(upstreamPerformanceBar); this.$refs.wrapper.appendChild(upstreamPerformanceBar);
}, },
}; };
......
...@@ -4,9 +4,9 @@ import Vue from 'vue'; ...@@ -4,9 +4,9 @@ import Vue from 'vue';
import performanceBarApp from './components/performance_bar_app.vue'; import performanceBarApp from './components/performance_bar_app.vue';
import PerformanceBarStore from './stores/performance_bar_store'; import PerformanceBarStore from './stores/performance_bar_store';
export default () => export default ({ container }) =>
new Vue({ new Vue({
el: '#js-peek', el: container,
components: { components: {
performanceBarApp, 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> <script>
import timeTrackingHelpState from './help_state'; import timeTrackingHelpState from './help_state';
import timeTrackingCollapsedState from './collapsed_state'; import TimeTrackingCollapsedState from './collapsed_state.vue';
import timeTrackingSpentOnlyPane from './spent_only_pane'; import timeTrackingSpentOnlyPane from './spent_only_pane';
import timeTrackingNoTrackingPane from './no_tracking_pane'; import timeTrackingNoTrackingPane from './no_tracking_pane';
import timeTrackingEstimateOnlyPane from './estimate_only_pane'; import timeTrackingEstimateOnlyPane from './estimate_only_pane';
...@@ -11,7 +11,7 @@ import eventHub from '../../event_hub'; ...@@ -11,7 +11,7 @@ import eventHub from '../../event_hub';
export default { export default {
name: 'IssuableTimeTracker', name: 'IssuableTimeTracker',
components: { components: {
'time-tracking-collapsed-state': timeTrackingCollapsedState, TimeTrackingCollapsedState,
'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane, 'time-tracking-estimate-only-pane': timeTrackingEstimateOnlyPane,
'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane, 'time-tracking-spent-only-pane': timeTrackingSpentOnlyPane,
'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane, 'time-tracking-no-tracking-pane': timeTrackingNoTrackingPane,
......
...@@ -62,8 +62,7 @@ ...@@ -62,8 +62,7 @@
return `${gon.sprite_file_icons}#${iconName}`; return `${gon.sprite_file_icons}#${iconName}`;
}, },
folderIconName() { folderIconName() {
// We don't have a open folder icon yet return this.opened ? 'folder-open' : 'folder';
return this.opened ? 'folder' : 'folder';
}, },
iconSizeClass() { iconSizeClass() {
return this.size ? `s${this.size}` : ''; return this.size ? `s${this.size}` : '';
......
...@@ -43,12 +43,6 @@ ...@@ -43,12 +43,6 @@
} }
} }
.wrapper {
width: 80%;
height: $performance-bar-height;
margin: 0 auto;
}
// UI Elements // UI Elements
.bucket { .bucket {
background: $perf-bar-bucket-bg; background: $perf-bar-bucket-bg;
......
...@@ -377,4 +377,11 @@ module IssuablesHelper ...@@ -377,4 +377,11 @@ module IssuablesHelper
def parent def parent
@project || @group @project || @group
end 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 end
...@@ -230,13 +230,13 @@ class Group < Namespace ...@@ -230,13 +230,13 @@ class Group < Namespace
end end
GroupMember GroupMember
.active_without_invites .active_without_invites_and_requests
.where(source_id: source_ids) .where(source_id: source_ids)
end end
def members_with_descendants def members_with_descendants
GroupMember GroupMember
.active_without_invites .active_without_invites_and_requests
.where(source_id: self_and_descendants.reorder(nil).select(:id)) .where(source_id: self_and_descendants.reorder(nil).select(:id))
end end
......
...@@ -52,7 +52,7 @@ class Member < ActiveRecord::Base ...@@ -52,7 +52,7 @@ class Member < ActiveRecord::Base
end end
# Like active, but without invites. For when a User is required. # 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 left_join_users
.where(users: { state: 'active' }) .where(users: { state: 'active' })
.non_request .non_request
......
...@@ -208,9 +208,9 @@ class NotificationService ...@@ -208,9 +208,9 @@ class NotificationService
def new_access_request(member) def new_access_request(member)
return true unless member.notifiable?(:subscription) 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) 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 end
recipients.each { |recipient| deliver_access_request_email(recipient, member) } recipients.each { |recipient| deliver_access_request_email(recipient, member) }
......
...@@ -67,12 +67,8 @@ ...@@ -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;" } %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" }/ %img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/
%div %div
%a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications - manage_notifications_link = link_to(_("Manage all notifications"), profile_notifications_url, style: "color:#3777b0;text-decoration:none;")
&middot; - help_link = link_to(_("Help"), help_url, style: "color:#3777b0;text-decoration:none;")
%a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help = _("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 }
%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
= yield :additional_footer = yield :additional_footer
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
profile_url: url_for(params.merge(lineprofiler: 'true')) }, profile_url: url_for(params.merge(lineprofiler: 'true')) },
class: Peek.env } class: Peek.env }
#peek-view-performance-bar #peek-view-performance-bar.hidden
= render_server_response_time = render_server_response_time
%span#serverstats %span#serverstats
%ul.performance-bar %ul.performance-bar
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
.issue-main-info .issue-main-info
.issue-title.title .issue-title.title
%span.issue-title-text %span.issue-title-text
- if issue.confidential?
%span.has-tooltip{ title: _('Confidential') }
= confidential_icon(issue) = confidential_icon(issue)
= link_to issue.title, issue_path(issue) = link_to issue.title, issue_path(issue)
- if issue.tasks? - if issue.tasks?
...@@ -24,11 +26,11 @@ ...@@ -24,11 +26,11 @@
- if issue.milestone - if issue.milestone
%span.issuable-milestone.hidden-xs %span.issuable-milestone.hidden-xs
&nbsp; &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') = icon('clock-o')
= issue.milestone.title = issue.milestone.title
- if issue.due_date - 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; &nbsp;
= icon('calendar') = icon('calendar')
= issue.due_date.to_s(:medium) = issue.due_date.to_s(:medium)
......
...@@ -23,11 +23,11 @@ ...@@ -23,11 +23,11 @@
- if merge_request.milestone - if merge_request.milestone
%span.issuable-milestone.hidden-xs %span.issuable-milestone.hidden-xs
&nbsp; &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') = icon('clock-o')
= merge_request.milestone.title = merge_request.milestone.title
- if merge_request.target_project.default_branch != merge_request.target_branch - 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; &nbsp;
= link_to project_ref_path(merge_request.project, merge_request.target_branch), class: 'ref-name' do = 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') = sprite_icon('fork', size: 12, css_class: 'fork-sprite')
...@@ -51,11 +51,11 @@ ...@@ -51,11 +51,11 @@
= render_pipeline_status(merge_request.head_pipeline) = render_pipeline_status(merge_request.head_pipeline)
- if merge_request.open? && merge_request.broken? - if merge_request.open? && merge_request.broken?
%li.issuable-pipeline-broken.hidden-xs %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') = icon('exclamation-triangle')
- if merge_request.assignee - if merge_request.assignee
%li %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 = render 'shared/issuable_meta_data', issuable: merge_request
......
...@@ -77,7 +77,7 @@ ...@@ -77,7 +77,7 @@
= render 'projects/find_file_link' = render 'projects/find_file_link'
= succeed " " do = 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') = _('Web IDE')
= render 'projects/buttons/download', project: @project, ref: @ref = render 'projects/buttons/download', project: @project, ref: @ref
...@@ -5,21 +5,21 @@ ...@@ -5,21 +5,21 @@
- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count - issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count
- if issuable_mr > 0 - 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') = image_tag('icon-merge-request-unmerged.svg', class: 'icon-merge-request-unmerged')
= issuable_mr = issuable_mr
- if upvotes > 0 - if upvotes > 0
%li.issuable-upvotes.hidden-xs %li.issuable-upvotes.hidden-xs.has-tooltip{ title: _('Upvotes') }
= icon('thumbs-up') = icon('thumbs-up')
= upvotes = upvotes
- if downvotes > 0 - if downvotes > 0
%li.issuable-downvotes.hidden-xs %li.issuable-downvotes.hidden-xs.has-tooltip{ title: _('Downvotes') }
= icon('thumbs-down') = icon('thumbs-down')
= downvotes = downvotes
%li.issuable-comments.hidden-xs %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') = icon('comments')
= note_count = note_count
...@@ -4,7 +4,7 @@ ...@@ -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)" } %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) }' } %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", %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" } "aria-hidden": "true" }
%span.board-title-text.has-tooltip{ "v-if": "list.type !== \"label\"", %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