Commit bca0dfcb authored by GitLab Bot's avatar GitLab Bot

Merge remote-tracking branch 'upstream/master' into ce-to-ee-2018-06-05

# Conflicts:
#	Gemfile.rails5.lock
#	app/assets/stylesheets/bootstrap_migration.scss
#	app/models/ci/pipeline.rb
#	app/models/personal_snippet.rb
#	app/services/application_settings/update_service.rb
#	db/schema.rb
#	doc/user/project/import/github.md
#	locale/gitlab.pot
#	spec/serializers/pipeline_serializer_spec.rb
#	spec/uploaders/object_storage_spec.rb

[ci skip]
parents 1f3a35f7 6f2cd9bc
...@@ -183,7 +183,7 @@ Assigning a team label makes sure issues get the attention of the appropriate ...@@ -183,7 +183,7 @@ Assigning a team label makes sure issues get the attention of the appropriate
people. people.
The current team labels are ~Distribution, ~"CI/CD", ~Discussion, ~Documentation, ~Quality, The current team labels are ~Distribution, ~"CI/CD", ~Discussion, ~Documentation, ~Quality,
~Geo, ~Gitaly, ~Monitoring, ~Platform, ~Release, ~"Security Products" and ~"UX". ~Geo, ~Gitaly, ~Monitoring, ~Platform, ~Release, ~"Security Products", ~"Configuration", and ~"UX".
The descriptions on the [labels page][labels-page] explain what falls under the The descriptions on the [labels page][labels-page] explain what falls under the
responsibility of each team. responsibility of each team.
...@@ -350,7 +350,7 @@ on those issues. Please select someone with relevant experience from the ...@@ -350,7 +350,7 @@ on those issues. Please select someone with relevant experience from the
[GitLab team][team]. If there is nobody mentioned with that expertise look in [GitLab team][team]. If there is nobody mentioned with that expertise look in
the commit history for the affected files to find someone. the commit history for the affected files to find someone.
[described in our handbook]: https://about.gitlab.com/handbook/engineering/issues/issue-triage-policies/ [described in our handbook]: https://about.gitlab.com/handbook/engineering/issue-triage/
[issue bash events]: https://gitlab.com/gitlab-org/gitlab-ce/issues/17815 [issue bash events]: https://gitlab.com/gitlab-org/gitlab-ce/issues/17815
### Feature proposals ### Feature proposals
......
...@@ -386,7 +386,7 @@ end ...@@ -386,7 +386,7 @@ end
group :test do group :test do
gem 'shoulda-matchers', '~> 3.1.2', require: false gem 'shoulda-matchers', '~> 3.1.2', require: false
gem 'email_spec', '~> 1.6.0' gem 'email_spec', '~> 2.2.0'
gem 'json-schema', '~> 2.8.0' gem 'json-schema', '~> 2.8.0'
gem 'webmock', '~> 2.3.2' gem 'webmock', '~> 2.3.2'
gem 'rails-controller-testing' if rails5? # Rails5 only gem. gem 'rails-controller-testing' if rails5? # Rails5 only gem.
......
...@@ -180,7 +180,7 @@ GEM ...@@ -180,7 +180,7 @@ GEM
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
doorkeeper (4.3.2) doorkeeper (4.3.2)
railties (>= 4.2) railties (>= 4.2)
doorkeeper-openid_connect (1.3.0) doorkeeper-openid_connect (1.4.0)
doorkeeper (~> 4.3) doorkeeper (~> 4.3)
json-jwt (~> 1.6) json-jwt (~> 1.6)
dropzonejs-rails (0.7.2) dropzonejs-rails (0.7.2)
...@@ -199,9 +199,10 @@ GEM ...@@ -199,9 +199,10 @@ GEM
faraday faraday
multi_json multi_json
email_reply_trimmer (0.1.6) email_reply_trimmer (0.1.6)
email_spec (1.6.0) email_spec (2.2.0)
htmlentities (~> 4.3.3)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.7)
encryptor (3.0.0) encryptor (3.0.0)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
...@@ -1045,7 +1046,7 @@ DEPENDENCIES ...@@ -1045,7 +1046,7 @@ DEPENDENCIES
elasticsearch-model (~> 0.1.9) elasticsearch-model (~> 0.1.9)
elasticsearch-rails (~> 0.1.9) elasticsearch-rails (~> 0.1.9)
email_reply_trimmer (~> 0.1) email_reply_trimmer (~> 0.1)
email_spec (~> 1.6.0) email_spec (~> 2.2.0)
factory_bot_rails (~> 4.8.2) factory_bot_rails (~> 4.8.2)
faraday (~> 0.12) faraday (~> 0.12)
faraday_middleware-aws-signers-v4 faraday_middleware-aws-signers-v4
......
...@@ -201,9 +201,10 @@ GEM ...@@ -201,9 +201,10 @@ GEM
faraday faraday
multi_json multi_json
email_reply_trimmer (0.1.10) email_reply_trimmer (0.1.10)
email_spec (1.6.0) email_spec (2.2.0)
htmlentities (~> 4.3.3)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.7)
encryptor (3.0.0) encryptor (3.0.0)
equalizer (0.0.11) equalizer (0.0.11)
erubis (2.7.0) erubis (2.7.0)
...@@ -1013,7 +1014,10 @@ DEPENDENCIES ...@@ -1013,7 +1014,10 @@ DEPENDENCIES
asset_sync (~> 2.4) asset_sync (~> 2.4)
attr_encrypted (~> 3.1.0) attr_encrypted (~> 3.1.0)
awesome_print awesome_print
<<<<<<< HEAD
aws-sdk aws-sdk
=======
>>>>>>> upstream/master
babosa (~> 1.0.2) babosa (~> 1.0.2)
base32 (~> 0.3.0) base32 (~> 0.3.0)
batch-loader (~> 1.2.1) batch-loader (~> 1.2.1)
...@@ -1050,7 +1054,7 @@ DEPENDENCIES ...@@ -1050,7 +1054,7 @@ DEPENDENCIES
elasticsearch-model (~> 0.1.9) elasticsearch-model (~> 0.1.9)
elasticsearch-rails (~> 0.1.9) elasticsearch-rails (~> 0.1.9)
email_reply_trimmer (~> 0.1) email_reply_trimmer (~> 0.1)
email_spec (~> 1.6.0) email_spec (~> 2.2.0)
factory_bot_rails (~> 4.8.2) factory_bot_rails (~> 4.8.2)
faraday (~> 0.12) faraday (~> 0.12)
faraday_middleware-aws-signers-v4 faraday_middleware-aws-signers-v4
......
...@@ -176,6 +176,7 @@ the stable branch are: ...@@ -176,6 +176,7 @@ the stable branch are:
* Fixes for [regressions](#regressions) * Fixes for [regressions](#regressions)
* Fixes for security issues * Fixes for security issues
* Fixes or improvements to automated QA scenarios
* New or updated translations (as long as they do not touch application code) * New or updated translations (as long as they do not touch application code)
During the feature freeze all merge requests that are meant to go into the During the feature freeze all merge requests that are meant to go into the
......
...@@ -156,5 +156,5 @@ Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on ...@@ -156,5 +156,5 @@ Please see [Getting help for GitLab](https://about.gitlab.com/getting-help/) on
## Is it awesome? ## Is it awesome?
Thanks for [asking this question](https://twitter.com/supersloth/status/489462789384056832) Joshua.
[These people](https://twitter.com/gitlab/likes) seem to like it. [These people](https://twitter.com/gitlab/likes) seem to like it.
...@@ -187,7 +187,7 @@ ...@@ -187,7 +187,7 @@
role="row" role="row"
> >
<div <div
class="alert alert-danger alert-block append-bottom-0" class="alert alert-danger alert-block append-bottom-0 clusters-error-alert"
role="gridcell" role="gridcell"
> >
<div> <div>
......
<script> <script>
import $ from 'jquery';
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
...@@ -20,6 +21,13 @@ export default { ...@@ -20,6 +21,13 @@ export default {
}, },
methods: { methods: {
...mapActions(['updateActivityBarView']), ...mapActions(['updateActivityBarView']),
changedActivityView(e, view) {
e.currentTarget.blur();
this.updateActivityBarView(view);
$(e.currentTarget).tooltip('hide');
},
}, },
activityBarViews, activityBarViews,
}; };
...@@ -54,7 +62,7 @@ export default { ...@@ -54,7 +62,7 @@ export default {
:class="{ :class="{
active: currentActivityView === $options.activityBarViews.edit active: currentActivityView === $options.activityBarViews.edit
}" }"
@click.prevent="updateActivityBarView($options.activityBarViews.edit)" @click.prevent="changedActivityView($event, $options.activityBarViews.edit)"
:title="s__('IDE|Edit')" :title="s__('IDE|Edit')"
:aria-label="s__('IDE|Edit')" :aria-label="s__('IDE|Edit')"
> >
...@@ -73,7 +81,7 @@ export default { ...@@ -73,7 +81,7 @@ export default {
:class="{ :class="{
active: currentActivityView === $options.activityBarViews.review active: currentActivityView === $options.activityBarViews.review
}" }"
@click.prevent="updateActivityBarView($options.activityBarViews.review)" @click.prevent="changedActivityView($event, $options.activityBarViews.review)"
:title="s__('IDE|Review')" :title="s__('IDE|Review')"
:aria-label="s__('IDE|Review')" :aria-label="s__('IDE|Review')"
> >
...@@ -92,7 +100,7 @@ export default { ...@@ -92,7 +100,7 @@ export default {
:class="{ :class="{
active: currentActivityView === $options.activityBarViews.commit active: currentActivityView === $options.activityBarViews.commit
}" }"
@click.prevent="updateActivityBarView($options.activityBarViews.commit)" @click.prevent="changedActivityView($event, $options.activityBarViews.commit)"
:title="s__('IDE|Commit')" :title="s__('IDE|Commit')"
:aria-label="s__('IDE|Commit')" :aria-label="s__('IDE|Commit')"
> >
......
...@@ -426,7 +426,7 @@ export default class LabelsSelect { ...@@ -426,7 +426,7 @@ export default class LabelsSelect {
const tpl = _.template([ const tpl = _.template([
'<% _.each(labels, function(label){ %>', '<% _.each(labels, function(label){ %>',
'<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">', '<a href="<%- issueUpdateURL.slice(0, issueUpdateURL.lastIndexOf("/")) %>?label_name[]=<%- encodeURIComponent(label.title) %>">',
'<span class="label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">', '<span class="badge label has-tooltip color-label" title="<%- label.description %>" style="background-color: <%- label.color %>; color: <%- label.text_color %>;">',
'<%- label.title %>', '<%- label.title %>',
'</span>', '</span>',
'</a>', '</a>',
......
...@@ -14,6 +14,7 @@ export const EPIC_NOTEABLE_TYPE = 'epic'; ...@@ -14,6 +14,7 @@ export const EPIC_NOTEABLE_TYPE = 'epic';
export const MERGE_REQUEST_NOTEABLE_TYPE = 'merge_request'; export const MERGE_REQUEST_NOTEABLE_TYPE = 'merge_request';
export const UNRESOLVE_NOTE_METHOD_NAME = 'delete'; export const UNRESOLVE_NOTE_METHOD_NAME = 'delete';
export const RESOLVE_NOTE_METHOD_NAME = 'post'; export const RESOLVE_NOTE_METHOD_NAME = 'post';
export const DESCRIPTION_TYPE = 'changed the description';
export const NOTEABLE_TYPE_MAPPING = { export const NOTEABLE_TYPE_MAPPING = {
Issue: ISSUE_NOTEABLE_TYPE, Issue: ISSUE_NOTEABLE_TYPE,
......
import { n__, s__, sprintf } from '~/locale';
import { DESCRIPTION_TYPE } from '../constants';
/**
* Changes the description from a note, returns 'changed the description n number of times'
*/
export const changeDescriptionNote = (note, descriptionChangedTimes, timeDifferenceMinutes) => {
const descriptionNote = Object.assign({}, note);
descriptionNote.note_html = sprintf(
s__(`MergeRequest|
%{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}`),
{
paragraphStart: '<p dir="auto">',
paragraphEnd: '</p>',
descriptionChangedTimes,
timeDifferenceMinutes: n__('within %d minute ', 'within %d minutes ', timeDifferenceMinutes),
},
false,
);
descriptionNote.times_updated = descriptionChangedTimes;
return descriptionNote;
};
/**
* Checks the time difference between two notes from their 'created_at' dates
* returns an integer
*/
export const getTimeDifferenceMinutes = (noteBeggining, noteEnd) => {
const descriptionNoteBegin = new Date(noteBeggining.created_at);
const descriptionNoteEnd = new Date(noteEnd.created_at);
const timeDifferenceMinutes = (descriptionNoteEnd - descriptionNoteBegin) / 1000 / 60;
return Math.ceil(timeDifferenceMinutes);
};
/**
* Checks if a note is a system note and if the content is description
*
* @param {Object} note
* @returns {Boolean}
*/
export const isDescriptionSystemNote = note => note.system && note.note === DESCRIPTION_TYPE;
/**
* Collapses the system notes of a description type, e.g. Changed the description, n minutes ago
* the notes will collapse as long as they happen no more than 10 minutes away from each away
* in between the notes can be anything, another type of system note
* (such as 'changed the weight') or a comment.
*
* @param {Array} notes
* @returns {Array}
*/
export const collapseSystemNotes = notes => {
let lastDescriptionSystemNote = null;
let lastDescriptionSystemNoteIndex = -1;
let descriptionChangedTimes = 1;
return notes.slice(0).reduce((acc, currentNote) => {
const note = currentNote.notes[0];
if (isDescriptionSystemNote(note)) {
// is it the first one?
if (!lastDescriptionSystemNote) {
lastDescriptionSystemNote = note;
lastDescriptionSystemNoteIndex = acc.length;
} else if (lastDescriptionSystemNote) {
const timeDifferenceMinutes = getTimeDifferenceMinutes(
lastDescriptionSystemNote,
note,
);
// are they less than 10 minutes appart?
if (timeDifferenceMinutes > 10) {
// reset counter
descriptionChangedTimes = 1;
// update the previous system note
lastDescriptionSystemNote = note;
lastDescriptionSystemNoteIndex = acc.length;
} else {
// increase counter
descriptionChangedTimes += 1;
// delete the previous one
acc.splice(lastDescriptionSystemNoteIndex, 1);
// replace the text of the current system note with the collapsed note.
currentNote.notes.splice(
0,
1,
changeDescriptionNote(note, descriptionChangedTimes, timeDifferenceMinutes),
);
// update the previous system note index
lastDescriptionSystemNoteIndex = acc.length;
}
}
}
acc.push(currentNote);
return acc;
}, []);
};
// for babel-rewire
export default {};
import _ from 'underscore'; import _ from 'underscore';
import { collapseSystemNotes } from './collapse_utils';
export const notes = state => collapseSystemNotes(state.notes);
export const notes = state => state.notes;
export const targetNoteHash = state => state.targetNoteHash; export const targetNoteHash = state => state.targetNoteHash;
export const getNotesData = state => state.notesData; export const getNotesData = state => state.notesData;
......
...@@ -124,15 +124,18 @@ ...@@ -124,15 +124,18 @@
break; break;
} }
}, },
hideOnSmallScreen(item) {
return !item.first && !item.last && !item.next && !item.prev && !item.active;
},
}, },
}; };
</script> </script>
<template> <template>
<div <div
v-if="showPagination" v-if="showPagination"
class="gl-pagination" class="gl-pagination prepend-top-default"
> >
<ul class="pagination clearfix"> <ul class="pagination justify-content-center">
<li <li
v-for="(item, index) in getItems" v-for="(item, index) in getItems"
:key="index" :key="index"
...@@ -142,12 +145,17 @@ ...@@ -142,12 +145,17 @@
'js-next-button': item.next, 'js-next-button': item.next,
'js-last-button': item.last, 'js-last-button': item.last,
'js-first-button': item.first, 'js-first-button': item.first,
'd-none d-md-block': hideOnSmallScreen(item),
separator: item.separator, separator: item.separator,
active: item.active, active: item.active,
disabled: item.disabled disabled: item.disabled || item.separator
}" }"
class="page-item"
> >
<a @click.prevent="changePage(item.title, item.disabled)"> <a
@click.prevent="changePage(item.title, item.disabled)"
class="page-link"
>
{{ item.title }} {{ item.title }}
</a> </a>
</li> </li>
......
...@@ -24,16 +24,54 @@ html { ...@@ -24,16 +24,54 @@ html {
font-size: 14px; font-size: 14px;
} }
legend {
border-bottom: 1px solid $border-color;
margin-bottom: 20px;
}
button, button,
html [type="button"], html [type="button"],
[type="reset"], [type="reset"],
[type="submit"] { [type="submit"],
[role="button"] {
// Override bootstrap reboot // Override bootstrap reboot
-webkit-appearance: inherit; -webkit-appearance: inherit;
cursor: pointer;
} }
[role="button"] { h1,
cursor: pointer; h2,
h3,
h4,
h5,
h6 {
color: $gl-text-color;
font-weight: 600;
}
h1,
.h1,
h2,
.h2,
h3,
.h3 {
margin-top: 20px;
margin-bottom: 10px;
}
h4,
.h4,
h5,
.h5,
h6,
.h6 {
margin-top: 10px;
margin-bottom: 10px;
}
h5,
.h5 {
font-size: $gl-font-size;
} }
input[type="file"] { input[type="file"] {
...@@ -59,6 +97,10 @@ a { ...@@ -59,6 +97,10 @@ a {
} }
} }
kbd {
display: inline-block;
}
code { code {
padding: 2px 4px; padding: 2px 4px;
color: $red-600; color: $red-600;
...@@ -69,6 +111,14 @@ code { ...@@ -69,6 +111,14 @@ code {
background-color: inherit; background-color: inherit;
padding: unset; padding: unset;
} }
<<<<<<< HEAD
=======
.build-trace & {
background-color: inherit;
padding: inherit;
}
>>>>>>> upstream/master
} }
.code { .code {
...@@ -178,7 +228,9 @@ table { ...@@ -178,7 +228,9 @@ table {
.nav-tabs { .nav-tabs {
.nav-link { .nav-link {
border: 0; border-top: 0;
border-left: 0;
border-right: 0;
} }
.nav-item { .nav-item {
......
...@@ -35,6 +35,12 @@ ...@@ -35,6 +35,12 @@
@include media-breakpoint-down(xs) { @include media-breakpoint-down(xs) {
width: 100%; width: 100%;
} }
&.projects-dropdown-menu {
padding: 0;
overflow-y: initial;
max-height: initial;
}
} }
.dropdown-toggle, .dropdown-toggle,
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
} }
&.active > a, &.active > a,
&.dropdown.open > a { &.dropdown.show > a {
color: $color-900; color: $color-900;
background-color: $color-alternate; background-color: $color-alternate;
} }
...@@ -74,7 +74,7 @@ ...@@ -74,7 +74,7 @@
} }
&.active > a, &.active > a,
&.dropdown.open > a { &.dropdown.show > a {
color: $color-900; color: $color-900;
background-color: $color-alternate; background-color: $color-alternate;
......
...@@ -297,12 +297,6 @@ ...@@ -297,12 +297,6 @@
display: flex; display: flex;
margin: 0 0 0 6px; margin: 0 0 0 6px;
.projects-dropdown-menu {
padding: 0;
overflow-y: initial;
max-height: initial;
}
.dropdown-chevron { .dropdown-chevron {
position: relative; position: relative;
top: -1px; top: -1px;
......
...@@ -115,9 +115,3 @@ body { ...@@ -115,9 +115,3 @@ body {
.with-performance-bar .layout-page { .with-performance-bar .layout-page {
margin-top: $header-height + $performance-bar-height; margin-top: $header-height + $performance-bar-height;
} }
.vertical-center {
min-height: 100vh;
display: flex;
align-items: center;
}
.gl-pagination { .gl-pagination {
text-align: center; a {
border-top: 1px solid $border-color; color: inherit;
margin: 0; text-decoration: none;
margin-top: 0;
.pagination {
padding: 0;
margin: 20px 0;
a {
cursor: pointer;
}
.separator,
.separator:hover {
a {
cursor: default;
background-color: $gray-light;
padding: $gl-vert-padding;
}
}
}
.gap,
.gap:hover {
background-color: $gray-light;
padding: $gl-vert-padding;
cursor: default;
}
}
.card > .gl-pagination {
margin: 0;
}
/**
* Extra-small screen pagination.
*/
@media (max-width: 320px) {
.gl-pagination {
.first,
.last {
display: none;
}
.page-item {
display: none;
&.active {
display: inline;
}
}
}
}
/**
* Small screen pagination
*/
@include media-breakpoint-down(xs) {
.gl-pagination {
.pagination li a {
padding: 6px 10px;
}
.page-item {
display: none;
&.active {
display: inline;
}
}
}
}
/**
* Medium screen pagination
*/
@media (min-width: map-get($grid-breakpoints, xs)) and (max-width: map-get($grid-breakpoints, sm)) {
.gl-pagination {
.page-item {
display: none;
&.active,
&.sibling {
display: inline;
}
}
} }
} }
...@@ -11,15 +11,15 @@ ...@@ -11,15 +11,15 @@
padding-top: $gl-padding; padding-top: $gl-padding;
} }
.panel { .card {
.panel-heading { .card-header {
display: -webkit-flex; display: -webkit-flex;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
line-height: $line-height-base; line-height: $line-height-base;
.title { .card-title {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -34,6 +34,8 @@ ...@@ -34,6 +34,8 @@
.navbar-collapse { .navbar-collapse {
padding-right: 0; padding-right: 0;
flex-grow: 0;
flex-basis: auto;
.navbar-nav { .navbar-nav {
margin: 0; margin: 0;
......
...@@ -114,26 +114,27 @@ ...@@ -114,26 +114,27 @@
font-size: 0.95em; font-size: 0.95em;
} }
blockquote,
.blockquote { .blockquote {
color: $gl-grayish-blue; color: $gl-grayish-blue;
font-size: inherit; font-size: inherit;
padding: 8px 24px; padding: 8px 24px;
margin: 16px 0; margin: 16px 0;
border-left: 3px solid $white-dark; border-left: 3px solid $white-dark;
}
.blockquote:dir(rtl) { &:dir(rtl) {
border-left: 0; border-left: 0;
border-right: 3px solid $white-dark; border-right: 3px solid $white-dark;
} }
.blockquote p { p {
color: $gl-grayish-blue !important; color: $gl-grayish-blue !important;
font-size: inherit; font-size: inherit;
line-height: 1.5; line-height: 1.5;
&:last-child { &:last-child {
margin: 0; margin: 0;
}
} }
} }
......
...@@ -138,6 +138,7 @@ pre { ...@@ -138,6 +138,7 @@ pre {
margin: 0; margin: 0;
} }
blockquote,
.blockquote { .blockquote {
color: $gl-grayish-blue; color: $gl-grayish-blue;
padding: 0 0 0 15px; padding: 0 0 0 15px;
......
...@@ -13,6 +13,10 @@ ...@@ -13,6 +13,10 @@
max-width: 100%; max-width: 100%;
} }
.clusters-error-alert {
width: 100%;
}
.clusters-container { .clusters-container {
.nav-bar-right { .nav-bar-right {
padding: $gl-padding-top $gl-padding; padding: $gl-padding-top $gl-padding;
......
...@@ -489,6 +489,15 @@ ...@@ -489,6 +489,15 @@
.sidebar-collapsed-user { .sidebar-collapsed-user {
padding-bottom: 0; padding-bottom: 0;
margin-bottom: 10px; margin-bottom: 10px;
.author_link {
padding-left: 0;
.avatar {
position: static;
margin: 0;
}
}
} }
.issuable-header-btn { .issuable-header-btn {
......
...@@ -196,6 +196,10 @@ ...@@ -196,6 +196,10 @@
.prioritized-labels { .prioritized-labels {
margin-bottom: 30px; margin-bottom: 30px;
h5 {
font-size: $gl-font-size;
}
.add-priority { .add-priority {
display: none; display: none;
color: $gray-light; color: $gray-light;
...@@ -210,6 +214,10 @@ ...@@ -210,6 +214,10 @@
} }
.other-labels { .other-labels {
h5 {
font-size: $gl-font-size;
}
.remove-priority { .remove-priority {
display: none; display: none;
} }
......
...@@ -183,7 +183,7 @@ ...@@ -183,7 +183,7 @@
svg { svg {
position: relative; position: relative;
top: -1px; top: -2px;
} }
.ide-file-changed-icon { .ide-file-changed-icon {
...@@ -458,6 +458,10 @@ ...@@ -458,6 +458,10 @@
width: auto; width: auto;
margin-right: 0; margin-right: 0;
a {
height: 60px;
}
a:hover, a:hover,
a:focus { a:focus {
text-decoration: none; text-decoration: none;
...@@ -718,9 +722,17 @@ ...@@ -718,9 +722,17 @@
} }
.ide-new-btn { .ide-new-btn {
.btn {
padding-top: 3px;
padding-bottom: 3px;
}
.dropdown {
display: flex;
}
.dropdown-toggle svg { .dropdown-toggle svg {
margin-top: -2px; top: 0;
margin-bottom: 2px;
} }
.dropdown-menu { .dropdown-menu {
...@@ -877,6 +889,7 @@ ...@@ -877,6 +889,7 @@
border-top: 1px solid transparent; border-top: 1px solid transparent;
border-bottom: 1px solid transparent; border-bottom: 1px solid transparent;
outline: 0; outline: 0;
cursor: pointer;
svg { svg {
margin: 0 auto; margin: 0 auto;
......
...@@ -174,7 +174,7 @@ ...@@ -174,7 +174,7 @@
.option-description, .option-description,
.option-disabled-reason { .option-disabled-reason {
margin-left: 45px; margin-left: 30px;
color: $project-option-descr-color; color: $project-option-descr-color;
} }
......
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
header, header,
nav, nav,
nav.main-nav,
nav.navbar-collapse, nav.navbar-collapse,
nav.navbar-collapse.collapse, nav.navbar-collapse.collapse,
.nav-sidebar,
.profiler-results, .profiler-results,
.tree-ref-holder, .tree-ref-holder,
.tree-holder .breadcrumb, .tree-holder .breadcrumb,
...@@ -38,7 +38,8 @@ ul.notes-form, ...@@ -38,7 +38,8 @@ ul.notes-form,
.edit-link, .edit-link,
.note-action-button, .note-action-button,
.right-sidebar, .right-sidebar,
.flash-container { .flash-container,
#js-peek {
display: none !important; display: none !important;
} }
......
...@@ -24,7 +24,9 @@ module Groups ...@@ -24,7 +24,9 @@ module Groups
# Make the `search` param consistent for the frontend, # Make the `search` param consistent for the frontend,
# which will be using `filter`. # which will be using `filter`.
params[:search] ||= params[:filter] if params[:filter] params[:search] ||= params[:filter] if params[:filter]
params.permit(:sort, :search) # Don't show archived projects
params[:non_archived] = true
params.permit(:sort, :search, :non_archived)
end end
end end
end end
......
...@@ -18,7 +18,7 @@ class Projects::LfsStorageController < Projects::GitHttpClientController ...@@ -18,7 +18,7 @@ class Projects::LfsStorageController < Projects::GitHttpClientController
def upload_authorize def upload_authorize
set_workhorse_internal_api_content_type set_workhorse_internal_api_content_type
authorized = LfsObjectUploader.workhorse_authorize authorized = LfsObjectUploader.workhorse_authorize(has_length: true)
authorized.merge!(LfsOid: oid, LfsSize: size) authorized.merge!(LfsOid: oid, LfsSize: size)
render json: authorized render json: authorized
......
class Projects::MilestonesController < Projects::ApplicationController class Projects::MilestonesController < Projects::ApplicationController
include Gitlab::Utils::StrongMemoize
include MilestoneActions include MilestoneActions
before_action :check_issuables_available! before_action :check_issuables_available!
...@@ -103,7 +104,7 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -103,7 +104,7 @@ class Projects::MilestonesController < Projects::ApplicationController
protected protected
def milestones def milestones
@milestones ||= begin strong_memoize(:milestones) do
MilestonesFinder.new(search_params).execute MilestonesFinder.new(search_params).execute
end end
end end
...@@ -121,10 +122,10 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -121,10 +122,10 @@ class Projects::MilestonesController < Projects::ApplicationController
end end
def search_params def search_params
if @project.group && can?(current_user, :read_group, @project.group) if request.format.json? && @project.group && can?(current_user, :read_group, @project.group)
group = @project.group groups = @project.group.self_and_ancestors
end end
params.permit(:state).merge(project_ids: @project.id, group_ids: group&.id) params.permit(:state).merge(project_ids: @project.id, group_ids: groups&.select(:id))
end end
end end
...@@ -25,8 +25,6 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -25,8 +25,6 @@ class Projects::PipelinesController < Projects::ApplicationController
@finished_count = limited_pipelines_count(project, 'finished') @finished_count = limited_pipelines_count(project, 'finished')
@pipelines_count = limited_pipelines_count(project) @pipelines_count = limited_pipelines_count(project)
Gitlab::Ci::Pipeline::Preloader.preload(@pipelines)
respond_to do |format| respond_to do |format|
format.html format.html
format.json do format.json do
...@@ -36,7 +34,7 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -36,7 +34,7 @@ class Projects::PipelinesController < Projects::ApplicationController
pipelines: PipelineSerializer pipelines: PipelineSerializer
.new(project: @project, current_user: @current_user) .new(project: @project, current_user: @current_user)
.with_pagination(request, response) .with_pagination(request, response)
.represent(@pipelines, disable_coverage: true), .represent(@pipelines, disable_coverage: true, preload: true),
count: { count: {
all: @pipelines_count, all: @pipelines_count,
running: @running_count, running: @running_count,
......
...@@ -13,6 +13,10 @@ module Users ...@@ -13,6 +13,10 @@ module Users
def index def index
@redirect = redirect_path @redirect = redirect_path
if @term.accepted_by_user?(current_user)
flash.now[:notice] = "You have already accepted the Terms of Service as #{current_user.to_reference}"
end
end end
def accept def accept
......
...@@ -37,7 +37,7 @@ module ApplicationSettingsHelper ...@@ -37,7 +37,7 @@ module ApplicationSettingsHelper
# Return a group of checkboxes that use Bootstrap's button plugin for a # Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect. # toggle button effect.
def restricted_level_checkboxes(help_block_id, checkbox_name) def restricted_level_checkboxes(help_block_id, checkbox_name, options = {})
Gitlab::VisibilityLevel.values.map do |level| Gitlab::VisibilityLevel.values.map do |level|
checked = restricted_visibility_levels(true).include?(level) checked = restricted_visibility_levels(true).include?(level)
css_class = checked ? 'active' : '' css_class = checked ? 'active' : ''
...@@ -47,6 +47,7 @@ module ApplicationSettingsHelper ...@@ -47,6 +47,7 @@ module ApplicationSettingsHelper
check_box_tag(checkbox_name, level, checked, check_box_tag(checkbox_name, level, checked,
autocomplete: 'off', autocomplete: 'off',
'aria-describedby' => help_block_id, 'aria-describedby' => help_block_id,
'class' => options[:class],
id: tag_name) + visibility_level_icon(level) + visibility_level_label(level) id: tag_name) + visibility_level_icon(level) + visibility_level_label(level)
end end
end end
...@@ -54,7 +55,7 @@ module ApplicationSettingsHelper ...@@ -54,7 +55,7 @@ module ApplicationSettingsHelper
# Return a group of checkboxes that use Bootstrap's button plugin for a # Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect. # toggle button effect.
def import_sources_checkboxes(help_block_id) def import_sources_checkboxes(help_block_id, options = {})
Gitlab::ImportSources.options.map do |name, source| Gitlab::ImportSources.options.map do |name, source|
checked = Gitlab::CurrentSettings.import_sources.include?(source) checked = Gitlab::CurrentSettings.import_sources.include?(source)
css_class = checked ? 'active' : '' css_class = checked ? 'active' : ''
...@@ -64,6 +65,7 @@ module ApplicationSettingsHelper ...@@ -64,6 +65,7 @@ module ApplicationSettingsHelper
check_box_tag(checkbox_name, source, checked, check_box_tag(checkbox_name, source, checked,
autocomplete: 'off', autocomplete: 'off',
'aria-describedby' => help_block_id, 'aria-describedby' => help_block_id,
'class' => options[:class],
id: name.tr(' ', '_')) + name id: name.tr(' ', '_')) + name
end end
end end
......
...@@ -240,6 +240,14 @@ module ProjectsHelper ...@@ -240,6 +240,14 @@ module ProjectsHelper
"git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)" "git push --set-upstream #{repository_url}/$(git rev-parse --show-toplevel | xargs basename).git $(git rev-parse --abbrev-ref HEAD)"
end end
def show_xcode_link?(project = @project)
browser.platform.mac? && project.repository.xcode_project?
end
def xcode_uri_to_repo(project = @project)
"xcode://clone?repo=#{CGI.escape(default_url_to_repo(project))}"
end
private private
def get_project_nav_tabs(project, current_user) def get_project_nav_tabs(project, current_user)
...@@ -455,7 +463,10 @@ module ProjectsHelper ...@@ -455,7 +463,10 @@ module ProjectsHelper
exports_path = File.join(Settings.shared['path'], 'tmp/project_exports') exports_path = File.join(Settings.shared['path'], 'tmp/project_exports')
filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]") filtered_message = message.strip.gsub(exports_path, "[REPO EXPORT PATH]")
disk_path = Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path disk_path = Gitlab::GitalyClient::StorageSettings.allow_disk_access do
Gitlab.config.repositories.storages[project.repository_storage].legacy_disk_path
end
filtered_message.gsub(disk_path.chomp('/'), "[REPOS PATH]") filtered_message.gsub(disk_path.chomp('/'), "[REPOS PATH]")
end end
......
class ApplicationSetting class ApplicationSetting
class Term < ActiveRecord::Base class Term < ActiveRecord::Base
include CacheMarkdownField include CacheMarkdownField
has_many :term_agreements
validates :terms, presence: true validates :terms, presence: true
...@@ -9,5 +10,10 @@ class ApplicationSetting ...@@ -9,5 +10,10 @@ class ApplicationSetting
def self.latest def self.latest
order(:id).last order(:id).last
end end
def accepted_by_user?(user)
user.accepted_term_id == id ||
term_agreements.accepted.where(user: user).exists?
end
end end
end end
...@@ -59,6 +59,11 @@ module Ci ...@@ -59,6 +59,11 @@ module Ci
where('(artifacts_file IS NOT NULL AND artifacts_file <> ?) OR EXISTS (?)', where('(artifacts_file IS NOT NULL AND artifacts_file <> ?) OR EXISTS (?)',
'', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').archive) '', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').archive)
end end
scope :without_archived_trace, ->() do
where('NOT EXISTS (?)', Ci::JobArtifact.select(1).where('ci_builds.id = ci_job_artifacts.job_id').trace)
end
scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) } scope :with_artifacts_stored_locally, -> { with_artifacts_archive.where(artifacts_file_store: [nil, LegacyArtifactUploader::Store::LOCAL]) }
scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) } scope :with_artifacts_not_expired, ->() { with_artifacts_archive.where('artifacts_expire_at IS NULL OR artifacts_expire_at > ?', Time.now) }
scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) } scope :with_expired_artifacts, ->() { with_artifacts_archive.where('artifacts_expire_at < ?', Time.now) }
...@@ -148,6 +153,7 @@ module Ci ...@@ -148,6 +153,7 @@ module Ci
after_transition any => [:success] do |build| after_transition any => [:success] do |build|
build.run_after_commit do build.run_after_commit do
BuildSuccessWorker.perform_async(id) BuildSuccessWorker.perform_async(id)
PagesWorker.perform_async(:deploy, id) if build.pages_generator?
end end
end end
...@@ -187,6 +193,11 @@ module Ci ...@@ -187,6 +193,11 @@ module Ci
pipeline.manual_actions.where.not(name: name) pipeline.manual_actions.where.not(name: name)
end end
def pages_generator?
Gitlab.config.pages.enabled &&
self.name == 'pages'
end
def playable? def playable?
action? && (manual? || retryable?) action? && (manual? || retryable?)
end end
...@@ -406,8 +417,6 @@ module Ci ...@@ -406,8 +417,6 @@ module Ci
build_data = Gitlab::DataBuilder::Build.build(self) build_data = Gitlab::DataBuilder::Build.build(self)
project.execute_hooks(build_data.dup, :job_hooks) project.execute_hooks(build_data.dup, :job_hooks)
project.execute_services(build_data.dup, :job_hooks) project.execute_services(build_data.dup, :job_hooks)
PagesService.new(build_data).execute
project.running_or_pending_build_count(force: true)
end end
def browsable_artifacts? def browsable_artifacts?
......
...@@ -31,6 +31,14 @@ module Ci ...@@ -31,6 +31,14 @@ module Ci
end end
end end
def self.fabricate(stage)
stage.statuses.ordered.latest
.sort_by(&:sortable_name).group_by(&:group_name)
.map do |group_name, grouped_statuses|
self.new(stage, name: group_name, jobs: grouped_statuses)
end
end
private private
def commit_statuses def commit_statuses
......
...@@ -16,11 +16,7 @@ module Ci ...@@ -16,11 +16,7 @@ module Ci
end end
def groups def groups
@groups ||= statuses.ordered.latest @groups ||= Ci::Group.fabricate(self)
.sort_by(&:sortable_name).group_by(&:group_name)
.map do |group_name, grouped_statuses|
Ci::Group.new(self, name: group_name, jobs: grouped_statuses)
end
end end
def to_param def to_param
......
...@@ -20,6 +20,7 @@ module Ci ...@@ -20,6 +20,7 @@ module Ci
s&.project&.pipelines&.maximum(:iid) || s&.project&.pipelines&.count s&.project&.pipelines&.maximum(:iid) || s&.project&.pipelines&.count
end end
<<<<<<< HEAD
has_one :source_pipeline, class_name: Ci::Sources::Pipeline has_one :source_pipeline, class_name: Ci::Sources::Pipeline
has_many :sourced_pipelines, class_name: Ci::Sources::Pipeline, foreign_key: :source_pipeline_id has_many :sourced_pipelines, class_name: Ci::Sources::Pipeline, foreign_key: :source_pipeline_id
...@@ -34,6 +35,9 @@ module Ci ...@@ -34,6 +35,9 @@ module Ci
end end
has_many :stages has_many :stages
=======
has_many :stages, -> { order(position: :asc) }, inverse_of: :pipeline
>>>>>>> upstream/master
has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline has_many :statuses, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
...@@ -271,6 +275,20 @@ module Ci ...@@ -271,6 +275,20 @@ module Ci
stage unless stage.statuses_count.zero? stage unless stage.statuses_count.zero?
end end
##
# TODO We do not completely switch to persisted stages because of
# race conditions with setting statuses gitlab-ce#23257.
#
def ordered_stages
return legacy_stages unless complete?
if Feature.enabled?('ci_pipeline_persisted_stages')
stages
else
legacy_stages
end
end
def legacy_stages def legacy_stages
# TODO, this needs refactoring, see gitlab-ce#26481. # TODO, this needs refactoring, see gitlab-ce#26481.
...@@ -433,7 +451,7 @@ module Ci ...@@ -433,7 +451,7 @@ module Ci
def number_of_warnings def number_of_warnings
BatchLoader.for(id).batch(default_value: 0) do |pipeline_ids, loader| BatchLoader.for(id).batch(default_value: 0) do |pipeline_ids, loader|
Build.where(commit_id: pipeline_ids) ::Ci::Build.where(commit_id: pipeline_ids)
.latest .latest
.failed_but_allowed .failed_but_allowed
.group(:commit_id) .group(:commit_id)
...@@ -529,7 +547,8 @@ module Ci ...@@ -529,7 +547,8 @@ module Ci
def update_status def update_status
retry_optimistic_lock(self) do retry_optimistic_lock(self) do
case latest_builds_status case latest_builds_status.to_s
when 'created' then nil
when 'pending' then enqueue when 'pending' then enqueue
when 'running' then run when 'running' then run
when 'success' then succeed when 'success' then succeed
...@@ -537,6 +556,9 @@ module Ci ...@@ -537,6 +556,9 @@ module Ci
when 'canceled' then cancel when 'canceled' then cancel
when 'skipped' then skip when 'skipped' then skip
when 'manual' then block when 'manual' then block
else
raise HasStatus::UnknownStatusError,
"Unknown status `#{latest_builds_status}`"
end end
end end
end end
......
...@@ -220,10 +220,8 @@ module Ci ...@@ -220,10 +220,8 @@ module Ci
cache_attributes(values) cache_attributes(values)
if persist_cached_data? # We save data without validation, it will always change due to `contacted_at`
self.assign_attributes(values) self.update_columns(values) if persist_cached_data?
self.save if self.changed?
end
end end
def pick_build!(build) def pick_build!(build)
......
...@@ -68,16 +68,44 @@ module Ci ...@@ -68,16 +68,44 @@ module Ci
def update_status def update_status
retry_optimistic_lock(self) do retry_optimistic_lock(self) do
case statuses.latest.status case statuses.latest.status
when 'created' then nil
when 'pending' then enqueue when 'pending' then enqueue
when 'running' then run when 'running' then run
when 'success' then succeed when 'success' then succeed
when 'failed' then drop when 'failed' then drop
when 'canceled' then cancel when 'canceled' then cancel
when 'manual' then block when 'manual' then block
when 'skipped' then skip when 'skipped', nil then skip
else skip else
raise HasStatus::UnknownStatusError,
"Unknown status `#{statuses.latest.status}`"
end end
end end
end end
def groups
@groups ||= Ci::Group.fabricate(self)
end
def has_warnings?
number_of_warnings.positive?
end
def number_of_warnings
BatchLoader.for(id).batch(default_value: 0) do |stage_ids, loader|
::Ci::Build.where(stage_id: stage_ids)
.latest
.failed_but_allowed
.group(:stage_id)
.count
.each { |id, amount| loader.call(id, amount) }
end
end
def detailed_status(current_user)
Gitlab::Ci::Status::Stage::Factory
.new(self, current_user)
.fabricate!
end
end end
end end
...@@ -11,6 +11,8 @@ module HasStatus ...@@ -11,6 +11,8 @@ module HasStatus
STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3, STATUSES_ENUM = { created: 0, pending: 1, running: 2, success: 3,
failed: 4, canceled: 5, skipped: 6, manual: 7 }.freeze failed: 4, canceled: 5, skipped: 6, manual: 7 }.freeze
UnknownStatusError = Class.new(StandardError)
class_methods do class_methods do
def status_sql def status_sql
scope_relevant = respond_to?(:exclude_ignored) ? exclude_ignored : all scope_relevant = respond_to?(:exclude_ignored) ? exclude_ignored : all
......
class PersonalSnippet < Snippet class PersonalSnippet < Snippet
<<<<<<< HEAD
# Elastic search configuration (it does not support STI) # Elastic search configuration (it does not support STI)
document_type 'snippet' document_type 'snippet'
index_name [Rails.application.class.parent_name.downcase, Rails.env].join('-') index_name [Rails.application.class.parent_name.downcase, Rails.env].join('-')
include Elastic::SnippetsSearch include Elastic::SnippetsSearch
=======
>>>>>>> upstream/master
include WithUploads include WithUploads
end end
...@@ -235,6 +235,7 @@ class Project < ActiveRecord::Base ...@@ -235,6 +235,7 @@ class Project < ActiveRecord::Base
has_many :commit_statuses has_many :commit_statuses
has_many :pipelines, class_name: 'Ci::Pipeline', inverse_of: :project has_many :pipelines, class_name: 'Ci::Pipeline', inverse_of: :project
has_many :stages, class_name: 'Ci::Stage', inverse_of: :project
# Ci::Build objects store data on the file system such as artifact files and # Ci::Build objects store data on the file system such as artifact files and
# build traces. Currently there's no efficient way of removing this data in # build traces. Currently there's no efficient way of removing this data in
...@@ -1443,8 +1444,14 @@ class Project < ActiveRecord::Base ...@@ -1443,8 +1444,14 @@ class Project < ActiveRecord::Base
Ci::Runner.from("(#{union.to_sql}) ci_runners") Ci::Runner.from("(#{union.to_sql}) ci_runners")
end end
def active_runners
strong_memoize(:active_runners) do
all_runners.active
end
end
def any_runners?(&block) def any_runners?(&block)
all_runners.active.any?(&block) active_runners.any?(&block)
end end
def valid_runners_token?(token) def valid_runners_token?(token)
...@@ -1667,12 +1674,6 @@ class Project < ActiveRecord::Base ...@@ -1667,12 +1674,6 @@ class Project < ActiveRecord::Base
import_state.update_column(:jid, nil) import_state.update_column(:jid, nil)
end end
def running_or_pending_build_count(force: false)
Rails.cache.fetch(['projects', id, 'running_or_pending_build_count'], force: force) do
builds.running_or_pending.count(:all)
end
end
# Lazy loading of the `pipeline_status` attribute # Lazy loading of the `pipeline_status` attribute
def pipeline_status def pipeline_status
@pipeline_status ||= Gitlab::Cache::Ci::ProjectPipelineStatus.load_for_project(self) @pipeline_status ||= Gitlab::Cache::Ci::ProjectPipelineStatus.load_for_project(self)
......
...@@ -277,6 +277,16 @@ class Repository ...@@ -277,6 +277,16 @@ class Repository
end end
end end
def archive_metadata(ref, storage_path, format = "tar.gz", append_sha:)
raw_repository.archive_metadata(
ref,
storage_path,
project.path,
format,
append_sha: append_sha
)
end
def expire_tags_cache def expire_tags_cache
expire_method_caches(%i(tag_names tag_count)) expire_method_caches(%i(tag_names tag_count))
@tags = nil @tags = nil
......
...@@ -2,5 +2,7 @@ class TermAgreement < ActiveRecord::Base ...@@ -2,5 +2,7 @@ class TermAgreement < ActiveRecord::Base
belongs_to :term, class_name: 'ApplicationSetting::Term' belongs_to :term, class_name: 'ApplicationSetting::Term'
belongs_to :user belongs_to :user
scope :accepted, -> { where(accepted: true) }
validates :user, :term, presence: true validates :user, :term, presence: true
end end
class PipelineDetailsEntity < PipelineEntity class PipelineDetailsEntity < PipelineEntity
expose :details do expose :details do
expose :legacy_stages, as: :stages, using: StageEntity expose :ordered_stages, as: :stages, using: StageEntity
expose :artifacts, using: BuildArtifactEntity expose :artifacts, using: BuildArtifactEntity
expose :manual_actions, using: BuildActionEntity expose :manual_actions, using: BuildActionEntity
end end
......
class PipelineSerializer < BaseSerializer class PipelineSerializer < BaseSerializer
include WithPagination include WithPagination
InvalidResourceError = Class.new(StandardError)
entity PipelineDetailsEntity entity PipelineDetailsEntity
def represent(resource, opts = {}) def represent(resource, opts = {})
if resource.is_a?(ActiveRecord::Relation) if resource.is_a?(ActiveRecord::Relation)
resource = resource.preload([ resource = resource.preload([
:stages,
:retryable_builds, :retryable_builds,
:cancelable_statuses, :cancelable_statuses,
:trigger_requests, :trigger_requests,
...@@ -22,10 +19,14 @@ class PipelineSerializer < BaseSerializer ...@@ -22,10 +19,14 @@ class PipelineSerializer < BaseSerializer
end end
if paginated? if paginated?
super(@paginator.paginate(resource), opts) resource = paginator.paginate(resource)
else
super(resource, opts)
end end
if opts.delete(:preload)
resource = Gitlab::Ci::Pipeline::Preloader.preload!(resource)
end
super(resource, opts)
end end
def represent_status(resource) def represent_status(resource)
...@@ -38,7 +39,7 @@ class PipelineSerializer < BaseSerializer ...@@ -38,7 +39,7 @@ class PipelineSerializer < BaseSerializer
def represent_stages(resource) def represent_stages(resource)
return {} unless resource.present? return {} unless resource.present?
data = represent(resource, { only: [{ details: [:stages] }] }) data = represent(resource, { only: [{ details: [:stages] }], preload: true })
data.dig(:details, :stages) || [] data.dig(:details, :stages) || []
end end
end end
module ApplicationSettings module ApplicationSettings
class UpdateService < ApplicationSettings::BaseService class UpdateService < ApplicationSettings::BaseService
<<<<<<< HEAD
prepend EE::ApplicationSettings::UpdateService prepend EE::ApplicationSettings::UpdateService
=======
>>>>>>> upstream/master
attr_reader :params, :application_setting attr_reader :params, :application_setting
def execute def execute
......
class PagesService
attr_reader :data
def initialize(data)
@data = data
end
def execute
return unless Settings.pages.enabled
return unless data[:build_name] == 'pages'
return unless data[:build_status] == 'success'
PagesWorker.perform_async(:deploy, data[:build_id])
end
end
...@@ -11,7 +11,7 @@ module Projects ...@@ -11,7 +11,7 @@ module Projects
order: { due_date: :asc, title: :asc } order: { due_date: :asc, title: :asc }
} }
finder_params[:group_ids] = [@project.group.id] if @project.group finder_params[:group_ids] = @project.group.self_and_ancestors.select(:id) if @project.group
MilestonesFinder.new(finder_params).execute.select([:iid, :title]) MilestonesFinder.new(finder_params).execute.select([:iid, :title])
end end
......
...@@ -40,7 +40,7 @@ module Projects ...@@ -40,7 +40,7 @@ module Projects
end end
def run_auto_devops_pipeline? def run_auto_devops_pipeline?
return false if project.repository.gitlab_ci_yml || !project.auto_devops.previous_changes.include?('enabled') return false if project.repository.gitlab_ci_yml || !project.auto_devops&.previous_changes&.include?('enabled')
project.auto_devops.enabled? || (project.auto_devops.enabled.nil? && Gitlab::CurrentSettings.auto_devops_enabled?) project.auto_devops.enabled? || (project.auto_devops.enabled.nil? && Gitlab::CurrentSettings.auto_devops_enabled?)
end end
......
...@@ -10,8 +10,6 @@ module ObjectStorage ...@@ -10,8 +10,6 @@ module ObjectStorage
UnknownStoreError = Class.new(StandardError) UnknownStoreError = Class.new(StandardError)
ObjectStorageUnavailable = Class.new(StandardError) ObjectStorageUnavailable = Class.new(StandardError)
DIRECT_UPLOAD_TIMEOUT = 4.hours
DIRECT_UPLOAD_EXPIRE_OFFSET = 15.minutes
TMP_UPLOAD_PATH = 'tmp/uploads'.freeze TMP_UPLOAD_PATH = 'tmp/uploads'.freeze
module Store module Store
...@@ -157,9 +155,9 @@ module ObjectStorage ...@@ -157,9 +155,9 @@ module ObjectStorage
model_class.uploader_options.dig(mount_point, :mount_on) || mount_point model_class.uploader_options.dig(mount_point, :mount_on) || mount_point
end end
def workhorse_authorize def workhorse_authorize(has_length:, maximum_size: nil)
{ {
RemoteObject: workhorse_remote_upload_options, RemoteObject: workhorse_remote_upload_options(has_length: has_length, maximum_size: maximum_size),
TempPath: workhorse_local_upload_path TempPath: workhorse_local_upload_path
}.compact }.compact
end end
...@@ -168,23 +166,16 @@ module ObjectStorage ...@@ -168,23 +166,16 @@ module ObjectStorage
File.join(self.root, TMP_UPLOAD_PATH) File.join(self.root, TMP_UPLOAD_PATH)
end end
def workhorse_remote_upload_options def workhorse_remote_upload_options(has_length:, maximum_size: nil)
return unless self.object_store_enabled? return unless self.object_store_enabled?
return unless self.direct_upload_enabled? return unless self.direct_upload_enabled?
id = [CarrierWave.generate_cache_id, SecureRandom.hex].join('-') id = [CarrierWave.generate_cache_id, SecureRandom.hex].join('-')
upload_path = File.join(TMP_UPLOAD_PATH, id) upload_path = File.join(TMP_UPLOAD_PATH, id)
connection = ::Fog::Storage.new(self.object_store_credentials) direct_upload = ObjectStorage::DirectUpload.new(self.object_store_credentials, remote_store_path, upload_path,
expire_at = Time.now + DIRECT_UPLOAD_TIMEOUT + DIRECT_UPLOAD_EXPIRE_OFFSET has_length: has_length, maximum_size: maximum_size)
options = { 'Content-Type' => 'application/octet-stream' }
{ direct_upload.to_hash.merge(ID: id)
ID: id,
Timeout: DIRECT_UPLOAD_TIMEOUT,
GetURL: connection.get_object_url(remote_store_path, upload_path, expire_at),
DeleteURL: connection.delete_object_url(remote_store_path, upload_path, expire_at),
StoreURL: connection.put_object_url(remote_store_path, upload_path, expire_at, options)
}
end end
end end
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
.col-sm-10 .col-sm-10
- checkbox_name = 'application_setting[restricted_visibility_levels][]' - checkbox_name = 'application_setting[restricted_visibility_levels][]'
= hidden_field_tag(checkbox_name) = hidden_field_tag(checkbox_name)
- restricted_level_checkboxes('restricted-visibility-help', checkbox_name).each do |level| - restricted_level_checkboxes('restricted-visibility-help', checkbox_name, class: 'form-check-input').each do |level|
.form-check .form-check
= level = level
%span.form-text.text-muted#restricted-visibility-help %span.form-text.text-muted#restricted-visibility-help
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
= f.label :import_sources, class: 'col-form-label col-sm-2' = f.label :import_sources, class: 'col-form-label col-sm-2'
.col-sm-10 .col-sm-10
= hidden_field_tag 'application_setting[import_sources][]' = hidden_field_tag 'application_setting[import_sources][]'
- import_sources_checkboxes('import-sources-help').each do |source| - import_sources_checkboxes('import-sources-help', class: 'form-check-input').each do |source|
.form-check= source .form-check= source
%span.form-text.text-muted#import-sources-help %span.form-text.text-muted#import-sources-help
Enabled sources for code import during project creation. OmniAuth must be configured for GitHub Enabled sources for code import during project creation. OmniAuth must be configured for GitHub
......
...@@ -118,8 +118,8 @@ ...@@ -118,8 +118,8 @@
.card-body .card-body
= form_for @project, url: transfer_admin_project_path(@project), method: :put do |f| = form_for @project, url: transfer_admin_project_path(@project), method: :put do |f|
.form-group.row .form-group.row
= f.label :new_namespace_id, "Namespace", class: 'col-form-label col-sm-2' = f.label :new_namespace_id, "Namespace", class: 'col-form-label col-sm-3'
.col-sm-10 .col-sm-9
.dropdown .dropdown
= dropdown_toggle('Search for Namespace', { toggle: 'dropdown', field_name: 'new_namespace_id' }, { toggle_class: 'js-namespace-select large' }) = dropdown_toggle('Search for Namespace', { toggle: 'dropdown', field_name: 'new_namespace_id' }, { toggle_class: 'js-namespace-select large' })
.dropdown-menu.dropdown-select .dropdown-menu.dropdown-select
...@@ -129,7 +129,7 @@ ...@@ -129,7 +129,7 @@
= dropdown_loading = dropdown_loading
.form-group.row .form-group.row
.offset-sm-2.col-sm-10 .offset-sm-3.col-sm-9
= f.submit 'Transfer', class: 'btn btn-primary' = f.submit 'Transfer', class: 'btn btn-primary'
.card.repository-check .card.repository-check
......
.nav-block .nav-block.activities
.controls .controls
= link_to group_path(@group, rss_url_options), class: 'btn rss-btn has-tooltip' , title: 'Subscribe' do = link_to group_path(@group, rss_url_options), class: 'btn rss-btn has-tooltip' , title: 'Subscribe' do
%i.fa.fa-rss %i.fa.fa-rss
......
This diff is collapsed.
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
= form_tag personal_access_token_import_gitea_path do = form_tag personal_access_token_import_gitea_path do
.form-group.row .form-group.row
= label_tag :gitea_host_url, 'Gitea Host URL', class: 'col-form-label col-sm-8' = label_tag :gitea_host_url, 'Gitea Host URL', class: 'col-form-label col-sm-2'
.col-sm-4 .col-sm-4
= text_field_tag :gitea_host_url, nil, placeholder: 'https://try.gitea.io', class: 'form-control' = text_field_tag :gitea_host_url, nil, placeholder: 'https://try.gitea.io', class: 'form-control'
.form-group.row .form-group.row
= label_tag :personal_access_token, 'Personal Access Token', class: 'col-form-label col-sm-8' = label_tag :personal_access_token, 'Personal Access Token', class: 'col-form-label col-sm-2'
.col-sm-4 .col-sm-4
= text_field_tag :personal_access_token, nil, class: 'form-control' = text_field_tag :personal_access_token, nil, class: 'form-control'
.form-actions .form-actions
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
= form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do = form_tag personal_access_token_import_github_path, method: :post, class: 'form-inline' do
.form-group .form-group
= text_field_tag :personal_access_token, '', class: 'form-control', placeholder: _('Personal Access Token'), size: 40 = text_field_tag :personal_access_token, '', class: 'form-control append-right-8', placeholder: _('Personal Access Token'), size: 40
= submit_tag _('List your GitHub repositories'), class: 'btn btn-success' = submit_tag _('List your GitHub repositories'), class: 'btn btn-success'
-# EE-specific start -# EE-specific start
......
...@@ -5,5 +5,5 @@ ...@@ -5,5 +5,5 @@
-# total_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li.first.page-item %li.page-item.js-first-button
= link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link' = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, remote: remote, class: 'page-link'
...@@ -4,5 +4,5 @@ ...@@ -4,5 +4,5 @@
-# total_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li.page-item.disabled %li.page-item.disabled.d-none.d-md-block
= link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link' = link_to raw(t 'views.pagination.truncate'), '#', class: 'page-link'
...@@ -5,5 +5,5 @@ ...@@ -5,5 +5,5 @@
-# total_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li.last.page-item %li.page-item.js-last-button
= link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {remote: remote, class: 'page-link'} = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {remote: remote, class: 'page-link'}
...@@ -8,5 +8,5 @@ ...@@ -8,5 +8,5 @@
- page_url = current_page.last? ? '#' : url - page_url = current_page.last? ? '#' : url
%li.page-item{ class: ('disabled' if current_page.last?) } %li.page-item.js-next-button{ class: ('disabled' if current_page.last?) }
= link_to raw(t 'views.pagination.next'), page_url, rel: 'next', remote: remote, class: 'page-link' = link_to raw(t 'views.pagination.next'), page_url, rel: 'next', remote: remote, class: 'page-link'
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
-# total_pages: total number of pages -# total_pages: total number of pages
-# per_page: number of items to fetch per page -# per_page: number of items to fetch per page
-# remote: data-remote -# remote: data-remote
%li.page-item.js-pagination-page{ class: [active_when(page.current?), ('sibling' if page.next? || page.prev?)] } %li.page-item.js-pagination-page{ class: [active_when(page.current?), ('sibling' if page.next? || page.prev?), ('d-none d-md-block' if !page.current?) ] }
= link_to page, url, { remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil, class: 'page-link' } = link_to page, url, { remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil, class: 'page-link' }
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
-# remote: data-remote -# remote: data-remote
-# paginator: the paginator that renders the pagination tags inside -# paginator: the paginator that renders the pagination tags inside
= paginator.render do = paginator.render do
.gl-pagination .gl-pagination.prepend-top-default
%ul.pagination.justify-content-center %ul.pagination.justify-content-center
- unless current_page.first? - unless current_page.first?
= first_page_tag unless total_pages < 5 # As kaminari will always show the first 5 pages = first_page_tag unless total_pages < 5 # As kaminari will always show the first 5 pages
......
...@@ -8,5 +8,5 @@ ...@@ -8,5 +8,5 @@
- page_url = current_page.first? ? '#' : url - page_url = current_page.first? ? '#' : url
%li.page-item{ class: ('disabled' if current_page.first?) } %li.page-item.js-previous-button{ class: ('disabled' if current_page.first?) }
= link_to raw(t 'views.pagination.previous'), page_url, rel: 'prev', remote: remote, class: 'page-link' = link_to raw(t 'views.pagination.previous'), page_url, rel: 'prev', remote: remote, class: 'page-link'
.gl-pagination .gl-pagination.prepend-top-default
%ul.pagination.clearfix %ul.pagination.justify-content-center
- if previous_path - if previous_path
%li.page-item.prev %li.page-item.prev
= link_to(t('views.pagination.previous'), previous_path, rel: 'prev', class: 'page-link') = link_to(t('views.pagination.previous'), previous_path, rel: 'prev', class: 'page-link')
......
...@@ -14,9 +14,9 @@ ...@@ -14,9 +14,9 @@
%div{ class: "#{container_class} limit-container-width" } %div{ class: "#{container_class} limit-container-width" }
.content{ id: "content-body" } .content{ id: "content-body" }
.panel.panel-default .card
.panel-heading .card-header
.title .card-title
= brand_header_logo = brand_header_logo
- logo_text = brand_header_logo_type - logo_text = brand_header_logo_type
- if logo_text.present? - if logo_text.present?
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
= form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f| = form_for @user, url: profile_preferences_path, remote: true, method: :put, html: { class: 'row prepend-top-default js-preferences-form' } do |f|
.col-lg-4.application-theme .col-lg-4.application-theme
%h4.prepend-top-0 %h4.prepend-top-0
s_('Preferences|Navigation theme') = s_('Preferences|Navigation theme')
%p Customize the appearance of the application header and navigation sidebar. %p Customize the appearance of the application header and navigation sidebar.
.col-lg-8.application-theme .col-lg-8.application-theme
- Gitlab::Themes.each do |theme| - Gitlab::Themes.each do |theme|
......
...@@ -49,6 +49,10 @@ ...@@ -49,6 +49,10 @@
.project-clone-holder .project-clone-holder
= render "shared/clone_panel" = render "shared/clone_panel"
- if show_xcode_link?(@project)
.project-action-button.project-xcode.inline
= render "projects/buttons/xcode_link"
- if current_user - if current_user
- if can?(current_user, :download_code, @project) - if can?(current_user, :download_code, @project)
= render 'projects/buttons/download', project: @project, ref: @ref = render 'projects/buttons/download', project: @project, ref: @ref
......
.file-content.blob_file.blob-no-preview .file-content.blob_file.blob-no-preview
.center.render-error.vertical-center .center.render-error
= link_to blob_raw_path do = link_to blob_raw_path do
%h1.light %h1.light
= sprite_icon('download') = sprite_icon('download')
......
%a.btn.btn-default{ href: xcode_uri_to_repo(@project) }
= _("Open in Xcode")
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
-# Only show it in the first page -# Only show it in the first page
- hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1') - hide = @available_labels.empty? || (params[:page].present? && params[:page] != '1')
.prioritized-labels{ class: ('hide' if hide) } .prioritized-labels{ class: ('hide' if hide) }
%h5 Prioritized Labels %h5.prepend-top-10 Prioritized Labels
%ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_project_labels_path(@project) } %ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_project_labels_path(@project) }
#js-priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty?}" } #js-priority-labels-empty-state{ class: "#{'hidden' unless @prioritized_labels.empty?}" }
= render 'shared/empty_states/priority_labels' = render 'shared/empty_states/priority_labels'
......
...@@ -34,16 +34,16 @@ ...@@ -34,16 +34,16 @@
.col-lg-9.js-toggle-container .col-lg-9.js-toggle-container
%ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' } %ul.nav.nav-tabs.nav-links.gitlab-tabs{ role: 'tablist' }
%li{ class: active_when(active_tab == 'blank'), role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link.active{ href: '#blank-project-pane', id: 'blank-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Blank project %span.d-none.d-sm-block Blank project
%span.d-block.d-sm-none Blank %span.d-block.d-sm-none Blank
%li{ class: active_when(active_tab == 'template'), role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#create-from-template-pane', id: 'create-from-template-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Create from template %span.d-none.d-sm-block Create from template
%span.d-block.d-sm-none Template %span.d-block.d-sm-none Template
%li{ class: active_when(active_tab == 'import'), role: 'presentation' } %li.nav-item{ role: 'presentation' }
%a{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' } %a.nav-link{ href: '#import-project-pane', id: 'import-project-tab', data: { toggle: 'tab' }, role: 'tab' }
%span.d-none.d-sm-block Import project %span.d-none.d-sm-block Import project
%span.d-block.d-sm-none Import %span.d-block.d-sm-none Import
-# EE-specific start -# EE-specific start
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
.errors-holder .errors-holder
.card-body .card-body
%p %p
Removing the pages will prevent from exposing them to outside world. Removing pages will prevent them from being exposed to the outside world.
.form-actions .form-actions
= link_to 'Remove pages', project_pages_path(@project), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove" = link_to 'Remove pages', project_pages_path(@project), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove"
- else - else
......
- with_label = local_assigns.fetch(:with_label, true) - with_label = local_assigns.fetch(:with_label, true)
.form-group.visibility-level-setting .form-group.row.visibility-level-setting
- if with_label - if with_label
= f.label :visibility_level, class: 'col-form-label col-sm-2' do = f.label :visibility_level, class: 'col-form-label col-sm-2' do
Visibility Level Visibility Level
= link_to icon('question-circle'), help_page_path("public_access/public_access") = link_to icon('question-circle'), help_page_path("public_access/public_access")
%div{ :class => ("col-sm-10" if with_label) } %div{ :class => (with_label ? "col-sm-10" : "col-sm-12") }
- if can_change_visibility_level - if can_change_visibility_level
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model) = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
- else - else
......
...@@ -15,15 +15,15 @@ ...@@ -15,15 +15,15 @@
- else - else
= render "shared/issuable/form/metadata_merge_request_assignee", issuable: issuable, form: form, has_due_date: has_due_date = render "shared/issuable/form/metadata_merge_request_assignee", issuable: issuable, form: form, has_due_date: has_due_date
.form-group.row.issue-milestone .form-group.row.issue-milestone
= form.label :milestone_id, "Milestone", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-2"}" = form.label :milestone_id, "Milestone", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
.col-10{ class: ("col-md-8" if has_due_date) } .col-sm-10{ class: ("col-md-8" if has_due_date) }
.issuable-form-select-holder .issuable-form-select-holder
= render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone" = render "shared/issuable/milestone_dropdown", selected: issuable.milestone, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false, show_started: false, extra_class: "js-issuable-form-dropdown js-dropdown-keep-input", dropdown_title: "Select milestone"
.form-group.row .form-group.row
- has_labels = @labels && @labels.any? - has_labels = @labels && @labels.any?
= form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-2"}" = form.label :label_ids, "Labels", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
= form.hidden_field :label_ids, multiple: true, value: '' = form.hidden_field :label_ids, multiple: true, value: ''
.col-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } .col-sm-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
.issuable-form-select-holder .issuable-form-select-holder
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label" = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label"
......
- redirect_params = { redirect: @redirect } if @redirect - redirect_params = { redirect: @redirect } if @redirect
.panel-content.rendered-terms .card-body.rendered-terms
= markdown_field(@term, :terms) = markdown_field(@term, :terms)
.row-content-block.footer-block.clearfix .card-footer.footer-block.clearfix
- if can?(current_user, :accept_terms, @term) - if can?(current_user, :accept_terms, @term)
.float-right .float-right
= button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do = button_to accept_term_path(@term, redirect_params), class: 'btn btn-success prepend-left-8' do
= _('Accept terms') = _('Accept terms')
- else
.pull-right
= link_to root_path, class: 'btn btn-success prepend-left-8' do
= _('Continue')
- if can?(current_user, :decline_terms, @term) - if can?(current_user, :decline_terms, @term)
.float-right .float-right
= button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do = button_to decline_term_path(@term, redirect_params), class: 'btn btn-default prepend-left-8' do
......
---
title: Include milestones from parent groups when assigning a milestone to an issue or merge request
merge_request:
author:
type: changed
---
title: Fix repository archive generation when hashed storage is enabled
merge_request: 19441
author:
type: fixed
---
title: Add Open in Xcode link for xcode repositories
merge_request:
author:
type: added
---
title: Check for nil AutoDevOps when saving project CI/CD settings.
merge_request: 19190
author:
type: fixed
---
title: Add flash notice if user has already accepted terms and allow users to continue
to root path
merge_request: 19156
author:
type: changed
---
title: Update email_spec to 2.2.0
merge_request: 19164
author: Takuya Noguchi
type: other
---
title: Add background migrations for archiving legacy job traces
merge_request: 19194
author:
type: performance
---
title: Move PR IO operations out of a transaction
merge_request:
author:
type: performance
---
title: Add support for smarter system notes
merge_request: 17164
author:
type: changed
---
title: Optimise PagesWorker usage
merge_request:
author:
type: performance
---
title: Update runner cached informations without performing validations
merge_request:
author:
type: performance
---
title: Adjust insufficient diff hunks being persisted on NoteDiffFile
merge_request:
author:
type: fixed
---
title: Support direct_upload with S3 Multipart uploads
merge_request:
author:
type: added
---
title: Support rails5 in postgres indexes function and fix some migrations
merge_request: 19400
author: Jasper Maes
type: fixed
---
title: Add migration to disable the usage of DSA keys
merge_request: 19299
author:
type: other
---
title: Remove unused running_or_pending_build_count
merge_request:
author:
type: performance
---
title: Remove N+1 query for author in issues API
merge_request:
author:
type: performance
---
title: Eliminate N+1 queries with authors and push_data_payload in Events API
merge_request:
author:
type: performance
---
title: Eliminate N+1 queries for CI job artifacts in /api/prjoects/:id/pipelines/:pipeline_id/jobs
merge_request:
author:
type: performance
artifacts_object_store = Gitlab.config.artifacts.object_store
if artifacts_object_store.enabled &&
artifacts_object_store.direct_upload &&
artifacts_object_store.connection&.provider.to_s != 'Google'
raise "Only 'Google' is supported as a object storage provider when 'direct_upload' of artifacts is used"
end
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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