Merge remote-tracking branch 'origin/master' into 18608-lock-issues
This commit is contained in:
commit
ff7b545c8e
|
@ -128,7 +128,7 @@ stages:
|
|||
- export CACHE_CLASSES=true
|
||||
- cp ${KNAPSACK_SPINACH_SUITE_REPORT_PATH} ${KNAPSACK_REPORT_PATH}
|
||||
- scripts/gitaly-test-spawn
|
||||
- knapsack spinach "-r rerun" || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)'
|
||||
- knapsack spinach "-r rerun" -b || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -b -r rerun $(cat tmp/spinach-rerun.txt)'
|
||||
artifacts:
|
||||
expire_in: 31d
|
||||
when: always
|
||||
|
@ -174,7 +174,8 @@ build-package:
|
|||
# Review docs base
|
||||
.review-docs: &review-docs
|
||||
image: ruby:2.4-alpine
|
||||
before_script: []
|
||||
before_script:
|
||||
- gem install gitlab --no-doc
|
||||
services: []
|
||||
variables:
|
||||
SETUP_DB: "false"
|
||||
|
@ -193,10 +194,9 @@ review-docs-deploy:
|
|||
name: review-docs/$CI_COMMIT_REF_NAME
|
||||
# DOCS_REVIEW_APPS_DOMAIN and DOCS_GITLAB_REPO_SUFFIX are secret variables
|
||||
# Discussion: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/14236/diffs#note_40140693
|
||||
url: http://$CI_COMMIT_REF_SLUG-built-from-ce-ee.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
|
||||
url: http://preview-$CI_COMMIT_REF_SLUG.$DOCS_REVIEW_APPS_DOMAIN/$DOCS_GITLAB_REPO_SUFFIX
|
||||
on_stop: review-docs-cleanup
|
||||
script:
|
||||
- gem install gitlab --no-doc
|
||||
- scripts/trigger-build-docs deploy
|
||||
|
||||
# Cleanup remote environment of gitlab-docs
|
||||
|
@ -207,7 +207,6 @@ review-docs-cleanup:
|
|||
name: review-docs/$CI_COMMIT_REF_NAME
|
||||
action: stop
|
||||
script:
|
||||
- gem install gitlab --no-doc
|
||||
- scripts/trigger-build-docs cleanup
|
||||
|
||||
# Retrieve knapsack and rspec_flaky reports
|
||||
|
@ -413,12 +412,12 @@ downtime_check:
|
|||
|
||||
ee_compat_check:
|
||||
<<: *rake-exec
|
||||
only:
|
||||
- branches@gitlab-org/gitlab-ce
|
||||
except:
|
||||
- master
|
||||
- tags
|
||||
- /^[\d-]+-stable(-ee)?/
|
||||
- branches@gitlab-org/gitlab-ee
|
||||
- branches@gitlab/gitlab-ee
|
||||
allow_failure: yes
|
||||
cache:
|
||||
key: "ee_compat_check_repo"
|
||||
|
@ -517,6 +516,12 @@ db:seed_fu-mysql:
|
|||
<<: *db-seed_fu
|
||||
<<: *use-mysql
|
||||
|
||||
db:check-schema-pg:
|
||||
<<: *db-migrate-reset
|
||||
<<: *use-pg
|
||||
script:
|
||||
- source scripts/schema_changed.sh
|
||||
|
||||
# Frontend-related jobs
|
||||
gitlab:assets:compile:
|
||||
<<: *dedicated-runner
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.0.0
|
||||
3.1.0
|
||||
|
|
1
Gemfile
1
Gemfile
|
@ -362,6 +362,7 @@ group :test do
|
|||
gem 'sham_rack', '~> 1.3.6'
|
||||
gem 'timecop', '~> 0.8.0'
|
||||
gem 'concurrent-ruby', '~> 1.0.5'
|
||||
gem 'test-prof', '~> 0.2.5'
|
||||
end
|
||||
|
||||
gem 'octokit', '~> 4.6.2'
|
||||
|
|
|
@ -882,6 +882,7 @@ GEM
|
|||
ffi
|
||||
sysexits (1.2.0)
|
||||
temple (0.7.7)
|
||||
test-prof (0.2.5)
|
||||
test_after_commit (1.1.0)
|
||||
activerecord (>= 3.2)
|
||||
text (1.3.1)
|
||||
|
@ -1163,6 +1164,7 @@ DEPENDENCIES
|
|||
stackprof (~> 0.2.10)
|
||||
state_machines-activerecord (~> 0.4.0)
|
||||
sys-filesystem (~> 1.1.6)
|
||||
test-prof (~> 0.2.5)
|
||||
test_after_commit (~> 1.1)
|
||||
thin (~> 1.7.0)
|
||||
timecop (~> 0.8.0)
|
||||
|
|
6
LICENSE
6
LICENSE
|
@ -1,5 +1,7 @@
|
|||
Copyright (c) 2011-2017 GitLab B.V.
|
||||
|
||||
With regard to the GitLab Software:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
|
@ -17,3 +19,7 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
For all third party components incorporated into the GitLab Software, those
|
||||
components are licensed under the original license provided by the owner of the
|
||||
applicable component.
|
|
@ -73,7 +73,7 @@
|
|||
</span>
|
||||
<a
|
||||
v-if="deployKey.can_edit"
|
||||
class="btn btn-small"
|
||||
class="btn btn-sm"
|
||||
:href="editDeployKeyPath"
|
||||
>
|
||||
Edit
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
import Vue from 'vue';
|
||||
|
||||
import '../mixins/discussion';
|
||||
|
||||
const JumpToDiscussion = Vue.extend({
|
||||
mixins: [DiscussionMixins],
|
||||
props: {
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
import Vue from 'vue';
|
||||
|
||||
import '../mixins/discussion';
|
||||
|
||||
window.ResolveCount = Vue.extend({
|
||||
mixins: [DiscussionMixins],
|
||||
props: {
|
||||
|
|
|
@ -1,61 +0,0 @@
|
|||
import Cookies from 'js-cookie';
|
||||
import _ from 'underscore';
|
||||
import {
|
||||
getCookieName,
|
||||
getSelector,
|
||||
hidePopover,
|
||||
setupDismissButton,
|
||||
mouseenter,
|
||||
mouseleave,
|
||||
} from './feature_highlight_helper';
|
||||
|
||||
export const setupFeatureHighlightPopover = (id, debounceTimeout = 300) => {
|
||||
const $selector = $(getSelector(id));
|
||||
const $parent = $selector.parent();
|
||||
const $popoverContent = $parent.siblings('.feature-highlight-popover-content');
|
||||
const hideOnScroll = hidePopover.bind($selector);
|
||||
const debouncedMouseleave = _.debounce(mouseleave, debounceTimeout);
|
||||
|
||||
$selector
|
||||
// Setup popover
|
||||
.data('content', $popoverContent.prop('outerHTML'))
|
||||
.popover({
|
||||
html: true,
|
||||
// Override the existing template to add custom CSS classes
|
||||
template: `
|
||||
<div class="popover feature-highlight-popover" role="tooltip">
|
||||
<div class="arrow"></div>
|
||||
<div class="popover-content"></div>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
.on('mouseenter', mouseenter)
|
||||
.on('mouseleave', debouncedMouseleave)
|
||||
.on('inserted.bs.popover', setupDismissButton)
|
||||
.on('show.bs.popover', () => {
|
||||
window.addEventListener('scroll', hideOnScroll);
|
||||
})
|
||||
.on('hide.bs.popover', () => {
|
||||
window.removeEventListener('scroll', hideOnScroll);
|
||||
})
|
||||
// Display feature highlight
|
||||
.removeAttr('disabled');
|
||||
};
|
||||
|
||||
export const shouldHighlightFeature = (id) => {
|
||||
const element = document.querySelector(getSelector(id));
|
||||
const previouslyDismissed = Cookies.get(getCookieName(id)) === 'true';
|
||||
|
||||
return element && !previouslyDismissed;
|
||||
};
|
||||
|
||||
export const highlightFeatures = (highlightOrder) => {
|
||||
const featureId = highlightOrder.find(shouldHighlightFeature);
|
||||
|
||||
if (featureId) {
|
||||
setupFeatureHighlightPopover(featureId);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
|
@ -1,57 +0,0 @@
|
|||
import Cookies from 'js-cookie';
|
||||
|
||||
export const getCookieName = cookieId => `feature-highlighted-${cookieId}`;
|
||||
export const getSelector = highlightId => `.js-feature-highlight[data-highlight=${highlightId}]`;
|
||||
|
||||
export const showPopover = function showPopover() {
|
||||
if (this.hasClass('js-popover-show')) {
|
||||
return false;
|
||||
}
|
||||
this.popover('show');
|
||||
this.addClass('disable-animation js-popover-show');
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const hidePopover = function hidePopover() {
|
||||
if (!this.hasClass('js-popover-show')) {
|
||||
return false;
|
||||
}
|
||||
this.popover('hide');
|
||||
this.removeClass('disable-animation js-popover-show');
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
export const dismiss = function dismiss(cookieId) {
|
||||
Cookies.set(getCookieName(cookieId), true);
|
||||
hidePopover.call(this);
|
||||
this.hide();
|
||||
};
|
||||
|
||||
export const mouseleave = function mouseleave() {
|
||||
if (!$('.popover:hover').length > 0) {
|
||||
const $featureHighlight = $(this);
|
||||
hidePopover.call($featureHighlight);
|
||||
}
|
||||
};
|
||||
|
||||
export const mouseenter = function mouseenter() {
|
||||
const $featureHighlight = $(this);
|
||||
|
||||
const showedPopover = showPopover.call($featureHighlight);
|
||||
if (showedPopover) {
|
||||
$('.popover')
|
||||
.on('mouseleave', mouseleave.bind($featureHighlight));
|
||||
}
|
||||
};
|
||||
|
||||
export const setupDismissButton = function setupDismissButton() {
|
||||
const popoverId = this.getAttribute('aria-describedby');
|
||||
const cookieId = this.dataset.highlight;
|
||||
const $popover = $(this);
|
||||
const dismissWrapper = dismiss.bind($popover, cookieId);
|
||||
|
||||
$(`#${popoverId} .dismiss-feature-highlight`)
|
||||
.on('click', dismissWrapper);
|
||||
};
|
|
@ -1,12 +0,0 @@
|
|||
import { highlightFeatures } from './feature_highlight';
|
||||
import bp from '../breakpoints';
|
||||
|
||||
const highlightOrder = ['issue-boards'];
|
||||
|
||||
export default function domContentLoaded(order) {
|
||||
if (bp.getBreakpointSize() === 'lg') {
|
||||
highlightFeatures(order);
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', domContentLoaded.bind(this, highlightOrder));
|
|
@ -1,68 +1,61 @@
|
|||
import _ from 'underscore';
|
||||
|
||||
(() => {
|
||||
/*
|
||||
* TODO: Make these methods more configurable (e.g. stringifyTime condensed or
|
||||
* non-condensed, abbreviateTimelengths)
|
||||
* */
|
||||
/*
|
||||
* TODO: Make these methods more configurable (e.g. stringifyTime condensed or
|
||||
* non-condensed, abbreviateTimelengths)
|
||||
* */
|
||||
|
||||
const utils = window.gl.utils = gl.utils || {};
|
||||
const prettyTime = utils.prettyTime = {
|
||||
/*
|
||||
* Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
|
||||
* Seconds can be negative or positive, zero or non-zero. Can be configured for any day
|
||||
* or week length.
|
||||
*/
|
||||
parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) {
|
||||
const DAYS_PER_WEEK = daysPerWeek;
|
||||
const HOURS_PER_DAY = hoursPerDay;
|
||||
const MINUTES_PER_HOUR = 60;
|
||||
const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
/*
|
||||
* Accepts seconds and returns a timeObject { weeks: #, days: #, hours: #, minutes: # }
|
||||
* Seconds can be negative or positive, zero or non-zero. Can be configured for any day
|
||||
* or week length.
|
||||
*/
|
||||
|
||||
const timePeriodConstraints = {
|
||||
weeks: MINUTES_PER_WEEK,
|
||||
days: MINUTES_PER_DAY,
|
||||
hours: MINUTES_PER_HOUR,
|
||||
minutes: 1,
|
||||
};
|
||||
export function parseSeconds(seconds, { daysPerWeek = 5, hoursPerDay = 8 } = {}) {
|
||||
const DAYS_PER_WEEK = daysPerWeek;
|
||||
const HOURS_PER_DAY = hoursPerDay;
|
||||
const MINUTES_PER_HOUR = 60;
|
||||
const MINUTES_PER_WEEK = DAYS_PER_WEEK * HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
const MINUTES_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR;
|
||||
|
||||
let unorderedMinutes = prettyTime.secondsToMinutes(seconds);
|
||||
|
||||
return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => {
|
||||
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
|
||||
|
||||
unorderedMinutes -= (periodCount * minutesPerPeriod);
|
||||
|
||||
return periodCount;
|
||||
});
|
||||
},
|
||||
|
||||
/*
|
||||
* Accepts a timeObject and returns a condensed string representation of it
|
||||
* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
|
||||
*/
|
||||
|
||||
stringifyTime(timeObject) {
|
||||
const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => {
|
||||
const isNonZero = !!unitValue;
|
||||
return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
|
||||
}, '').trim();
|
||||
return reducedTime.length ? reducedTime : '0m';
|
||||
},
|
||||
|
||||
/*
|
||||
* Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
|
||||
* the first non-zero unit/value pair.
|
||||
*/
|
||||
|
||||
abbreviateTime(timeStr) {
|
||||
return timeStr.split(' ')
|
||||
.filter(unitStr => unitStr.charAt(0) !== '0')[0];
|
||||
},
|
||||
|
||||
secondsToMinutes(seconds) {
|
||||
return Math.abs(seconds / 60);
|
||||
},
|
||||
const timePeriodConstraints = {
|
||||
weeks: MINUTES_PER_WEEK,
|
||||
days: MINUTES_PER_DAY,
|
||||
hours: MINUTES_PER_HOUR,
|
||||
minutes: 1,
|
||||
};
|
||||
})(window.gl || (window.gl = {}));
|
||||
|
||||
let unorderedMinutes = Math.abs(seconds / MINUTES_PER_HOUR);
|
||||
|
||||
return _.mapObject(timePeriodConstraints, (minutesPerPeriod) => {
|
||||
const periodCount = Math.floor(unorderedMinutes / minutesPerPeriod);
|
||||
|
||||
unorderedMinutes -= (periodCount * minutesPerPeriod);
|
||||
|
||||
return periodCount;
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepts a timeObject (see parseSeconds) and returns a condensed string representation of it
|
||||
* (e.g. '1w 2d 3h 1m' or '1h 30m'). Zero value units are not included.
|
||||
*/
|
||||
|
||||
export function stringifyTime(timeObject) {
|
||||
const reducedTime = _.reduce(timeObject, (memo, unitValue, unitName) => {
|
||||
const isNonZero = !!unitValue;
|
||||
return isNonZero ? `${memo} ${unitValue}${unitName.charAt(0)}` : memo;
|
||||
}, '').trim();
|
||||
return reducedTime.length ? reducedTime : '0m';
|
||||
}
|
||||
|
||||
/*
|
||||
* Accepts a time string of any size (e.g. '1w 2d 3h 5m' or '1w 2d') and returns
|
||||
* the first non-zero unit/value pair.
|
||||
*/
|
||||
|
||||
export function abbreviateTime(timeStr) {
|
||||
return timeStr.split(' ')
|
||||
.filter(unitStr => unitStr.charAt(0) !== '0')[0];
|
||||
}
|
||||
|
||||
|
|
|
@ -101,7 +101,6 @@ import './label_manager';
|
|||
import './labels';
|
||||
import './labels_select';
|
||||
import './layout_nav';
|
||||
import './feature_highlight/feature_highlight_options';
|
||||
import LazyLoader from './lazy_loader';
|
||||
import './line_highlighter';
|
||||
import './logo';
|
||||
|
|
|
@ -11,6 +11,7 @@ export default class NewNavSidebar {
|
|||
initDomElements() {
|
||||
this.$page = $('.page-with-sidebar');
|
||||
this.$sidebar = $('.nav-sidebar');
|
||||
this.$innerScroll = $('.nav-sidebar-inner-scroll', this.$sidebar);
|
||||
this.$overlay = $('.mobile-overlay');
|
||||
this.$openSidebar = $('.toggle-mobile-nav');
|
||||
this.$closeSidebar = $('.close-nav-button');
|
||||
|
@ -55,6 +56,16 @@ export default class NewNavSidebar {
|
|||
this.$page.toggleClass('page-with-icon-sidebar', breakpoint === 'sm' ? true : collapsed);
|
||||
}
|
||||
NewNavSidebar.setCollapsedCookie(collapsed);
|
||||
|
||||
this.toggleSidebarOverflow();
|
||||
}
|
||||
|
||||
toggleSidebarOverflow() {
|
||||
if (this.$innerScroll.prop('scrollHeight') > this.$innerScroll.prop('offsetHeight')) {
|
||||
this.$innerScroll.css('overflow-y', 'scroll');
|
||||
} else {
|
||||
this.$innerScroll.css('overflow-y', '');
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */
|
||||
/* global Mousetrap */
|
||||
import Cookies from 'js-cookie';
|
||||
import Mousetrap from 'mousetrap';
|
||||
|
||||
import findAndFollowLink from './shortcuts_dashboard_navigation';
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import stopwatchSvg from 'icons/_icon_stopwatch.svg';
|
||||
|
||||
import '../../../lib/utils/pretty_time';
|
||||
import { abbreviateTime } from '../../../lib/utils/pretty_time';
|
||||
|
||||
export default {
|
||||
name: 'time-tracking-collapsed-state',
|
||||
|
@ -79,7 +78,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
abbreviateTime(timeStr) {
|
||||
return gl.utils.prettyTime.abbreviateTime(timeStr);
|
||||
return abbreviateTime(timeStr);
|
||||
},
|
||||
},
|
||||
template: `
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import '../../../lib/utils/pretty_time';
|
||||
|
||||
const prettyTime = gl.utils.prettyTime;
|
||||
import { parseSeconds, stringifyTime } from '../../../lib/utils/pretty_time';
|
||||
|
||||
export default {
|
||||
name: 'time-tracking-comparison-pane',
|
||||
|
@ -23,12 +21,12 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
parsedRemaining() {
|
||||
parsedTimeRemaining() {
|
||||
const diffSeconds = this.timeEstimate - this.timeSpent;
|
||||
return prettyTime.parseSeconds(diffSeconds);
|
||||
return parseSeconds(diffSeconds);
|
||||
},
|
||||
timeRemainingHumanReadable() {
|
||||
return prettyTime.stringifyTime(this.parsedRemaining);
|
||||
return stringifyTime(this.parsedTimeRemaining);
|
||||
},
|
||||
timeRemainingTooltip() {
|
||||
const prefix = this.timeRemainingMinutes < 0 ? 'Over by' : 'Time remaining:';
|
||||
|
@ -44,13 +42,6 @@ export default {
|
|||
timeRemainingStatusClass() {
|
||||
return this.timeEstimate >= this.timeSpent ? 'within_estimate' : 'over_estimate';
|
||||
},
|
||||
/* Parsed time values */
|
||||
parsedEstimate() {
|
||||
return prettyTime.parseSeconds(this.timeEstimate);
|
||||
},
|
||||
parsedSpent() {
|
||||
return prettyTime.parseSeconds(this.timeSpent);
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div class="time-tracking-comparison-pane">
|
||||
|
|
|
@ -72,12 +72,12 @@ export default {
|
|||
<a
|
||||
href="#modal_merge_info"
|
||||
data-toggle="modal"
|
||||
class="btn btn-small inline">
|
||||
class="btn btn-sm inline">
|
||||
Check out branch
|
||||
</a>
|
||||
<span class="dropdown prepend-left-10">
|
||||
<a
|
||||
class="btn btn-small inline dropdown-toggle"
|
||||
class="btn btn-sm inline dropdown-toggle"
|
||||
data-toggle="dropdown"
|
||||
aria-label="Download as"
|
||||
role="button">
|
||||
|
|
|
@ -12,6 +12,9 @@ export default {
|
|||
ciIcon,
|
||||
},
|
||||
computed: {
|
||||
hasPipeline() {
|
||||
return this.mr.pipeline && Object.keys(this.mr.pipeline).length > 0;
|
||||
},
|
||||
hasCIError() {
|
||||
const { hasCI, ciStatus } = this.mr;
|
||||
|
||||
|
@ -28,7 +31,9 @@ export default {
|
|||
},
|
||||
},
|
||||
template: `
|
||||
<div class="mr-widget-heading">
|
||||
<div
|
||||
v-if="hasPipeline || hasCIError"
|
||||
class="mr-widget-heading">
|
||||
<div class="ci-widget media">
|
||||
<template v-if="hasCIError">
|
||||
<div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-10">
|
||||
|
@ -40,7 +45,7 @@ export default {
|
|||
Could not connect to the CI server. Please check your settings and try again
|
||||
</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-else-if="hasPipeline">
|
||||
<div class="ci-status-icon append-right-10">
|
||||
<a
|
||||
class="icon-link"
|
||||
|
|
|
@ -27,7 +27,7 @@ export default {
|
|||
<button
|
||||
v-if="showDisabledButton"
|
||||
type="button"
|
||||
class="btn btn-success btn-small"
|
||||
class="btn btn-success btn-sm"
|
||||
disabled="true">
|
||||
Merge
|
||||
</button>
|
||||
|
|
|
@ -11,7 +11,7 @@ export default {
|
|||
<status-icon status="failed" />
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success btn-small"
|
||||
class="btn btn-success btn-sm"
|
||||
disabled="true">
|
||||
Merge
|
||||
</button>
|
||||
|
|
|
@ -29,6 +29,9 @@ export default {
|
|||
statusIcon,
|
||||
},
|
||||
computed: {
|
||||
shouldShowMergeWhenPipelineSucceedsText() {
|
||||
return this.mr.isPipelineActive;
|
||||
},
|
||||
commitMessageLinkTitle() {
|
||||
const withDesc = 'Include description in commit message';
|
||||
const withoutDesc = "Don't include description in commit message";
|
||||
|
@ -36,7 +39,7 @@ export default {
|
|||
return this.useCommitMessageWithDescription ? withoutDesc : withDesc;
|
||||
},
|
||||
mergeButtonClass() {
|
||||
const defaultClass = 'btn btn-small btn-success accept-merge-request';
|
||||
const defaultClass = 'btn btn-sm btn-success accept-merge-request';
|
||||
const failedClass = `${defaultClass} btn-danger`;
|
||||
const inActionClass = `${defaultClass} btn-info`;
|
||||
const { pipeline, isPipelineActive, isPipelineFailed, hasCI, ciStatus } = this.mr;
|
||||
|
@ -56,7 +59,7 @@ export default {
|
|||
mergeButtonText() {
|
||||
if (this.isMergingImmediately) {
|
||||
return 'Merge in progress';
|
||||
} else if (this.mr.isPipelineActive) {
|
||||
} else if (this.shouldShowMergeWhenPipelineSucceedsText) {
|
||||
return 'Merge when pipeline succeeds';
|
||||
}
|
||||
|
||||
|
@ -68,7 +71,7 @@ export default {
|
|||
isMergeButtonDisabled() {
|
||||
const { commitMessage } = this;
|
||||
return Boolean(!commitMessage.length
|
||||
|| !this.isMergeAllowed()
|
||||
|| !this.shouldShowMergeControls()
|
||||
|| this.isMakingRequest
|
||||
|| this.mr.preventMerge);
|
||||
},
|
||||
|
@ -82,7 +85,12 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
isMergeAllowed() {
|
||||
return !(this.mr.onlyAllowMergeIfPipelineSucceeds && this.mr.isPipelineFailed);
|
||||
return !this.mr.onlyAllowMergeIfPipelineSucceeds ||
|
||||
this.mr.isPipelinePassing ||
|
||||
this.mr.isPipelineSkipped;
|
||||
},
|
||||
shouldShowMergeControls() {
|
||||
return this.isMergeAllowed() || this.shouldShowMergeWhenPipelineSucceedsText;
|
||||
},
|
||||
updateCommitMessage() {
|
||||
const cmwd = this.mr.commitMessageWithDescription;
|
||||
|
@ -202,8 +210,8 @@ export default {
|
|||
<div class="mr-widget-body media">
|
||||
<status-icon status="success" />
|
||||
<div class="media-body">
|
||||
<div class="media space-children">
|
||||
<span class="btn-group">
|
||||
<div class="mr-widget-body-controls media space-children">
|
||||
<span class="btn-group append-bottom-5">
|
||||
<button
|
||||
@click="handleMergeButtonClick()"
|
||||
:disabled="isMergeButtonDisabled"
|
||||
|
@ -219,7 +227,7 @@ export default {
|
|||
v-if="shouldShowMergeOptionsDropdown"
|
||||
:disabled="isMergeButtonDisabled"
|
||||
type="button"
|
||||
class="btn btn-small btn-info dropdown-toggle js-merge-moment"
|
||||
class="btn btn-sm btn-info dropdown-toggle js-merge-moment"
|
||||
data-toggle="dropdown"
|
||||
aria-label="Select merge moment">
|
||||
<i
|
||||
|
@ -260,8 +268,8 @@ export default {
|
|||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
<div class="media-body space-children">
|
||||
<template v-if="isMergeAllowed()">
|
||||
<div class="media-body-wrap space-children">
|
||||
<template v-if="shouldShowMergeControls()">
|
||||
<label>
|
||||
<input
|
||||
id="remove-source-branch-input"
|
||||
|
@ -286,7 +294,7 @@ export default {
|
|||
</template>
|
||||
<template v-else>
|
||||
<span class="bold">
|
||||
The pipeline for this merge request failed. Please retry the job or push a new commit to fix the failure
|
||||
The pipeline for this merge request has not succeeded yet
|
||||
</span>
|
||||
</template>
|
||||
</div>
|
||||
|
|
|
@ -57,7 +57,7 @@ export default {
|
|||
return stateMaps.statesToShowHelpWidget.indexOf(this.mr.state) > -1;
|
||||
},
|
||||
shouldRenderPipelines() {
|
||||
return Object.keys(this.mr.pipeline).length || this.mr.hasCI;
|
||||
return this.mr.hasCI;
|
||||
},
|
||||
shouldRenderRelatedLinks() {
|
||||
return this.mr.relatedLinks;
|
||||
|
|
|
@ -85,7 +85,9 @@ export default class MergeRequestStore {
|
|||
this.ciEnvironmentsStatusPath = data.ci_environments_status_path;
|
||||
this.hasCI = data.has_ci;
|
||||
this.ciStatus = data.ci_status;
|
||||
this.isPipelineFailed = this.ciStatus ? (this.ciStatus === 'failed' || this.ciStatus === 'canceled') : false;
|
||||
this.isPipelineFailed = this.ciStatus === 'failed' || this.ciStatus === 'canceled';
|
||||
this.isPipelinePassing = this.ciStatus === 'success' || this.ciStatus === 'success_with_warnings';
|
||||
this.isPipelineSkipped = this.ciStatus === 'skipped';
|
||||
this.pipelineDetailedStatus = pipelineStatus;
|
||||
this.isPipelineActive = data.pipeline ? data.pipeline.active : false;
|
||||
this.isPipelineBlocked = pipelineStatus ? pipelineStatus.group === 'manual' : false;
|
||||
|
|
|
@ -52,4 +52,3 @@
|
|||
@import "framework/snippets";
|
||||
@import "framework/memory_graph";
|
||||
@import "framework/responsive-tables";
|
||||
@import "framework/feature_highlight";
|
||||
|
|
|
@ -46,15 +46,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
@mixin btn-svg {
|
||||
svg {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin btn-color($light, $border-light, $normal, $border-normal, $dark, $border-dark, $color) {
|
||||
background-color: $light;
|
||||
border-color: $border-light;
|
||||
|
@ -132,7 +123,6 @@
|
|||
.btn {
|
||||
@include btn-default;
|
||||
@include btn-white;
|
||||
@include btn-svg;
|
||||
|
||||
color: $gl-text-color;
|
||||
|
||||
|
@ -140,7 +130,6 @@
|
|||
outline: 0;
|
||||
}
|
||||
|
||||
&.btn-small,
|
||||
&.btn-sm {
|
||||
padding: 4px 10px;
|
||||
font-size: 13px;
|
||||
|
@ -232,6 +221,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
svg,
|
||||
.fa {
|
||||
&:not(:last-child) {
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
.feature-highlight {
|
||||
position: relative;
|
||||
margin-left: $gl-padding;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-color: $blue-500;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 0 rgba($blue-500, 0.4);
|
||||
animation: pulse-highlight 2s infinite;
|
||||
}
|
||||
|
||||
&:hover::before,
|
||||
&.disable-animation::before {
|
||||
animation: none;
|
||||
}
|
||||
|
||||
&[disabled]::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.is-showing-fly-out {
|
||||
.feature-highlight {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.feature-highlight-popover-content {
|
||||
display: none;
|
||||
|
||||
hr {
|
||||
margin: $gl-padding * 0.5 0;
|
||||
}
|
||||
|
||||
.btn-link {
|
||||
@include btn-svg;
|
||||
|
||||
svg path {
|
||||
fill: currentColor;
|
||||
}
|
||||
}
|
||||
|
||||
.dismiss-feature-highlight {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
svg:first-child {
|
||||
width: 100%;
|
||||
background-color: $indigo-50;
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom: 1px solid darken($gray-normal, 8%);
|
||||
}
|
||||
}
|
||||
|
||||
.popover .feature-highlight-popover-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.feature-highlight-popover {
|
||||
padding: 0;
|
||||
|
||||
.popover-content {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.feature-highlight-popover-sub-content {
|
||||
padding: 9px 14px;
|
||||
}
|
||||
|
||||
@include keyframes(pulse-highlight) {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 rgba($blue-200, 0.4);
|
||||
}
|
||||
|
||||
70% {
|
||||
box-shadow: 0 0 0 10px transparent;
|
||||
}
|
||||
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent;
|
||||
}
|
||||
}
|
|
@ -6,3 +6,7 @@
|
|||
.media-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.media-body-wrap {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
|
|
@ -192,7 +192,11 @@ $new-sidebar-collapsed-width: 50px;
|
|||
.nav-sidebar-inner-scroll {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
|
||||
@media (min-width: $screen-sm-min) {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.with-performance-bar .nav-sidebar {
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
.info-well {
|
||||
.admin-well-statistics,
|
||||
.admin-well-features {
|
||||
padding-bottom: 46px;
|
||||
}
|
||||
}
|
|
@ -356,6 +356,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.mr-widget-body-controls {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.mr_source_commit,
|
||||
.mr_target_commit {
|
||||
margin-bottom: 0;
|
||||
|
|
|
@ -784,6 +784,7 @@ ul.notes {
|
|||
background-color: transparent;
|
||||
border: none;
|
||||
outline: 0;
|
||||
color: $gray-darkest;
|
||||
transition: color $general-hover-transition-duration $general-hover-transition-curve;
|
||||
|
||||
&.is-disabled {
|
||||
|
@ -807,7 +808,7 @@ ul.notes {
|
|||
}
|
||||
|
||||
svg {
|
||||
fill: $gray-darkest;
|
||||
fill: currentColor;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
}
|
||||
|
|
|
@ -209,6 +209,11 @@
|
|||
}
|
||||
|
||||
.stage-cell {
|
||||
@media (min-width: $screen-md-min) {
|
||||
min-width: 148px;
|
||||
margin-right: -4px;
|
||||
}
|
||||
|
||||
.mini-pipeline-graph-dropdown-toggle svg {
|
||||
height: $ci-action-icon-size;
|
||||
width: $ci-action-icon-size;
|
||||
|
|
|
@ -56,7 +56,6 @@
|
|||
|
||||
.tree-content-holder {
|
||||
display: flex;
|
||||
max-height: 100vh;
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
|
@ -156,7 +155,7 @@
|
|||
list-style-type: none;
|
||||
background: $gray-normal;
|
||||
display: inline-block;
|
||||
padding: 10px 18px;
|
||||
padding: #{$gl-padding / 2} $gl-padding;
|
||||
border-right: 1px solid $white-dark;
|
||||
border-bottom: 1px solid $white-dark;
|
||||
white-space: nowrap;
|
||||
|
@ -180,10 +179,9 @@
|
|||
a {
|
||||
@include str-truncated(100px);
|
||||
color: $black;
|
||||
width: 100px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
text-decoration: none;
|
||||
margin-right: 12px;
|
||||
|
||||
&.close {
|
||||
width: auto;
|
||||
|
@ -193,6 +191,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.close-icon:hover {
|
||||
color: $hint-color;
|
||||
}
|
||||
|
||||
.close-icon,
|
||||
.unsaved-icon {
|
||||
float: right;
|
||||
|
|
|
@ -29,7 +29,7 @@ class Admin::LabelsController < Admin::ApplicationController
|
|||
@label = Labels::UpdateService.new(label_params).execute(@label)
|
||||
|
||||
if @label.valid?
|
||||
redirect_to admin_labels_path, notice: 'label was successfully updated.'
|
||||
redirect_to admin_labels_path, notice: 'Label was successfully updated.'
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
|
|
|
@ -38,7 +38,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
|
|||
end
|
||||
|
||||
def set_index_vars
|
||||
@scopes = Gitlab::Auth::AVAILABLE_SCOPES
|
||||
@scopes = Gitlab::Auth.available_scopes
|
||||
|
||||
@personal_access_token = finder.build
|
||||
@inactive_personal_access_tokens = finder(state: 'inactive').execute
|
||||
|
|
|
@ -15,10 +15,14 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
respond_to do |format|
|
||||
format.html do
|
||||
@refs_pipelines = @project.pipelines.latest_successful_for_refs(@branches.map(&:name))
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37429
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
@max_commits = @branches.reduce(0) do |memo, branch|
|
||||
diverging_commit_counts = repository.diverging_commit_counts(branch)
|
||||
[memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max
|
||||
end
|
||||
|
||||
@max_commits = @branches.reduce(0) do |memo, branch|
|
||||
diverging_commit_counts = repository.diverging_commit_counts(branch)
|
||||
[memo, diverging_commit_counts[:behind], diverging_commit_counts[:ahead]].max
|
||||
render
|
||||
end
|
||||
end
|
||||
format.json do
|
||||
|
|
|
@ -20,7 +20,12 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
apply_diff_view_cookie!
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.html do
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37599
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
render
|
||||
end
|
||||
end
|
||||
format.diff { render text: @commit.to_diff }
|
||||
format.patch { render text: @commit.to_patch }
|
||||
end
|
||||
|
|
|
@ -17,6 +17,10 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
|
||||
def show
|
||||
apply_diff_view_cookie!
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37430
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
render
|
||||
end
|
||||
end
|
||||
|
||||
def diff_for_path
|
||||
|
|
|
@ -9,14 +9,12 @@ class Projects::ForksController < Projects::ApplicationController
|
|||
def index
|
||||
base_query = project.forks.includes(:creator)
|
||||
|
||||
@forks = base_query.merge(ProjectsFinder.new(current_user: current_user).execute)
|
||||
forks = ForkProjectsFinder.new(project, params: params.merge(search: params[:filter_projects]), current_user: current_user).execute
|
||||
@total_forks_count = base_query.size
|
||||
@private_forks_count = @total_forks_count - @forks.size
|
||||
@private_forks_count = @total_forks_count - forks.size
|
||||
@public_forks_count = @total_forks_count - @private_forks_count
|
||||
|
||||
@sort = params[:sort] || 'id_desc'
|
||||
@forks = @forks.search(params[:filter_projects]) if params[:filter_projects].present?
|
||||
@forks = @forks.order_by(@sort).page(params[:page])
|
||||
@forks = forks.page(params[:page])
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
|
|
@ -71,9 +71,6 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
@noteable = @issue
|
||||
@note = @project.notes.new(noteable: @issue)
|
||||
|
||||
@discussions = @issue.discussions
|
||||
@notes = prepare_notes_for_rendering(@discussions.flat_map(&:notes), @noteable)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
|
@ -87,9 +84,9 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
.inc_relations_for_view
|
||||
.includes(:noteable)
|
||||
.fresh
|
||||
.reject { |n| n.cross_reference_not_visible_for?(current_user) }
|
||||
|
||||
prepare_notes_for_rendering(notes)
|
||||
notes = prepare_notes_for_rendering(notes)
|
||||
notes = notes.reject { |n| n.cross_reference_not_visible_for?(current_user) }
|
||||
|
||||
discussions = Discussion.build_collection(notes, @issue)
|
||||
|
||||
|
|
|
@ -10,7 +10,10 @@ class Projects::MergeRequests::DiffsController < Projects::MergeRequests::Applic
|
|||
def show
|
||||
@environment = @merge_request.environments_for(current_user).last
|
||||
|
||||
render json: { html: view_to_html_string("projects/merge_requests/diffs/_diffs") }
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37431
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
render json: { html: view_to_html_string("projects/merge_requests/diffs/_diffs") }
|
||||
end
|
||||
end
|
||||
|
||||
def diff_for_path
|
||||
|
|
|
@ -56,6 +56,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
close_merge_request_without_source_project
|
||||
check_if_can_be_merged
|
||||
|
||||
# Return if the response has already been rendered
|
||||
return if response_body
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
# Build a note object for comment form
|
||||
|
@ -70,6 +73,11 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
labels
|
||||
|
||||
set_pipeline_variables
|
||||
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37432
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
render
|
||||
end
|
||||
end
|
||||
|
||||
format.json do
|
||||
|
|
|
@ -8,19 +8,24 @@ class Projects::NetworkController < Projects::ApplicationController
|
|||
before_action :assign_commit
|
||||
|
||||
def show
|
||||
@url = project_network_path(@project, @ref, @options.merge(format: :json))
|
||||
@commit_url = project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37602
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
@url = project_network_path(@project, @ref, @options.merge(format: :json))
|
||||
@commit_url = project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if @options[:extended_sha1] && !@commit
|
||||
flash.now[:alert] = "Git revision '#{@options[:extended_sha1]}' does not exist."
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
if @options[:extended_sha1] && !@commit
|
||||
flash.now[:alert] = "Git revision '#{@options[:extended_sha1]}' does not exist."
|
||||
end
|
||||
end
|
||||
|
||||
format.json do
|
||||
@graph = Network::Graph.new(project, @ref, @commit, @options[:filter_ref])
|
||||
end
|
||||
end
|
||||
|
||||
format.json do
|
||||
@graph = Network::Graph.new(project, @ref, @commit, @options[:filter_ref])
|
||||
end
|
||||
render
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -51,13 +51,16 @@ class Projects::RefsController < Projects::ApplicationController
|
|||
contents.push(*tree.blobs)
|
||||
contents.push(*tree.submodules)
|
||||
|
||||
@logs = contents[@offset, @limit].to_a.map do |content|
|
||||
file = @path ? File.join(@path, content.name) : content.name
|
||||
last_commit = @repo.last_commit_for_path(@commit.id, file)
|
||||
{
|
||||
file_name: content.name,
|
||||
commit: last_commit
|
||||
}
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37433
|
||||
@logs = Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
contents[@offset, @limit].to_a.map do |content|
|
||||
file = @path ? File.join(@path, content.name) : content.name
|
||||
last_commit = @repo.last_commit_for_path(@commit.id, file)
|
||||
{
|
||||
file_name: content.name,
|
||||
commit: last_commit
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
offset = (@offset + @limit)
|
||||
|
|
|
@ -28,7 +28,7 @@ class Projects::UploadsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def image_or_video?
|
||||
uploader && uploader.file.exists? && uploader.image_or_video?
|
||||
uploader && uploader.exists? && uploader.image_or_video?
|
||||
end
|
||||
|
||||
def uploader_class
|
||||
|
|
|
@ -13,7 +13,10 @@ class RootController < Dashboard::ProjectsController
|
|||
before_action :redirect_logged_user, if: -> { current_user.present? }
|
||||
|
||||
def index
|
||||
super
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37434
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
super
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class ForkProjectsFinder < ProjectsFinder
|
||||
def initialize(project, params: {}, current_user: nil)
|
||||
project_ids = project.forks.includes(:creator).select(:id)
|
||||
super(params: params, current_user: current_user, project_ids_relation: project_ids)
|
||||
end
|
||||
end
|
|
@ -57,7 +57,7 @@ class GroupsFinder < UnionFinder
|
|||
end
|
||||
|
||||
def owned_groups
|
||||
current_user&.groups || Group.none
|
||||
current_user&.owned_groups || Group.none
|
||||
end
|
||||
|
||||
def include_public_groups?
|
||||
|
|
|
@ -244,6 +244,8 @@ class IssuableFinder
|
|||
end
|
||||
|
||||
def by_scope(items)
|
||||
return items.none if current_user_related? && !current_user
|
||||
|
||||
case params[:scope]
|
||||
when 'created-by-me', 'authored'
|
||||
items.where(author_id: current_user.id)
|
||||
|
|
|
@ -5,6 +5,25 @@ module AutoDevopsHelper
|
|||
can?(current_user, :admin_pipeline, project) &&
|
||||
project.has_auto_devops_implicitly_disabled? &&
|
||||
!project.repository.gitlab_ci_yml &&
|
||||
project.ci_services.active.none?
|
||||
!project.ci_service
|
||||
end
|
||||
|
||||
def auto_devops_warning_message(project)
|
||||
missing_domain = !project.auto_devops&.has_domain?
|
||||
missing_service = !project.kubernetes_service&.active?
|
||||
|
||||
if missing_service
|
||||
params = {
|
||||
kubernetes: link_to('Kubernetes service', edit_project_service_path(project, 'kubernetes'))
|
||||
}
|
||||
|
||||
if missing_domain
|
||||
_('Auto Review Apps and Auto Deploy need a domain name and the %{kubernetes} to work correctly.') % params
|
||||
else
|
||||
_('Auto Review Apps and Auto Deploy need the %{kubernetes} to work correctly.') % params
|
||||
end
|
||||
elsif missing_domain
|
||||
_('Auto Review Apps and Auto Deploy need a domain name to work correctly.')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -94,6 +94,12 @@ module MilestonesHelper
|
|||
end
|
||||
end
|
||||
|
||||
def milestone_tooltip_title(milestone)
|
||||
if milestone.due_date
|
||||
[milestone.due_date.to_s(:medium), "(#{milestone_remaining_days(milestone)})"].join(' ')
|
||||
end
|
||||
end
|
||||
|
||||
def milestone_remaining_days(milestone)
|
||||
if milestone.expired?
|
||||
content_tag(:strong, 'Past due')
|
||||
|
|
|
@ -87,10 +87,14 @@ module SubmoduleHelper
|
|||
namespace = @project.namespace.full_path
|
||||
end
|
||||
|
||||
[
|
||||
namespace_project_path(namespace, base),
|
||||
namespace_project_tree_path(namespace, base, commit)
|
||||
]
|
||||
begin
|
||||
[
|
||||
namespace_project_path(namespace, base),
|
||||
namespace_project_tree_path(namespace, base, commit)
|
||||
]
|
||||
rescue ActionController::UrlGenerationError
|
||||
[nil, nil]
|
||||
end
|
||||
end
|
||||
|
||||
def sanitize_submodule_url(url)
|
||||
|
|
|
@ -31,6 +31,7 @@ module Ci
|
|||
has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
|
||||
|
||||
delegate :id, to: :project, prefix: true
|
||||
delegate :full_path, to: :project, prefix: true
|
||||
|
||||
validates :source, exclusion: { in: %w(unknown), unless: :importing? }, on: :create
|
||||
validates :sha, presence: { unless: :importing? }
|
||||
|
@ -336,7 +337,7 @@ module Ci
|
|||
return @config_processor if defined?(@config_processor)
|
||||
|
||||
@config_processor ||= begin
|
||||
Gitlab::Ci::YamlProcessor.new(ci_yaml_file, project.full_path)
|
||||
Gitlab::Ci::YamlProcessor.new(ci_yaml_file)
|
||||
rescue Gitlab::Ci::YamlProcessor::ValidationError, Psych::SyntaxError => e
|
||||
self.yaml_errors = e.message
|
||||
nil
|
||||
|
|
|
@ -6,9 +6,7 @@ class Environment < ActiveRecord::Base
|
|||
|
||||
belongs_to :project, required: true, validate: true
|
||||
|
||||
has_many :deployments,
|
||||
-> (env) { where(project_id: env.project_id) },
|
||||
dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
has_many :deployments, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
|
||||
|
||||
has_one :last_deployment, -> { order('deployments.id DESC') }, class_name: 'Deployment'
|
||||
|
||||
|
|
|
@ -275,8 +275,6 @@ class Issue < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def update_project_counter_caches
|
||||
return unless update_project_counter_caches?
|
||||
|
||||
Projects::OpenIssuesCountService.new(project).refresh_cache
|
||||
end
|
||||
|
||||
|
|
|
@ -415,8 +415,11 @@ class MergeRequest < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def create_merge_request_diff
|
||||
merge_request_diffs.create
|
||||
reload_merge_request_diff
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37435
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
merge_request_diffs.create
|
||||
reload_merge_request_diff
|
||||
end
|
||||
end
|
||||
|
||||
def reload_merge_request_diff
|
||||
|
@ -955,8 +958,6 @@ class MergeRequest < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def update_project_counter_caches
|
||||
return unless update_project_counter_caches?
|
||||
|
||||
Projects::OpenMergeRequestsCountService.new(target_project).refresh_cache
|
||||
end
|
||||
|
||||
|
|
|
@ -162,9 +162,7 @@ class Milestone < ActiveRecord::Base
|
|||
# Milestone.first.to_reference(cross_namespace_project) # => "gitlab-org/gitlab-ce%1"
|
||||
# Milestone.first.to_reference(same_namespace_project) # => "gitlab-ce%1"
|
||||
#
|
||||
def to_reference(from_project = nil, format: :iid, full: false)
|
||||
return if group_milestone? && format != :name
|
||||
|
||||
def to_reference(from_project = nil, format: :name, full: false)
|
||||
format_reference = milestone_format_reference(format)
|
||||
reference = "#{self.class.reference_prefix}#{format_reference}"
|
||||
|
||||
|
@ -241,6 +239,10 @@ class Milestone < ActiveRecord::Base
|
|||
def milestone_format_reference(format = :iid)
|
||||
raise ArgumentError, 'Unknown format' unless [:iid, :name].include?(format)
|
||||
|
||||
if group_milestone? && format == :iid
|
||||
raise ArgumentError, 'Cannot refer to a group milestone by an internal id!'
|
||||
end
|
||||
|
||||
if format == :name && !name.include?('"')
|
||||
%("#{name}")
|
||||
else
|
||||
|
|
|
@ -61,8 +61,11 @@ module Network
|
|||
@reserved[i] = []
|
||||
end
|
||||
|
||||
commits_sort_by_ref.each do |commit|
|
||||
place_chain(commit)
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37436
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
commits_sort_by_ref.each do |commit|
|
||||
place_chain(commit)
|
||||
end
|
||||
end
|
||||
|
||||
# find parent spaces for not overlap lines
|
||||
|
|
|
@ -28,7 +28,7 @@ class PersonalAccessToken < ActiveRecord::Base
|
|||
protected
|
||||
|
||||
def validate_scopes
|
||||
unless revoked || scopes.all? { |scope| Gitlab::Auth::AVAILABLE_SCOPES.include?(scope.to_sym) }
|
||||
unless revoked || scopes.all? { |scope| Gitlab::Auth.available_scopes.include?(scope.to_sym) }
|
||||
errors.add :scopes, "can only contain available scopes"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -192,7 +192,7 @@ class Project < ActiveRecord::Base
|
|||
accepts_nested_attributes_for :variables, allow_destroy: true
|
||||
accepts_nested_attributes_for :project_feature, update_only: true
|
||||
accepts_nested_attributes_for :import_data
|
||||
accepts_nested_attributes_for :auto_devops
|
||||
accepts_nested_attributes_for :auto_devops, update_only: true
|
||||
|
||||
delegate :name, to: :owner, allow_nil: true, prefix: true
|
||||
delegate :members, to: :team, prefix: true
|
||||
|
|
|
@ -6,6 +6,10 @@ class ProjectAutoDevops < ActiveRecord::Base
|
|||
|
||||
validates :domain, allow_blank: true, hostname: { allow_numeric_hostname: true }
|
||||
|
||||
def has_domain?
|
||||
domain.present?
|
||||
end
|
||||
|
||||
def variables
|
||||
variables = []
|
||||
variables << { key: 'AUTO_DEVOPS_DOMAIN', value: domain, public: true } if domain.present?
|
||||
|
|
|
@ -146,7 +146,7 @@ class ProjectTeam
|
|||
def member?(user, min_access_level = Gitlab::Access::GUEST)
|
||||
return false unless user
|
||||
|
||||
user.authorized_project?(project, min_access_level)
|
||||
max_member_access(user.id) >= min_access_level
|
||||
end
|
||||
|
||||
def human_max_access(user_id)
|
||||
|
|
|
@ -834,10 +834,6 @@ class Repository
|
|||
}
|
||||
end
|
||||
|
||||
def user_to_committer(user)
|
||||
Gitlab::Git.committer_hash(email: user.email, name: user.name)
|
||||
end
|
||||
|
||||
def can_be_merged?(source_sha, target_branch)
|
||||
our_commit = rugged.branches[target_branch].target
|
||||
their_commit = rugged.lookup(source_sha)
|
||||
|
@ -859,54 +855,34 @@ class Repository
|
|||
end
|
||||
|
||||
def revert(
|
||||
user, commit, branch_name,
|
||||
user, commit, branch_name, message,
|
||||
start_branch_name: nil, start_project: project)
|
||||
with_branch(
|
||||
user,
|
||||
branch_name,
|
||||
start_branch_name: start_branch_name,
|
||||
start_repository: start_project.repository.raw_repository) do |start_commit|
|
||||
|
||||
revert_tree_id = check_revert_content(commit, start_commit.sha)
|
||||
unless revert_tree_id
|
||||
raise Repository::CreateTreeError.new('Failed to revert commit')
|
||||
end
|
||||
|
||||
committer = user_to_committer(user)
|
||||
|
||||
create_commit(message: commit.revert_message(user),
|
||||
author: committer,
|
||||
committer: committer,
|
||||
tree: revert_tree_id,
|
||||
parents: [start_commit.sha])
|
||||
with_cache_hooks do
|
||||
raw_repository.revert(
|
||||
user: user,
|
||||
commit: commit.raw,
|
||||
branch_name: branch_name,
|
||||
message: message,
|
||||
start_branch_name: start_branch_name,
|
||||
start_repository: start_project.repository.raw_repository
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def cherry_pick(
|
||||
user, commit, branch_name,
|
||||
user, commit, branch_name, message,
|
||||
start_branch_name: nil, start_project: project)
|
||||
with_branch(
|
||||
user,
|
||||
branch_name,
|
||||
start_branch_name: start_branch_name,
|
||||
start_repository: start_project.repository.raw_repository) do |start_commit|
|
||||
|
||||
cherry_pick_tree_id = check_cherry_pick_content(commit, start_commit.sha)
|
||||
unless cherry_pick_tree_id
|
||||
raise Repository::CreateTreeError.new('Failed to cherry-pick commit')
|
||||
end
|
||||
|
||||
committer = user_to_committer(user)
|
||||
|
||||
create_commit(message: commit.cherry_pick_message(user),
|
||||
author: {
|
||||
email: commit.author_email,
|
||||
name: commit.author_name,
|
||||
time: commit.authored_date
|
||||
},
|
||||
committer: committer,
|
||||
tree: cherry_pick_tree_id,
|
||||
parents: [start_commit.sha])
|
||||
with_cache_hooks do
|
||||
raw_repository.cherry_pick(
|
||||
user: user,
|
||||
commit: commit.raw,
|
||||
branch_name: branch_name,
|
||||
message: message,
|
||||
start_branch_name: start_branch_name,
|
||||
start_repository: start_project.repository.raw_repository
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -918,36 +894,6 @@ class Repository
|
|||
end
|
||||
end
|
||||
|
||||
def check_revert_content(target_commit, source_sha)
|
||||
args = [target_commit.sha, source_sha]
|
||||
args << { mainline: 1 } if target_commit.merge_commit?
|
||||
|
||||
revert_index = rugged.revert_commit(*args)
|
||||
return false if revert_index.conflicts?
|
||||
|
||||
tree_id = revert_index.write_tree(rugged)
|
||||
return false unless diff_exists?(source_sha, tree_id)
|
||||
|
||||
tree_id
|
||||
end
|
||||
|
||||
def check_cherry_pick_content(target_commit, source_sha)
|
||||
args = [target_commit.sha, source_sha]
|
||||
args << 1 if target_commit.merge_commit?
|
||||
|
||||
cherry_pick_index = rugged.cherrypick_commit(*args)
|
||||
return false if cherry_pick_index.conflicts?
|
||||
|
||||
tree_id = cherry_pick_index.write_tree(rugged)
|
||||
return false unless diff_exists?(source_sha, tree_id)
|
||||
|
||||
tree_id
|
||||
end
|
||||
|
||||
def diff_exists?(sha1, sha2)
|
||||
rugged.diff(sha1, sha2).size > 0
|
||||
end
|
||||
|
||||
def merged_to_root_ref?(branch_name)
|
||||
branch_commit = commit(branch_name)
|
||||
root_ref_commit = commit(root_ref)
|
||||
|
@ -983,6 +929,7 @@ class Repository
|
|||
def empty_repo?
|
||||
!exists? || !has_visible_content?
|
||||
end
|
||||
cache_method :empty_repo?, memoize_only: true
|
||||
|
||||
def search_files_by_content(query, ref)
|
||||
return [] if empty_repo? || query.blank?
|
||||
|
|
|
@ -9,6 +9,7 @@ class GroupPolicy < BasePolicy
|
|||
condition(:has_access) { access_level != GroupMember::NO_ACCESS }
|
||||
|
||||
condition(:guest) { access_level >= GroupMember::GUEST }
|
||||
condition(:developer) { access_level >= GroupMember::DEVELOPER }
|
||||
condition(:owner) { access_level >= GroupMember::OWNER }
|
||||
condition(:master) { access_level >= GroupMember::MASTER }
|
||||
condition(:reporter) { access_level >= GroupMember::REPORTER }
|
||||
|
@ -33,11 +34,11 @@ class GroupPolicy < BasePolicy
|
|||
rule { admin } .enable :read_group
|
||||
rule { has_projects } .enable :read_group
|
||||
|
||||
rule { developer }.enable :admin_milestones
|
||||
rule { reporter }.enable :admin_label
|
||||
|
||||
rule { master }.policy do
|
||||
enable :create_projects
|
||||
enable :admin_milestones
|
||||
enable :admin_pipeline
|
||||
enable :admin_build
|
||||
end
|
||||
|
|
|
@ -155,6 +155,7 @@ class ProjectPolicy < BasePolicy
|
|||
|
||||
rule { can?(:developer_access) }.policy do
|
||||
enable :admin_merge_request
|
||||
enable :admin_milestone
|
||||
enable :update_merge_request
|
||||
enable :create_commit_status
|
||||
enable :update_commit_status
|
||||
|
@ -178,7 +179,6 @@ class ProjectPolicy < BasePolicy
|
|||
enable :update_project_snippet
|
||||
enable :update_environment
|
||||
enable :update_deployment
|
||||
enable :admin_milestone
|
||||
enable :admin_project_snippet
|
||||
enable :admin_project_member
|
||||
enable :admin_note
|
||||
|
|
|
@ -11,15 +11,19 @@ module Commits
|
|||
def commit_change(action)
|
||||
raise NotImplementedError unless repository.respond_to?(action)
|
||||
|
||||
# rubocop:disable GitlabSecurity/PublicSend
|
||||
message = @commit.public_send(:"#{action}_message", current_user)
|
||||
|
||||
# rubocop:disable GitlabSecurity/PublicSend
|
||||
repository.public_send(
|
||||
action,
|
||||
current_user,
|
||||
@commit,
|
||||
@branch_name,
|
||||
message,
|
||||
start_project: @start_project,
|
||||
start_branch_name: @start_branch)
|
||||
rescue Repository::CreateTreeError
|
||||
rescue Gitlab::Git::Repository::CreateTreeError
|
||||
error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title(current_user)} automatically.
|
||||
This #{@commit.change_type_title(current_user)} may already have been #{action.to_s.dasherize}ed, or a more recent commit may have updated some of its content."
|
||||
raise ChangeError, error_msg
|
||||
|
|
|
@ -6,15 +6,18 @@ class DeleteMergedBranchesService < BaseService
|
|||
def execute
|
||||
raise Gitlab::Access::AccessDeniedError unless can?(current_user, :push_code, project)
|
||||
|
||||
branches = project.repository.branch_names
|
||||
branches = branches.select { |branch| project.repository.merged_to_root_ref?(branch) }
|
||||
# Prevent deletion of branches relevant to open merge requests
|
||||
branches -= merge_request_branch_names
|
||||
# Prevent deletion of protected branches
|
||||
branches = branches.reject { |branch| project.protected_for?(branch) }
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37438
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
branches = project.repository.branch_names
|
||||
branches = branches.select { |branch| project.repository.merged_to_root_ref?(branch) }
|
||||
# Prevent deletion of branches relevant to open merge requests
|
||||
branches -= merge_request_branch_names
|
||||
# Prevent deletion of protected branches
|
||||
branches = branches.reject { |branch| project.protected_for?(branch) }
|
||||
|
||||
branches.each do |branch|
|
||||
DeleteBranchService.new(project, current_user).execute(branch)
|
||||
branches.each do |branch|
|
||||
DeleteBranchService.new(project, current_user).execute(branch)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -187,6 +187,7 @@ class IssuableBaseService < BaseService
|
|||
after_create(issuable)
|
||||
execute_hooks(issuable)
|
||||
invalidate_cache_counts(issuable, users: issuable.assignees)
|
||||
issuable.update_project_counter_caches
|
||||
end
|
||||
|
||||
issuable
|
||||
|
@ -198,8 +199,6 @@ class IssuableBaseService < BaseService
|
|||
|
||||
def after_create(issuable)
|
||||
# To be overridden by subclasses
|
||||
|
||||
issuable.update_project_counter_caches
|
||||
end
|
||||
|
||||
def before_update(issuable)
|
||||
|
@ -208,8 +207,6 @@ class IssuableBaseService < BaseService
|
|||
|
||||
def after_update(issuable)
|
||||
# To be overridden by subclasses
|
||||
|
||||
issuable.update_project_counter_caches
|
||||
end
|
||||
|
||||
def update(issuable)
|
||||
|
@ -234,6 +231,10 @@ class IssuableBaseService < BaseService
|
|||
|
||||
before_update(issuable)
|
||||
|
||||
# We have to perform this check before saving the issuable as Rails resets
|
||||
# the changed fields upon calling #save.
|
||||
update_project_counters = issuable.update_project_counter_caches?
|
||||
|
||||
if issuable.with_transaction_returning_status { issuable.save }
|
||||
# We do not touch as it will affect a update on updated_at field
|
||||
ActiveRecord::Base.no_touching do
|
||||
|
@ -255,6 +256,8 @@ class IssuableBaseService < BaseService
|
|||
after_update(issuable)
|
||||
issuable.create_new_cross_references!(current_user)
|
||||
execute_hooks(issuable, 'update')
|
||||
|
||||
issuable.update_project_counter_caches if update_project_counters
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ module Issues
|
|||
todo_service.close_issue(issue, current_user)
|
||||
execute_hooks(issue, 'close')
|
||||
invalidate_cache_counts(issue, users: issue.assignees)
|
||||
issue.update_project_counter_caches
|
||||
end
|
||||
|
||||
issue
|
||||
|
|
|
@ -14,6 +14,7 @@ module MergeRequests
|
|||
todo_service.close_merge_request(merge_request, current_user)
|
||||
execute_hooks(merge_request, 'close')
|
||||
invalidate_cache_counts(merge_request, users: merge_request.assignees)
|
||||
merge_request.update_project_counter_caches
|
||||
end
|
||||
|
||||
merge_request
|
||||
|
|
|
@ -13,7 +13,10 @@ module MergeRequests
|
|||
merge_request.source_branch = params[:source_branch]
|
||||
merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch)
|
||||
|
||||
create(merge_request)
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37439
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
create(merge_request)
|
||||
end
|
||||
end
|
||||
|
||||
def before_create(merge_request)
|
||||
|
|
|
@ -4,7 +4,13 @@ module Notes
|
|||
merge_request_diff_head_sha = params.delete(:merge_request_diff_head_sha)
|
||||
|
||||
note = Notes::BuildService.new(project, current_user, params).execute
|
||||
return note unless note.valid?
|
||||
|
||||
# n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37440
|
||||
note_valid = Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
note.valid?
|
||||
end
|
||||
|
||||
return note unless note_valid
|
||||
|
||||
# We execute commands (extracted from `params[:note]`) on the noteable
|
||||
# **before** we save the note because if the note consists of commands
|
||||
|
|
|
@ -2,6 +2,11 @@ module Projects
|
|||
# Base class for the various service classes that count project data (e.g.
|
||||
# issues or forks).
|
||||
class CountService
|
||||
# The version of the cache format. This should be bumped whenever the
|
||||
# underlying logic changes. This removes the need for explicitly flushing
|
||||
# all caches.
|
||||
VERSION = 1
|
||||
|
||||
def initialize(project)
|
||||
@project = project
|
||||
end
|
||||
|
@ -37,7 +42,7 @@ module Projects
|
|||
end
|
||||
|
||||
def cache_key
|
||||
['projects', @project.id, cache_key_name]
|
||||
['projects', 'count_service', VERSION, @project.id, cache_key_name]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@ class AvatarUploader < GitlabUploader
|
|||
end
|
||||
|
||||
def exists?
|
||||
model.avatar.file && model.avatar.file.exists?
|
||||
model.avatar.file && model.avatar.file.present?
|
||||
end
|
||||
|
||||
# We set move_to_store and move_to_cache to 'false' to prevent stealing
|
||||
|
|
|
@ -51,7 +51,7 @@ class GitlabUploader < CarrierWave::Uploader::Base
|
|||
end
|
||||
|
||||
def exists?
|
||||
file.try(:exists?)
|
||||
file.present?
|
||||
end
|
||||
|
||||
# Override this if you don't want to save files by default to the Rails.root directory
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
= image_tag @appearance.logo_url, class: 'appearance-logo-preview'
|
||||
- if @appearance.persisted?
|
||||
%br
|
||||
= link_to 'Remove logo', logo_admin_appearances_path, data: { confirm: "Logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-logo"
|
||||
= link_to 'Remove logo', logo_admin_appearances_path, data: { confirm: "Logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-logo"
|
||||
%hr
|
||||
= f.hidden_field :logo_cache
|
||||
= f.file_field :logo, class: ""
|
||||
|
@ -38,7 +38,7 @@
|
|||
= image_tag @appearance.header_logo_url, class: 'appearance-light-logo-preview'
|
||||
- if @appearance.persisted?
|
||||
%br
|
||||
= link_to 'Remove header logo', header_logos_admin_appearances_path, data: { confirm: "Header logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-small remove-logo"
|
||||
= link_to 'Remove header logo', header_logos_admin_appearances_path, data: { confirm: "Header logo will be removed. Are you sure?"}, method: :delete, class: "btn btn-remove btn-sm remove-logo"
|
||||
%hr
|
||||
= f.hidden_field :header_logo_cache
|
||||
= f.file_field :header_logo, class: ""
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
.row
|
||||
.col-md-4
|
||||
.info-well
|
||||
.well-segment.admin-well
|
||||
.well-segment.admin-well.admin-well-statistics
|
||||
%h4 Statistics
|
||||
%p
|
||||
Forks
|
||||
|
@ -43,7 +43,7 @@
|
|||
= number_with_delimiter(User.active.count)
|
||||
.col-md-4
|
||||
.info-well
|
||||
.well-segment.admin-well
|
||||
.well-segment.admin-well.admin-well-features
|
||||
%h4 Features
|
||||
- sign_up = "Sign up"
|
||||
%p{ "aria-label" => "#{sign_up}: status " + (signup_enabled? ? "on" : "off") }
|
||||
|
@ -111,6 +111,10 @@
|
|||
GitLab API
|
||||
%span.pull-right
|
||||
= API::API::version
|
||||
%p
|
||||
Gitaly
|
||||
%span.pull-right
|
||||
= Gitlab::GitalyClient.expected_server_version
|
||||
- if Gitlab.config.pages.enabled
|
||||
%p
|
||||
GitLab Pages
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
- @hooks.each do |hook|
|
||||
%li
|
||||
.controls
|
||||
= render 'shared/web_hooks/test_button', triggers: SystemHook::TRIGGERS, hook: hook, button_class: 'btn-small'
|
||||
= render 'shared/web_hooks/test_button', triggers: SystemHook::TRIGGERS, hook: hook, button_class: 'btn-sm'
|
||||
= link_to 'Edit', edit_admin_hook_path(hook), class: 'btn btn-sm'
|
||||
= link_to 'Remove', admin_hook_path(hook), data: { confirm: 'Are you sure?' }, method: :delete, class: 'btn btn-remove btn-sm'
|
||||
.monospace= hook.url
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="214" height="102" viewBox="0 0 214 102" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<defs>
|
||||
<path id="b" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,27 C48,28.1045695 47.1045695,29 46,29 L2,29 C0.8954305,29 1.3527075e-16,28.1045695 0,27 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
||||
<filter id="a" width="102.1%" height="106.9%" x="-1%" y="-1.7%" filterUnits="objectBoundingBox">
|
||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
||||
</filter>
|
||||
<path id="d" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
||||
<filter id="c" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
||||
</filter>
|
||||
<path id="e" d="M5,0 L53,0 C55.7614237,-5.07265313e-16 58,2.23857625 58,5 L58,91 C58,93.7614237 55.7614237,96 53,96 L5,96 C2.23857625,96 3.38176876e-16,93.7614237 0,91 L0,5 C-3.38176876e-16,2.23857625 2.23857625,5.07265313e-16 5,0 Z"/>
|
||||
<path id="h" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
||||
<filter id="g" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
||||
</filter>
|
||||
<path id="j" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
||||
<filter id="i" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
||||
</filter>
|
||||
<path id="l" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
||||
<filter id="k" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
||||
</filter>
|
||||
<path id="n" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
||||
<filter id="m" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
||||
</filter>
|
||||
<path id="p" d="M2,0 L46,0 C47.1045695,-2.02906125e-16 48,0.8954305 48,2 L48,26 C48,27.1045695 47.1045695,28 46,28 L2,28 C0.8954305,28 1.3527075e-16,27.1045695 0,26 L0,2 C-1.3527075e-16,0.8954305 0.8954305,2.02906125e-16 2,0 Z"/>
|
||||
<filter id="o" width="102.1%" height="107.1%" x="-1%" y="-1.8%" filterUnits="objectBoundingBox">
|
||||
<feOffset dy="1" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
||||
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.05 0" in="shadowOffsetOuter1"/>
|
||||
</filter>
|
||||
</defs>
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#D6D4DE" d="M14,21 L62,21 C64.7614237,21 67,23.2385763 67,26 L67,112 C67,114.761424 64.7614237,117 62,117 L14,117 C11.2385763,117 9,114.761424 9,112 L9,26 C9,23.2385763 11.2385763,21 14,21 Z"/>
|
||||
<g transform="translate(11 23)">
|
||||
<path fill="#FFFFFF" d="M5,0 L53,0 C55.7614237,-5.07265313e-16 58,2.23857625 58,5 L58,91 C58,93.7614237 55.7614237,96 53,96 L5,96 C2.23857625,96 3.38176876e-16,93.7614237 0,91 L0,5 C-3.38176876e-16,2.23857625 2.23857625,5.07265313e-16 5,0 Z"/>
|
||||
<path fill="#FC6D26" d="M4,0 L54,0 C56.209139,-4.05812251e-16 58,1.790861 58,4 L0,4 C-2.705415e-16,1.790861 1.790861,4.05812251e-16 4,0 Z"/>
|
||||
<g transform="translate(5 10)">
|
||||
<use fill="black" filter="url(#a)" xlink:href="#b"/>
|
||||
<use fill="#F9F9F9" xlink:href="#b"/>
|
||||
</g>
|
||||
<g transform="translate(5 42)">
|
||||
<use fill="black" filter="url(#c)" xlink:href="#d"/>
|
||||
<use fill="#FEF0E8" xlink:href="#d"/>
|
||||
<path fill="#FEE1D3" d="M9,8 L33,8 C34.1045695,8 35,8.8954305 35,10 C35,11.1045695 34.1045695,12 33,12 L9,12 C7.8954305,12 7,11.1045695 7,10 C7,8.8954305 7.8954305,8 9,8 Z"/>
|
||||
<path fill="#FDC4A8" d="M9,17 L17,17 C18.1045695,17 19,17.8954305 19,19 C19,20.1045695 18.1045695,21 17,21 L9,21 C7.8954305,21 7,20.1045695 7,19 C7,17.8954305 7.8954305,17 9,17 Z"/>
|
||||
<path fill="#FC6D26" d="M24,17 L32,17 C33.1045695,17 34,17.8954305 34,19 C34,20.1045695 33.1045695,21 32,21 L24,21 C22.8954305,21 22,20.1045695 22,19 C22,17.8954305 22.8954305,17 24,17 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path fill="#D6D4DE" d="M148,26 L196,26 C198.761424,26 201,28.2385763 201,31 L201,117 C201,119.761424 198.761424,122 196,122 L148,122 C145.238576,122 143,119.761424 143,117 L143,31 C143,28.2385763 145.238576,26 148,26 Z"/>
|
||||
<g transform="translate(145 28)">
|
||||
<mask id="f" fill="white">
|
||||
<use xlink:href="#e"/>
|
||||
</mask>
|
||||
<use fill="#FFFFFF" xlink:href="#e"/>
|
||||
<path fill="#FC6D26" d="M4,0 L54,0 C56.209139,-4.05812251e-16 58,1.790861 58,4 L0,4 C-2.705415e-16,1.790861 1.790861,4.05812251e-16 4,0 Z" mask="url(#f)"/>
|
||||
<g transform="translate(5 10)">
|
||||
<use fill="black" filter="url(#g)" xlink:href="#h"/>
|
||||
<use fill="#F9F9F9" xlink:href="#h"/>
|
||||
</g>
|
||||
<g transform="translate(5 42)">
|
||||
<use fill="black" filter="url(#i)" xlink:href="#j"/>
|
||||
<use fill="#FEF0E8" xlink:href="#j"/>
|
||||
<path fill="#FEE1D3" d="M9 8L33 8C34.1045695 8 35 8.8954305 35 10 35 11.1045695 34.1045695 12 33 12L9 12C7.8954305 12 7 11.1045695 7 10 7 8.8954305 7.8954305 8 9 8zM9 17L13 17C14.1045695 17 15 17.8954305 15 19 15 20.1045695 14.1045695 21 13 21L9 21C7.8954305 21 7 20.1045695 7 19 7 17.8954305 7.8954305 17 9 17z"/>
|
||||
<path fill="#FC6D26" d="M20,17 L24,17 C25.1045695,17 26,17.8954305 26,19 C26,20.1045695 25.1045695,21 24,21 L20,21 C18.8954305,21 18,20.1045695 18,19 C18,17.8954305 18.8954305,17 20,17 Z"/>
|
||||
<path fill="#FDC4A8" d="M31,17 L35,17 C36.1045695,17 37,17.8954305 37,19 C37,20.1045695 36.1045695,21 35,21 L31,21 C29.8954305,21 29,20.1045695 29,19 C29,17.8954305 29.8954305,17 31,17 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
<path fill="#D6D4DE" d="M81,14 L129,14 C131.761424,14 134,16.2385763 134,19 L134,105 C134,107.761424 131.761424,110 129,110 L81,110 C78.2385763,110 76,107.761424 76,105 L76,19 C76,16.2385763 78.2385763,14 81,14 Z"/>
|
||||
<g transform="translate(78 16)">
|
||||
<path fill="#FFFFFF" d="M5,0 L53,0 C55.7614237,-5.07265313e-16 58,2.23857625 58,5 L58,91 C58,93.7614237 55.7614237,96 53,96 L5,96 C2.23857625,96 3.38176876e-16,93.7614237 0,91 L0,5 C-3.38176876e-16,2.23857625 2.23857625,5.07265313e-16 5,0 Z"/>
|
||||
<g transform="translate(5 10)">
|
||||
<use fill="black" filter="url(#k)" xlink:href="#l"/>
|
||||
<use fill="#EFEDF8" xlink:href="#l"/>
|
||||
<path fill="#E1DBF1" d="M9,8 L33,8 C34.1045695,8 35,8.8954305 35,10 C35,11.1045695 34.1045695,12 33,12 L9,12 C7.8954305,12 7,11.1045695 7,10 C7,8.8954305 7.8954305,8 9,8 Z"/>
|
||||
<path fill="#6B4FBB" d="M9,17 L13,17 C14.1045695,17 15,17.8954305 15,19 C15,20.1045695 14.1045695,21 13,21 L9,21 C7.8954305,21 7,20.1045695 7,19 C7,17.8954305 7.8954305,17 9,17 Z"/>
|
||||
<path fill="#C3B8E3" d="M20,17 L28,17 C29.1045695,17 30,17.8954305 30,19 C30,20.1045695 29.1045695,21 28,21 L20,21 C18.8954305,21 18,20.1045695 18,19 C18,17.8954305 18.8954305,17 20,17 Z"/>
|
||||
</g>
|
||||
<g transform="translate(5 42)">
|
||||
<use fill="black" filter="url(#m)" xlink:href="#n"/>
|
||||
<use fill="#F9F9F9" xlink:href="#n"/>
|
||||
</g>
|
||||
<g transform="translate(5 74)">
|
||||
<rect width="34" height="4" x="7" y="7" fill="#E1DBF1" rx="2"/>
|
||||
<use fill="black" filter="url(#o)" xlink:href="#p"/>
|
||||
<use fill="#F9F9F9" xlink:href="#p"/>
|
||||
</g>
|
||||
<path fill="#6B4FBB" d="M4,0 L54,0 C56.209139,-4.05812251e-16 58,1.790861 58,4 L0,4 C-2.705415e-16,1.790861 1.790861,4.05812251e-16 4,0 Z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 8.8 KiB |
|
@ -117,20 +117,6 @@
|
|||
= link_to project_boards_path(@project), title: boards_link_text do
|
||||
%span
|
||||
= boards_link_text
|
||||
.feature-highlight.js-feature-highlight{ disabled: true, data: { trigger: 'manual', container: 'body', toggle: 'popover', placement: 'right', highlight: 'issue-boards' } }
|
||||
.feature-highlight-popover-content
|
||||
= render 'feature_highlight/issue_boards.svg'
|
||||
.feature-highlight-popover-sub-content
|
||||
%span= _('Use')
|
||||
= link_to 'Issue Boards', project_boards_path(@project)
|
||||
%span= _('to create customized software development workflows like')
|
||||
%strong= _('Scrum')
|
||||
%span= _('or')
|
||||
%strong= _('Kanban')
|
||||
%hr
|
||||
%button.btn-link.dismiss-feature-highlight{ type: 'button' }
|
||||
%span= _("Got it! Don't show this again")
|
||||
= custom_icon('thumbs_up')
|
||||
|
||||
= nav_link(controller: :labels) do
|
||||
= link_to project_labels_path(@project), title: 'Labels' do
|
||||
|
|
|
@ -74,7 +74,9 @@
|
|||
%h4.prepend-top-0.warning-title
|
||||
Change username
|
||||
%p
|
||||
Changing your username will change path to all personal projects!
|
||||
Changing your username can have unintended side effects.
|
||||
= succeed '.' do
|
||||
= link_to 'Learn more', help_page_path('user/profile/index', anchor: 'changing-your-username'), target: '_blank'
|
||||
.col-lg-8
|
||||
= form_for @user, url: update_username_profile_path, method: :put, html: {class: "update-username"} do |f|
|
||||
.form-group
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
- if can?(current_user, :push_code, @project)
|
||||
%div{ class: container_class }
|
||||
- if show_auto_devops_callout?(@project)
|
||||
= render 'shared/auto_devops_callout'
|
||||
.prepend-top-20
|
||||
.empty_wrapper
|
||||
%h3.page-title-empty
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
- if issue.milestone
|
||||
%span.issuable-milestone.hidden-xs
|
||||
|
||||
= link_to project_issues_path(issue.project, milestone_title: issue.milestone.title) do
|
||||
= link_to project_issues_path(issue.project, milestone_title: issue.milestone.title), data: { html: 1, toggle: 'tooltip', title: milestone_tooltip_title(issue.milestone) } do
|
||||
= icon('clock-o')
|
||||
= issue.milestone.title
|
||||
- if issue.due_date
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
- if merge_request.milestone
|
||||
%span.issuable-milestone.hidden-xs
|
||||
|
||||
= link_to project_merge_requests_path(merge_request.project, milestone_title: merge_request.milestone.title) do
|
||||
= 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
|
||||
= icon('clock-o')
|
||||
= merge_request.milestone.title
|
||||
- if merge_request.target_project.default_branch != merge_request.target_branch
|
||||
|
|
|
@ -62,7 +62,10 @@
|
|||
":class" => "{ 'has-next-btn': !loggedOut && resolvedDiscussionCount !== discussionCount }" }
|
||||
%span.line-resolve-btn.is-disabled{ type: "button",
|
||||
":class" => "{ 'is-active': resolvedDiscussionCount === discussionCount }" }
|
||||
= render "shared/icons/icon_status_success.svg"
|
||||
%template{ 'v-if' => 'resolvedDiscussionCount === discussionCount' }
|
||||
= render 'shared/icons/icon_status_success_solid.svg'
|
||||
%template{ 'v-else' => '' }
|
||||
= render 'shared/icons/icon_resolve_discussion.svg'
|
||||
%span.line-resolve-text
|
||||
{{ resolvedDiscussionCount }}/{{ discussionCount }} {{ resolvedCountText }} resolved
|
||||
= render "discussions/new_issue_for_all_discussions", merge_request: @merge_request
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
New project
|
||||
- if import_sources_enabled?
|
||||
%p
|
||||
Create or Import your project from popular Git services
|
||||
A project is where you house your files (repository), plan your work (issues), and publish your documentation (wiki), #{link_to 'among other things', help_page_path("user/project/index.md", anchor: "projects-features"), target: '_blank'}.
|
||||
%p
|
||||
All features are enabled when you create a project, but you can disable the ones you don’t need in the project settings.
|
||||
.col-lg-9.js-toggle-container
|
||||
= form_for @project, html: { class: 'new_project' } do |f|
|
||||
.create-project-options
|
||||
|
|
|
@ -3,11 +3,15 @@
|
|||
= form_for @project, url: project_pipelines_settings_path(@project) do |f|
|
||||
%fieldset.builds-feature
|
||||
.form-group
|
||||
%p Pipelines need to have Auto DevOps enabled or have a .gitlab-ci.yml configured before you can begin using Continuous Integration and Delivery.
|
||||
%h5 Auto DevOps (Beta)
|
||||
%p
|
||||
Auto DevOps will automatically build, test, and deploy your application based on a predefined Continious Integration and Delivery configuration.
|
||||
Auto DevOps will automatically build, test, and deploy your application based on a predefined Continuous Integration and Delivery configuration.
|
||||
This will happen starting with the next event (e.g.: push) that occurs to the project.
|
||||
= link_to 'Learn more about Auto DevOps', help_page_path('topics/autodevops/index.md')
|
||||
- message = auto_devops_warning_message(@project)
|
||||
- if message
|
||||
%p.settings-message.text-center
|
||||
= message.html_safe
|
||||
= f.fields_for :auto_devops_attributes, @auto_devops do |form|
|
||||
.radio
|
||||
= form.label :enabled_true do
|
||||
|
@ -15,26 +19,24 @@
|
|||
%strong Enable Auto DevOps
|
||||
%br
|
||||
%span.descr
|
||||
The Auto DevOps pipeline configuration will be used when there is no .gitlab-ci.yml
|
||||
in the project.
|
||||
The Auto DevOps pipeline configuration will be used when there is no <code>.gitlab-ci.yml</code> in the project.
|
||||
.radio
|
||||
= form.label :enabled_false do
|
||||
= form.radio_button :enabled, 'false'
|
||||
%strong Disable Auto DevOps
|
||||
%br
|
||||
%span.descr
|
||||
A specific .gitlab-ci.yml file needs to be specified before you can begin using Continious Integration and Delivery.
|
||||
An explicit <code>.gitlab-ci.yml</code> needs to be specified before you can begin using Continious Integration and Delivery.
|
||||
.radio
|
||||
= form.label :enabled do
|
||||
= form.radio_button :enabled, nil
|
||||
%strong
|
||||
Instance default (status: #{current_application_settings.auto_devops_enabled?})
|
||||
= form.label :enabled_nil do
|
||||
= form.radio_button :enabled, ''
|
||||
%strong Instance default (#{current_application_settings.auto_devops_enabled? ? 'enabled' : 'disabled'})
|
||||
%br
|
||||
%span.descr
|
||||
Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific .gitlab-ci.yml file specified.
|
||||
Follow the instance default to either have Auto DevOps enabled or disabled when there is no project specific <code>.gitlab-ci.yml</code>.
|
||||
%br
|
||||
%p
|
||||
Define a domain used by Auto DevOps to deploy towards, this is required for deploys to succeed.
|
||||
You need to specify a domain if you want to use Auto Review Apps and Auto Deploy stages.
|
||||
= form.text_field :domain, class: 'form-control', placeholder: 'domain.com'
|
||||
|
||||
%hr
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
%button.btn.js-settings-toggle
|
||||
= expanded ? 'Collapse' : 'Expand'
|
||||
%p
|
||||
Update your CI/CD configuration, like job timeout.
|
||||
Update your CI/CD configuration, like job timeout or Auto DevOps.
|
||||
.settings-content.no-animate{ class: ('expanded' if expanded) }
|
||||
= render 'projects/pipelines_settings/show'
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
%span.append-right-10.inline
|
||||
SSL Verification: #{hook.enable_ssl_verification ? 'enabled' : 'disabled'}
|
||||
= link_to 'Edit', edit_project_hook_path(@project, hook), class: 'btn btn-sm'
|
||||
= render 'shared/web_hooks/test_button', triggers: ProjectHook::TRIGGERS, hook: hook, button_class: 'btn-small'
|
||||
= render 'shared/web_hooks/test_button', triggers: ProjectHook::TRIGGERS, hook: hook, button_class: 'btn-sm'
|
||||
= link_to project_hook_path(@project, hook), data: { confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-transparent' do
|
||||
%span.sr-only Remove
|
||||
= icon('trash')
|
||||
|
|
|
@ -22,11 +22,9 @@
|
|||
|
||||
- if @group.persisted?
|
||||
.alert.alert-warning.prepend-top-10
|
||||
%ul
|
||||
%li Changing group path can have unintended side effects.
|
||||
%li Renaming group path will rename directory for all related projects
|
||||
%li It will change web url for access group and group projects.
|
||||
%li It will change the git path to repositories under this group.
|
||||
Changing group path can have unintended side effects.
|
||||
= succeed '.' do
|
||||
= link_to 'Learn more', help_page_path('user/group/index', anchor: 'changing-a-groups-path'), target: '_blank'
|
||||
|
||||
.form-group.group-name-holder
|
||||
= f.label :name, class: 'control-label' do
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- dropdown_toggle_text = @ref || @project.default_branch
|
||||
= form_tag nil, method: :get, style: { display: 'none' }, class: "project-refs-target-form" do
|
||||
= form_tag nil, method: :get, class: "project-refs-form project-refs-target-form" do
|
||||
= hidden_field_tag :destination, destination
|
||||
- if defined?(path)
|
||||
= hidden_field_tag :path, path
|
||||
|
@ -7,14 +7,10 @@
|
|||
= hidden_field_tag key, value, id: nil
|
||||
.dropdown
|
||||
= dropdown_toggle dropdown_toggle_text, { toggle: "dropdown", selected: dropdown_toggle_text, ref: @ref, refs_url: refs_project_path(@project, find: ['branches']), field_name: 'ref', input_field_name: 'new-branch', submit_form_on_click: true, visit: false }, { toggle_class: "js-project-refs-dropdown" }
|
||||
%ul.dropdown-menu.dropdown-menu-selectable.git-revision-dropdown{ class: ("dropdown-menu-align-right" if local_assigns[:align_right]) }
|
||||
%li
|
||||
= dropdown_title _("Create a new branch")
|
||||
%li
|
||||
= dropdown_input _("Create a new branch")
|
||||
%li
|
||||
= dropdown_title _("Select existing branch"), options: {close: false}
|
||||
%li
|
||||
= dropdown_filter _("Search branches and tags")
|
||||
= dropdown_content
|
||||
= dropdown_loading
|
||||
.dropdown-menu.dropdown-menu-selectable.git-revision-dropdown{ class: ("dropdown-menu-align-right" if local_assigns[:align_right]) }
|
||||
= dropdown_title _("Create a new branch")
|
||||
= dropdown_input _("Create a new branch")
|
||||
= dropdown_title _("Select existing branch"), options: {close: false}
|
||||
= dropdown_filter _("Search branches and tags")
|
||||
= dropdown_content
|
||||
= dropdown_loading
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
%span.issue-count-badge-count.pull-left{ ":class" => '{ "has-btn": list.type !== "closed" && !disabled }' }
|
||||
{{ list.issuesSize }}
|
||||
- if can?(current_user, :admin_list, current_board_parent)
|
||||
%button.issue-count-badge-add-button.btn.btn-small.btn-default.has-tooltip.js-no-trigger-collapse{ type: "button",
|
||||
%button.issue-count-badge-add-button.btn.btn-sm.btn-default.has-tooltip.js-no-trigger-collapse{ type: "button",
|
||||
"@click" => "showNewIssueForm",
|
||||
"v-if" => 'list.type !== "closed"',
|
||||
"aria-label" => "New issue",
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.33 5h5.282a2 2 0 0 1 1.963 2.38l-.563 2.905a3 3 0 0 1-.243.732l-1.104 2.286A3 3 0 0 1 10.964 15H7a3 3 0 0 1-3-3V5.7a2 2 0 0 1 .436-1.247l3.11-3.9A.632.632 0 0 1 8.486.5l.138.137a1 1 0 0 1 .28.87L8.33 5zM1 6h2v7H1a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1z"/></svg>
|
Before Width: | Height: | Size: 368 B |
|
@ -26,7 +26,7 @@
|
|||
= icon('clock-o', 'aria-hidden': 'true')
|
||||
%span.milestone-title
|
||||
- if issuable.milestone
|
||||
%span.has-tooltip{ title: "#{issuable.milestone.title}<br>#{milestone_remaining_days(issuable.milestone)}", data: { container: 'body', html: 1, placement: 'left' } }
|
||||
%span.has-tooltip{ title: "#{issuable.milestone.title}<br>#{milestone_tooltip_title(issuable.milestone)}", data: { container: 'body', html: 1, placement: 'left' } }
|
||||
= issuable.milestone.title
|
||||
- else
|
||||
None
|
||||
|
@ -37,7 +37,7 @@
|
|||
= link_to 'Edit', '#', class: 'js-sidebar-dropdown-toggle edit-link pull-right'
|
||||
.value.hide-collapsed
|
||||
- if issuable.milestone
|
||||
= link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_remaining_days(issuable.milestone), data: { container: "body", html: 1 }
|
||||
= link_to issuable.milestone.title, milestone_path(issuable.milestone), class: "bold has-tooltip", title: milestone_tooltip_title(issuable.milestone), data: { container: "body", html: 1 }
|
||||
- else
|
||||
%span.no-value None
|
||||
|
||||
|
|
|
@ -26,6 +26,6 @@
|
|||
|
||||
%span.assignee-icon
|
||||
- assignees.each do |assignee|
|
||||
= link_to polymorphic_path(base_url_args, { milestone_title: @milestone.title, assignee_id: assignee.id, state: 'all' }),
|
||||
= link_to polymorphic_path(issuable_type_args, { milestone_title: @milestone.title, assignee_id: assignee.id, state: 'all' }),
|
||||
class: 'has-tooltip', title: "Assigned to #{assignee.name}", data: { container: 'body' } do
|
||||
- image_tag(avatar_icon(assignee, 16), class: "avatar s16", alt: '')
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add an API endpoint to determine the forks of a project
|
||||
merge_request:
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix errors thrown in merge request widget with external CI service/integration
|
||||
merge_request:
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fixes project denial of service via gitmodules using Extended ASCII.
|
||||
merge_request: 14301
|
||||
author:
|
||||
type: fixed
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: made read-only APIs for public merge requests available without authentication
|
||||
merge_request: 13291
|
||||
author: haseebeqx
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue