Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into 2518-saved-configuration-for-issue-board

This commit is contained in:
Simon Knox 2017-11-06 20:35:14 +11:00
commit d5baa33f7a
485 changed files with 4373 additions and 3151 deletions

View file

@ -1,4 +1,4 @@
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git-2.13-phantomjs-2.1-node-8.x-yarn-1.0-postgresql-9.6"
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git-2.13-chrome-62.0-node-8.x-yarn-1.2-postgresql-9.6"
.default-cache: &default-cache
key: "ruby-235-with-yarn"
@ -23,7 +23,6 @@ variables:
SIMPLECOV: "true"
GIT_DEPTH: "20"
GIT_SUBMODULE_STRATEGY: "none"
PHANTOMJS_VERSION: "2.1.1"
GET_SOURCES_ATTEMPTS: "3"
KNAPSACK_RSPEC_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/rspec_report-master.json
KNAPSACK_SPINACH_SUITE_REPORT_PATH: knapsack/${CI_PROJECT_NAME}/spinach_report-master.json
@ -455,7 +454,7 @@ db:migrate:reset-mysql:
variables:
SETUP_DB: "false"
script:
- git fetch origin v9.3.0
- git fetch https://gitlab.com/gitlab-org/gitlab-ce.git v9.3.0
- git checkout -f FETCH_HEAD
- bundle install $BUNDLE_INSTALL_FLAGS
- cp config/gitlab.yml.example config/gitlab.yml
@ -551,7 +550,6 @@ karma:
<<: *dedicated-runner
<<: *except-docs
<<: *pull-cache
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.3.5-golang-1.8-git-2.13-chrome-61.0-node-8.x-yarn-1.0-postgresql-9.6"
stage: test
variables:
BABEL_ENV: "coverage"

2
.nvmrc
View file

@ -1 +1 @@
7.5
9.0.0

View file

@ -112,7 +112,7 @@ linters:
# Reports when you define the same selector twice in a single sheet.
MergeableSelector:
enabled: false
enabled: true
# Functions, mixins, variables, and placeholders should be declared
# with all lowercase letters and hyphens instead of underscores.

View file

@ -2,6 +2,30 @@
documentation](doc/development/changelog.md) for instructions on adding your own
entry.
## 10.1.1 (2017-10-31)
- [FIXED] Auto Devops kubernetes default namespace is now correctly built out of gitlab project group-name. !14642 (Mircea Danila Dumitrescu)
- [FIXED] Forbid the usage of `Redis#keys`. !14889
- [FIXED] Make the circuitbreaker more robust by adding higher thresholds, and multiple access attempts. !14933
- [FIXED] Only cache last push event for existing projects when pushing to a fork. !14989
- [FIXED] Fix bug preventing secondary emails from being confirmed. !15010
- [FIXED] Fix broken wiki pages that link to a wiki file. !15019
- [FIXED] Don't rename paths that were freed up when upgrading. !15029
- [FIXED] Fix bitbucket login. !15051
- [FIXED] Update gitaly in Gitlab 10.1 to 0.43.1 for temp file cleanup. !15055
- [FIXED] Use the correct visibility attribute for projects in system hooks. !15065
- [FIXED] Normalize LDAP DN when looking up identity.
- [FIXED] Adds callback functions for initial request in clusters page.
- [FIXED] Fix missing Import/Export issue assignees.
- [FIXED] Allow boards as top level route.
- [FIXED] Fix widget of locked merge requests not being presented.
- [FIXED] Fix editing issue description in mobile view.
- [FIXED] Fix deletion of container registry or images returning an error.
- [FIXED] Fix the writing of invalid environment refs.
- [CHANGED] Store circuitbreaker settings in the database instead of config. !14842
- [CHANGED] Update default disabled merge request widget message to reflect a general failure. !14960
- [PERFORMANCE] Stop merge requests with thousands of commits from timing out. !15063
## 10.1.0 (2017-10-22)
- [SECURITY] Use a timeout on certain git operations. !14872
@ -194,6 +218,24 @@ entry.
- creation of keys moved to services. !13331 (haseebeqx)
- Add username as GL_USERNAME in hooks.
## 10.0.5 (2017-11-03)
- [FIXED] Fix incorrect X-axis labels in Prometheus graphs. !14258
- [FIXED] Fix `rake gitlab:incoming_email:check` and make it report the actual error. !14423
- [FIXED] Does not check if an invariant hashed storage path exists on disk when renaming projects. !14428
- [FIXED] Fix bottom spacing for dropdowns that open upwards. !14535
- [FIXED] Fix the project import with issues and milestones. !14657
- [FIXED] Fix broken Y-axis scaling in some Prometheus graphs. !14693
- [FIXED] Fixed duplicate notifications when added multiple labels on an issue. !14798
- [FIXED] Don't rename paths that were freed up when upgrading. !15029
- [FIXED] Fixed issue/merge request breadcrumb titles not having links.
- [FIXED] Fix application setting to cache nil object.
- [FIXED] Fix missing Import/Export issue assignees.
- [FIXED] Allow boards as top level route.
- [FIXED] Fixed milestone breadcrumb links.
- [FIXED] Fixed merge request widget merged & closed date tooltip text.
- [FIXED] fix merge request widget status icon for failed CI.
## 10.0.4 (2017-10-16)
- [SECURITY] Move project repositories between namespaces when renaming users.

View file

@ -104,8 +104,7 @@ the remaining issues on the GitHub issue tracker.
## I want to contribute!
If you want to contribute to GitLab, but are not sure where to start,
look for [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight].
If you want to contribute to GitLab, [issues with the label `Accepting Merge Requests` and small weight][accepting-mrs-weight] is a great place to start. Issues with a lower weight (1 or 2) are deemed suitable for beginners.
These issues will be of reasonable size and challenge, for anyone to start
contributing to GitLab.

View file

@ -324,9 +324,9 @@ group :development, :test do
# Generate Fake data
gem 'ffaker', '~> 2.4'
gem 'capybara', '~> 2.15.0'
gem 'capybara', '~> 2.15'
gem 'capybara-screenshot', '~> 1.0.0'
gem 'poltergeist', '~> 1.9.0'
gem 'selenium-webdriver', '~> 3.5'
gem 'spring', '~> 2.0.0'
gem 'spring-commands-rspec', '~> 1.0.4'

View file

@ -113,12 +113,13 @@ GEM
mime-types (>= 1.16)
cause (0.1)
charlock_holmes (0.7.5)
childprocess (0.7.0)
ffi (~> 1.0, >= 1.0.11)
chronic (0.10.2)
chronic_duration (0.10.6)
numerizer (~> 0.1.1)
chunky_png (1.3.5)
citrus (3.0.2)
cliver (0.3.2)
coderay (1.1.1)
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
@ -604,11 +605,6 @@ GEM
pg (0.18.4)
po_to_json (1.0.1)
json (>= 1.6.0)
poltergeist (1.9.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
multi_json (~> 1.0)
websocket-driver (>= 0.2.0)
posix-spawn (0.3.13)
powerpack (0.1.1)
premailer (1.10.4)
@ -818,6 +814,9 @@ GEM
activesupport (>= 3.1)
select2-rails (3.5.9.3)
thor (~> 0.14)
selenium-webdriver (3.5.0)
childprocess (~> 0.5)
rubyzip (~> 1.0)
sentry-raven (2.5.3)
faraday (>= 0.7.6, < 1.0)
settingslogic (2.0.9)
@ -949,9 +948,6 @@ GEM
hashdiff
webpack-rails (0.9.10)
railties (>= 3.2.0)
websocket-driver (0.6.3)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
wikicloth (0.8.1)
builder
expression_parser
@ -988,7 +984,7 @@ DEPENDENCIES
browser (~> 2.2)
bullet (~> 5.5.0)
bundler-audit (~> 0.5.0)
capybara (~> 2.15.0)
capybara (~> 2.15)
capybara-screenshot (~> 1.0.0)
carrierwave (~> 1.2)
charlock_holmes (~> 0.7.5)
@ -1104,7 +1100,6 @@ DEPENDENCIES
peek-redis (~> 1.2.0)
peek-sidekiq (~> 1.0.3)
pg (~> 0.18.2)
poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.7)
prometheus-client-mmap (~> 0.7.0.beta18)
pry-byebug (~> 3.4.1)
@ -1150,6 +1145,7 @@ DEPENDENCIES
scss_lint (~> 0.54.0)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3)
settingslogic (~> 2.0.9)
sham_rack (~> 1.3.6)

View file

@ -1,6 +1,7 @@
/* globals Flash */
import Visibility from 'visibilityjs';
import axios from 'axios';
import setAxiosCsrfToken from './lib/utils/axios_utils';
import Poll from './lib/utils/poll';
import { s__ } from './locale';
import initSettingsPanels from './settings_panels';
@ -17,6 +18,7 @@ import Flash from './flash';
class ClusterService {
constructor(options = {}) {
this.options = options;
setAxiosCsrfToken();
}
fetchData() {
return axios.get(this.options.endpoint);

View file

@ -16,7 +16,7 @@ import CILintEditor from './ci_lint_editor';
import groupsSelect from './groups_select';
/* global Search */
/* global Admin */
/* global NamespaceSelects */
import NamespaceSelect from './namespace_select';
/* global NewCommitForm */
/* global NewBranchForm */
/* global Project */
@ -575,7 +575,8 @@ import Diff from './diff';
new UsersSelect();
break;
case 'projects':
new NamespaceSelects();
document.querySelectorAll('.js-namespace-select')
.forEach(dropdown => new NamespaceSelect({ dropdown }));
break;
case 'labels':
switch (path[2]) {

View file

@ -79,8 +79,6 @@ const Filter = {
this.hook.trigger.addEventListener('keydown.dl', this.eventWrapper.debounceKeydown);
this.hook.trigger.addEventListener('mousedown.dl', this.eventWrapper.debounceKeydown);
this.debounceKeydown({ detail: { hook: this.hook } });
},
destroy: function destroy() {

View file

@ -30,7 +30,7 @@ const utils = {
},
isDropDownParts(target) {
if (!target || target.tagName === 'HTML') return false;
if (!target || !target.hasAttribute || target.tagName === 'HTML') return false;
return target.hasAttribute(DATA_TRIGGER) || target.hasAttribute(DATA_DROPDOWN);
},
};

View file

@ -119,11 +119,9 @@ export default function dropzoneInput(form) {
// removeAllFiles(true) stops uploading files (if any)
// and remove them from dropzone files queue.
$cancelButton.on('click', (e) => {
const target = e.target.closest('.js-main-target-form').querySelector('.div-dropzone');
e.preventDefault();
e.stopPropagation();
Dropzone.forElement(target).removeAllFiles(true);
Dropzone.forElement($formDropzone.get(0)).removeAllFiles(true);
});
// If 'error' event is fired, we store a failed files,

View file

@ -421,7 +421,11 @@ export default {
</script>
<template>
<div
:class="{ 'js-child-row environment-child-row': model.isChildren, 'folder-row': model.isFolder, 'gl-responsive-table-row': !model.isFolder }"
class="gl-responsive-table-row"
:class="{
'js-child-row environment-child-row': model.isChildren,
'folder-row': model.isFolder,
}"
role="row">
<div class="table-section section-10" role="gridcell">
<div
@ -495,15 +499,16 @@ export default {
</a>
</div>
<div class="table-section section-25" role="gridcell">
<div
v-if="!model.isFolder"
class="table-section section-25" role="gridcell">
<div
v-if="!model.isFolder"
role="rowheader"
class="table-mobile-header">
Commit
</div>
<div
v-if="!model.isFolder && hasLastDeploymentKey"
v-if="hasLastDeploymentKey"
class="js-commit-component table-mobile-content">
<commit-component
:tag="commitTag"
@ -514,21 +519,22 @@ export default {
:author="commitAuthor"/>
</div>
<div
v-if="!model.isFolder && !hasLastDeploymentKey"
v-if="!hasLastDeploymentKey"
class="commit-title table-mobile-content">
No deployments yet
</div>
</div>
<div class="table-section section-10" role="gridcell">
<div
v-if="!model.isFolder"
class="table-section section-10" role="gridcell">
<div
v-if="!model.isFolder"
role="rowheader"
class="table-mobile-header">
Updated
</div>
<span
v-if="!model.isFolder && canShowDate"
v-if="canShowDate"
class="environment-created-date-timeago table-mobile-content">
{{createdDate}}
</span>

View file

@ -4,6 +4,7 @@ import _ from 'underscore';
import d3 from 'd3';
import { ContributorsGraph, ContributorsAuthorGraph, ContributorsMasterGraph } from './stat_graph_contributors_graph';
import ContributorsStatGraphUtil from './stat_graph_contributors_util';
import { n__ } from '../locale';
export default (function() {
function ContributorsStatGraph() {}
@ -44,7 +45,7 @@ export default (function() {
commits = $('<span/>', {
"class": 'graph-author-commits-count'
});
commits.text(author.commits + " commits");
commits.text(n__('%d commit', '%d commits', author.commits));
return $('<span/>').append(commits);
};

View file

@ -0,0 +1,6 @@
import axios from 'axios';
import csrf from './csrf';
export default function setAxiosCsrfToken() {
axios.defaults.headers.common[csrf.headerKey] = csrf.token;
}

View file

@ -1,85 +1,57 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, vars-on-top, one-var-declaration-per-line, comma-dangle, object-shorthand, no-else-return, prefer-template, quotes, prefer-arrow-callback, no-param-reassign, no-cond-assign, max-len */
/* eslint-disable func-names, space-before-function-paren, no-var, comma-dangle, object-shorthand, no-else-return, prefer-template, quotes, prefer-arrow-callback, max-len */
import Api from './api';
import './lib/utils/url_utility';
(function() {
window.NamespaceSelect = (function() {
function NamespaceSelect(opts) {
this.onSelectItem = this.onSelectItem.bind(this);
var fieldName, showAny;
this.dropdown = opts.dropdown;
showAny = true;
fieldName = 'namespace_id';
if (this.dropdown.attr('data-field-name')) {
fieldName = this.dropdown.data('fieldName');
}
if (this.dropdown.attr('data-show-any')) {
showAny = this.dropdown.data('showAny');
}
this.dropdown.glDropdown({
filterable: true,
selectable: true,
filterRemote: true,
search: {
fields: ['path']
},
fieldName: fieldName,
toggleLabel: function(selected) {
if (selected.id == null) {
return selected.text;
} else {
return selected.kind + ": " + selected.full_path;
export default class NamespaceSelect {
constructor(opts) {
const isFilter = opts.dropdown.dataset.isFilter === 'true';
const fieldName = opts.dropdown.dataset.fieldName || 'namespace_id';
$(opts.dropdown).glDropdown({
filterable: true,
selectable: true,
filterRemote: true,
search: {
fields: ['path']
},
fieldName: fieldName,
toggleLabel: function(selected) {
if (selected.id == null) {
return selected.text;
} else {
return selected.kind + ": " + selected.full_path;
}
},
data: function(term, dataCallback) {
return Api.namespaces(term, function(namespaces) {
if (isFilter) {
const anyNamespace = {
text: 'Any namespace',
id: null
};
namespaces.unshift(anyNamespace);
namespaces.splice(1, 0, 'divider');
}
},
data: function(term, dataCallback) {
return Api.namespaces(term, function(namespaces) {
var anyNamespace;
if (showAny) {
anyNamespace = {
text: 'Any namespace',
id: null
};
namespaces.unshift(anyNamespace);
namespaces.splice(1, 0, 'divider');
}
return dataCallback(namespaces);
});
},
text: function(namespace) {
if (namespace.id == null) {
return namespace.text;
} else {
return namespace.kind + ": " + namespace.full_path;
}
},
renderRow: this.renderRow,
clicked: this.onSelectItem
});
}
NamespaceSelect.prototype.onSelectItem = function(options) {
const { e } = options;
return e.preventDefault();
};
return NamespaceSelect;
})();
window.NamespaceSelects = (function() {
function NamespaceSelects(opts) {
var ref;
if (opts == null) {
opts = {};
}
this.$dropdowns = (ref = opts.$dropdowns) != null ? ref : $('.js-namespace-select');
this.$dropdowns.each(function(i, dropdown) {
var $dropdown;
$dropdown = $(dropdown);
return new window.NamespaceSelect({
dropdown: $dropdown
return dataCallback(namespaces);
});
});
}
return NamespaceSelects;
})();
}).call(window);
},
text: function(namespace) {
if (namespace.id == null) {
return namespace.text;
} else {
return namespace.kind + ": " + namespace.full_path;
}
},
renderRow: this.renderRow,
clicked(options) {
if (!isFilter) {
const { e } = options;
e.preventDefault();
}
},
url(namespace) {
return gl.utils.mergeUrlParams({ [fieldName]: namespace.id }, window.location.href);
},
});
}
}

View file

@ -122,7 +122,9 @@
// we need to do this to prevent noteForm inconsistent content warning
// this is something we intentionally do so we need to recover the content
this.note.note = noteText;
this.$refs.noteBody.$refs.noteForm.note = noteText; // TODO: This could be better
if (this.$refs.noteBody) {
this.$refs.noteBody.$refs.noteForm.note = noteText; // TODO: This could be better
}
},
},
created() {

View file

@ -1,6 +1,6 @@
<script>
import getActionIcon from '../../../vue_shared/ci_action_icons';
import tooltip from '../../../vue_shared/directives/tooltip';
import icon from '../../../vue_shared/components/icon.vue';
/**
* Renders either a cancel, retry or play icon pointing to the given path.
@ -29,17 +29,18 @@
},
},
components: {
icon,
},
directives: {
tooltip,
},
computed: {
actionIconSvg() {
return getActionIcon(this.actionIcon);
},
cssClass() {
return `js-${gl.text.dasherize(this.actionIcon)}`;
const actionIconDash = gl.text.dasherize(this.actionIcon);
return `${actionIconDash} js-icon-${actionIconDash}`;
},
},
};
@ -50,14 +51,9 @@
:data-method="actionMethod"
:title="tooltipText"
:href="link"
class="ci-action-icon-container"
class="ci-action-icon-container ci-action-icon-wrapper"
:class="cssClass"
data-container="body">
<i
class="ci-action-icon-wrapper"
:class="cssClass"
v-html="actionIconSvg"
aria-hidden="true"
/>
<icon :name="actionIcon"/>
</a>
</template>

View file

@ -1,5 +1,5 @@
<script>
import getActionIcon from '../../../vue_shared/ci_action_icons';
import icon from '../../../vue_shared/components/icon.vue';
import tooltip from '../../../vue_shared/directives/tooltip';
/**
@ -29,14 +29,12 @@
},
},
directives: {
tooltip,
components: {
icon,
},
computed: {
actionIconSvg() {
return getActionIcon(this.actionIcon);
},
directives: {
tooltip,
},
};
</script>
@ -49,7 +47,7 @@
rel="nofollow"
class="ci-action-icon-wrapper js-ci-status-icon"
data-container="body"
v-html="actionIconSvg"
aria-label="Job's action">
<icon :name="actionIcon"/>
</a>
</template>

View file

@ -18,7 +18,7 @@
* "group": "success",
* "details_path": "/root/ci-mock/builds/4256",
* "action": {
* "icon": "icon_action_retry",
* "icon": "retry",
* "title": "Retry",
* "path": "/root/ci-mock/builds/4256/retry",
* "method": "post"

View file

@ -19,7 +19,7 @@
* "group": "success",
* "details_path": "/root/ci-mock/builds/4256",
* "action": {
* "icon": "icon_action_retry",
* "icon": "retry",
* "title": "Retry",
* "path": "/root/ci-mock/builds/4256/retry",
* "method": "post"

View file

@ -14,7 +14,7 @@
*/
import Flash from '../../flash';
import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons';
import icon from '../../vue_shared/components/icon.vue';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip';
@ -45,6 +45,7 @@ export default {
components: {
loadingIcon,
icon,
},
updated() {
@ -122,8 +123,8 @@ export default {
return `ci-status-icon-${this.stage.status.group}`;
},
svgIcon() {
return borderlessStatusIconEntityMap[this.stage.status.icon];
borderlessIcon() {
return `${this.stage.status.icon}_borderless`;
},
},
};
@ -145,9 +146,10 @@ export default {
aria-expanded="false">
<span
v-html="svgIcon"
aria-hidden="true"
:aria-label="stage.title">
<icon
:name="borderlessIcon"/>
</span>
<i

View file

@ -98,7 +98,7 @@ Once you confirm %{deleteAccount}, it cannot be undone or recovered.`),
@toggle="toggleOpen"
@submit="onSubmit">
<template slot="body" scope="props">
<template slot="body" slot-scope="props">
<p v-html="props.text"></p>
<form

View file

@ -27,6 +27,8 @@ export default {
'changeFileContent',
]),
initMonaco() {
if (this.shouldHideEditor) return;
if (this.monacoInstance) {
this.monacoInstance.setModel(null);
}
@ -94,8 +96,12 @@ export default {
<template>
<div
id="ide"
v-if='!shouldHideEditor'
class="blob-viewer-container blob-editor-container"
>
<div
v-if="shouldHideEditor"
v-html="activeFile.html"
>
</div>
</div>
</template>

View file

@ -1,34 +1,26 @@
function expandSectionParent($section, $content) {
$section.addClass('expanded');
$content.off('animationend.expandSectionParent');
}
function expandSection($section) {
$section.find('.js-settings-toggle').text('Collapse');
const $content = $section.find('.settings-content');
$content.addClass('expanded').off('scroll.expandSection').scrollTop(0);
if ($content.hasClass('no-animate')) {
expandSectionParent($section, $content);
} else {
$content.on('animationend.expandSectionParent', () => expandSectionParent($section, $content));
$section.find('.settings-content').off('scroll.expandSection').scrollTop(0);
$section.addClass('expanded');
if (!$section.hasClass('no-animate')) {
$section.addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating'));
}
}
function closeSection($section) {
$section.find('.js-settings-toggle').text('Expand');
const $content = $section.find('.settings-content');
$content.removeClass('expanded').on('scroll.expandSection', () => expandSection($section));
$section.find('.settings-content').on('scroll.expandSection', () => expandSection($section));
$section.removeClass('expanded');
if (!$section.hasClass('no-animate')) {
$section.addClass('animating')
.one('animationend.animateSection', () => $section.removeClass('animating'));
}
}
function toggleSection($section) {
const $content = $section.find('.settings-content');
$content.removeClass('no-animate');
if ($content.hasClass('expanded')) {
$section.removeClass('no-animate');
if ($section.hasClass('expanded')) {
closeSection($section);
} else {
expandSection($section);
@ -39,10 +31,19 @@ export default function initSettingsPanels() {
$('.settings').each((i, elm) => {
const $section = $(elm);
$section.on('click.toggleSection', '.js-settings-toggle', () => toggleSection($section));
$section.find('.settings-content:not(.expanded)').on('scroll.expandSection', () => expandSection($section));
if (!$section.hasClass('expanded')) {
$section.find('.settings-content').on('scroll.expandSection', () => {
$section.removeClass('no-animate');
expandSection($section);
});
}
});
if (location.hash) {
expandSection($(location.hash));
const $target = $(location.hash);
if ($target.length && $target.hasClass('.settings')) {
expandSection($target);
}
}
}

View file

@ -1,6 +1,8 @@
import 'core-js/es6/map';
import 'core-js/es6/set';
import simulateDrag from './simulate_drag';
import simulateInput from './simulate_input';
// Export to global space for rspec to use
window.simulateDrag = simulateDrag;
window.simulateInput = simulateInput;

View file

@ -0,0 +1,23 @@
function triggerEvents(input) {
input.dispatchEvent(new Event('keydown'));
input.dispatchEvent(new Event('keypress'));
input.dispatchEvent(new Event('input'));
input.dispatchEvent(new Event('keyup'));
}
export default function simulateInput(target, text) {
const input = document.querySelector(target);
if (!input || !input.matches('textarea, input')) {
return false;
}
if (text.length > 0) {
Array.prototype.forEach.call(text, (char) => {
input.value += char;
triggerEvents(input);
});
} else {
triggerEvents(input);
}
return true;
}

View file

@ -1,6 +1,6 @@
import PipelineStage from '../../pipelines/components/stage.vue';
import ciIcon from '../../vue_shared/components/ci_icon.vue';
import { statusIconEntityMap } from '../../vue_shared/ci_status_icons';
import icon from '../../vue_shared/components/icon.vue';
export default {
name: 'MRWidgetPipeline',
@ -10,6 +10,7 @@ export default {
components: {
'pipeline-stage': PipelineStage,
ciIcon,
icon,
},
computed: {
hasPipeline() {
@ -20,9 +21,6 @@ export default {
return hasCI && !ciStatus;
},
svg() {
return statusIconEntityMap.icon_status_failed;
},
stageText() {
return this.mr.pipeline.details.stages.length > 1 ? 'stages' : 'stage';
},
@ -38,8 +36,10 @@ export default {
<template v-if="hasCIError">
<div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error append-right-10">
<span
v-html="svg"
aria-hidden="true"></span>
aria-hidden="true">
<icon
name="status_failed"/>
</span>
</div>
<div class="media-body">
Could not connect to the CI server. Please check your settings and try again

View file

@ -1,21 +0,0 @@
import cancelSVG from 'icons/_icon_action_cancel.svg';
import retrySVG from 'icons/_icon_action_retry.svg';
import playSVG from 'icons/_icon_action_play.svg';
import stopSVG from 'icons/_icon_action_stop.svg';
/**
* For the provided action returns the respective SVG
*
* @param {String} action
* @return {SVG|String}
*/
export default function getActionIcon(action) {
const icons = {
icon_action_cancel: cancelSVG,
icon_action_play: playSVG,
icon_action_retry: retrySVG,
icon_action_stop: stopSVG,
};
return icons[action] || '';
}

View file

@ -1,43 +0,0 @@
import BORDERLESS_CANCELED_SVG from 'icons/_icon_status_canceled_borderless.svg';
import BORDERLESS_CREATED_SVG from 'icons/_icon_status_created_borderless.svg';
import BORDERLESS_FAILED_SVG from 'icons/_icon_status_failed_borderless.svg';
import BORDERLESS_MANUAL_SVG from 'icons/_icon_status_manual_borderless.svg';
import BORDERLESS_PENDING_SVG from 'icons/_icon_status_pending_borderless.svg';
import BORDERLESS_RUNNING_SVG from 'icons/_icon_status_running_borderless.svg';
import BORDERLESS_SKIPPED_SVG from 'icons/_icon_status_skipped_borderless.svg';
import BORDERLESS_SUCCESS_SVG from 'icons/_icon_status_success_borderless.svg';
import BORDERLESS_WARNING_SVG from 'icons/_icon_status_warning_borderless.svg';
import CANCELED_SVG from 'icons/_icon_status_canceled.svg';
import CREATED_SVG from 'icons/_icon_status_created.svg';
import FAILED_SVG from 'icons/_icon_status_failed.svg';
import MANUAL_SVG from 'icons/_icon_status_manual.svg';
import PENDING_SVG from 'icons/_icon_status_pending.svg';
import RUNNING_SVG from 'icons/_icon_status_running.svg';
import SKIPPED_SVG from 'icons/_icon_status_skipped.svg';
import SUCCESS_SVG from 'icons/_icon_status_success.svg';
import WARNING_SVG from 'icons/_icon_status_warning.svg';
export const borderlessStatusIconEntityMap = {
icon_status_canceled: BORDERLESS_CANCELED_SVG,
icon_status_created: BORDERLESS_CREATED_SVG,
icon_status_failed: BORDERLESS_FAILED_SVG,
icon_status_manual: BORDERLESS_MANUAL_SVG,
icon_status_pending: BORDERLESS_PENDING_SVG,
icon_status_running: BORDERLESS_RUNNING_SVG,
icon_status_skipped: BORDERLESS_SKIPPED_SVG,
icon_status_success: BORDERLESS_SUCCESS_SVG,
icon_status_warning: BORDERLESS_WARNING_SVG,
};
export const statusIconEntityMap = {
icon_status_canceled: CANCELED_SVG,
icon_status_created: CREATED_SVG,
icon_status_failed: FAILED_SVG,
icon_status_manual: MANUAL_SVG,
icon_status_pending: PENDING_SVG,
icon_status_running: RUNNING_SVG,
icon_status_skipped: SKIPPED_SVG,
icon_status_success: SUCCESS_SVG,
icon_status_warning: WARNING_SVG,
};

View file

@ -43,7 +43,6 @@
computed: {
cssClass() {
const className = this.status.group;
return className ? `ci-status ci-${className}` : 'ci-status';
},
},

View file

@ -1,5 +1,5 @@
<script>
import { statusIconEntityMap } from '../ci_status_icons';
import icon from '../../vue_shared/components/icon.vue';
/**
* Renders CI icon based on API response shared between all places where it is used.
@ -30,11 +30,11 @@
},
},
computed: {
statusIconSvg() {
return statusIconEntityMap[this.status.icon];
},
components: {
icon,
},
computed: {
cssClass() {
const status = this.status.group;
return `ci-status-icon ci-status-icon-${status} js-ci-status-icon-${status}`;
@ -44,7 +44,8 @@
</script>
<template>
<span
:class="cssClass"
v-html="statusIconSvg">
:class="cssClass">
<icon
:name="status.icon"/>
</span>
</template>

View file

@ -0,0 +1,52 @@
<script>
/* This is a re-usable vue component for rendering a svg sprite
icon
Sample configuration:
<icon
:img-src="userAvatarSrc"
:img-alt="tooltipText"
:tooltip-text="tooltipText"
tooltip-placement="top"
/>
*/
export default {
props: {
name: {
type: String,
required: true,
},
size: {
type: Number,
required: false,
default: 0,
},
cssClasses: {
type: String,
required: false,
default: '',
},
},
computed: {
spriteHref() {
return `${gon.sprite_icons}#${this.name}`;
},
iconSizeClass() {
return this.size ? `s${this.size}` : '';
},
},
};
</script>
<template>
<svg
:class="[iconSizeClass, cssClasses]">
<use
v-bind="{'xlink:href':spriteHref}"/>
</svg>
</template>

View file

@ -56,4 +56,4 @@
@import "framework/icons";
@import "framework/snippets";
@import "framework/memory_graph";
@import "framework/responsive-tables";
@import "framework/responsive_tables";

View file

@ -40,6 +40,10 @@
&.top-block {
border-top: none;
.container-fluid {
background-color: inherit;
}
}
&.middle-block {
@ -98,10 +102,6 @@
background-color: $white-light;
border-top: none;
}
&.top-block .container-fluid {
background-color: inherit;
}
}
.sub-header-block {

View file

@ -12,15 +12,15 @@
border-left: 3px solid $border-color;
color: $text-color;
background: $gray-light;
}
.bs-callout h4 {
margin-top: 0;
margin-bottom: 5px;
}
h4 {
margin-top: 0;
margin-bottom: 5px;
}
.bs-callout p:last-child {
margin-bottom: 0;
p:last-child {
margin-bottom: 0;
}
}
/* Variations */

View file

@ -8,32 +8,6 @@
color: $gl-text-color-secondary;
}
/** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; }
.prepend-top-5 { margin-top: 5px; }
.prepend-top-10 { margin-top: 10px; }
.prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-20 { margin-top: 20px; }
.prepend-left-4 { margin-left: 4px; }
.prepend-left-5 { margin-left: 5px; }
.prepend-left-10 { margin-left: 10px; }
.prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px; }
.append-right-5 { margin-right: 5px; }
.append-right-8 { margin-right: 8px; }
.append-right-10 { margin-right: 10px; }
.append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right: 20px; }
.append-bottom-0 { margin-bottom: 0; }
.append-bottom-5 { margin-bottom: 5px; }
.append-bottom-10 { margin-bottom: 10px; }
.append-bottom-15 { margin-bottom: 15px; }
.append-bottom-20 { margin-bottom: 20px; }
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block; }
.center { text-align: center; }
.vertical-align-middle { vertical-align: middle; }
.underlined-link { text-decoration: underline; }
.hint { font-style: italic; color: $hint-color; }
.light { color: $common-gray; }
@ -82,6 +56,14 @@ hr {
.str-truncated {
@include str-truncated;
&-60 {
@include str-truncated(60%);
}
&-100 {
@include str-truncated(100%);
}
}
.block-truncated {
@ -107,10 +89,17 @@ hr {
font-size: 14px;
}
table a code {
position: relative;
top: -2px;
margin-right: 3px;
table {
a code {
position: relative;
top: -2px;
margin-right: 3px;
}
td.permission-x {
background: $table-permission-x-bg !important;
text-align: center;
}
}
.loading {
@ -295,13 +284,6 @@ img.emoji {
margin-bottom: 10px;
}
table {
td.permission-x {
background: $table-permission-x-bg !important;
text-align: center;
}
}
.btn-sign-in {
text-shadow: none;
@ -367,10 +349,11 @@ table {
.dropzone .dz-preview .dz-progress {
border-color: $border-color !important;
}
.dropzone .dz-preview .dz-progress .dz-upload {
background: $gl-success !important;
.dz-upload {
background: $gl-success !important;
}
}
.dz-message {
@ -431,16 +414,6 @@ table {
border-radius: $border-radius-default;
}
.str-truncated {
&-60 {
@include str-truncated(60%);
}
&-100 {
@include str-truncated(100%);
}
}
.tooltip {
.tooltip-inner {
word-wrap: break-word;
@ -451,3 +424,30 @@ table {
pointer-events: none;
opacity: .5;
}
/** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; }
.prepend-top-5 { margin-top: 5px; }
.prepend-top-10 { margin-top: 10px; }
.prepend-top-15 { margin-top: 15px; }
.prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-20 { margin-top: 20px; }
.prepend-left-4 { margin-left: 4px; }
.prepend-left-5 { margin-left: 5px; }
.prepend-left-10 { margin-left: 10px; }
.prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px; }
.append-right-5 { margin-right: 5px; }
.append-right-8 { margin-right: 8px; }
.append-right-10 { margin-right: 10px; }
.append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right: 20px; }
.append-bottom-0 { margin-bottom: 0; }
.append-bottom-5 { margin-bottom: 5px; }
.append-bottom-10 { margin-bottom: 10px; }
.append-bottom-15 { margin-bottom: 15px; }
.append-bottom-20 { margin-bottom: 20px; }
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block; }
.center { text-align: center; }
.vertical-align-middle { vertical-align: middle; }

View file

@ -141,15 +141,15 @@
svg {
fill: $gl-text-color-secondary;
}
}
.nav-item-name {
flex: 1;
}
.nav-item-name {
flex: 1;
}
li.active {
> a {
font-weight: $gl-font-weight-bold;
&.active {
> a {
font-weight: $gl-font-weight-bold;
}
}
}
@ -484,10 +484,7 @@
height: calc(100vh - #{$header-height});
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
// scss-lint:disable DuplicateProperty
height: calc(100vh - 180px);
// scss-lint:enable DuplicateProperty
}
}

View file

@ -728,11 +728,11 @@
.pika-single.animate-picker.is-bound {
@include set-visible;
}
.pika-single.animate-picker.is-bound.is-hidden {
@include set-invisible;
overflow: hidden;
&.is-hidden {
@include set-invisible;
overflow: hidden;
}
}
@mixin dropdown-item-hover {
@ -939,9 +939,7 @@ header.header-content .dropdown-menu.projects-dropdown-menu {
border-right: 0;
}
}
}
.projects-dropdown-container {
.projects-list-frequent-container,
.projects-list-search-container, {
padding: 8px 0;
@ -952,11 +950,6 @@ header.header-content .dropdown-menu.projects-dropdown-menu {
.projects-list-frequent-container li.section-empty,
.projects-list-search-container li.section-empty {
padding: 0 15px;
}
.section-header,
.projects-list-frequent-container li.section-empty,
.projects-list-search-container li.section-empty {
color: $gl-text-color-secondary;
font-size: $gl-font-size;
}

View file

@ -165,22 +165,36 @@
&:last-child {
border-right: none;
}
}
td.blame-commit {
padding: 5px 10px;
min-width: 400px;
max-width: 400px;
background: $gray-light;
border-left: 3px solid;
&.blame-commit {
padding: 5px 10px;
min-width: 400px;
max-width: 400px;
background: $gray-light;
border-left: 3px solid;
.commit-row-title {
display: flex;
.commit-row-title {
display: flex;
}
.item-title {
flex: 1;
margin-right: 0.5em;
}
}
.item-title {
flex: 1;
margin-right: 0.5em;
&.line-numbers {
float: none;
border-left: 1px solid $blame-line-numbers-border;
i {
float: none;
margin-right: 0;
}
}
&.lines {
padding: 0;
}
}
@ -195,20 +209,6 @@
border-left-color: mix($blame-gray, $blame-cyan, $i / 4.0 * 100%);
}
}
td.line-numbers {
float: none;
border-left: 1px solid $blame-line-numbers-border;
i {
float: none;
margin-right: 0;
}
}
td.lines {
padding: 0;
}
}
&.logs {

View file

@ -268,12 +268,6 @@
.filtered-search-box-input-container {
flex: 1;
position: relative;
// Fix PhantomJS not supporting `flex: 1;` properly.
// This is important because it can change the expected `e.target` when clicking things in tests.
// See https://gitlab.com/gitlab-org/gitlab-ce/blob/b54acba8b732688c59fe2f38510c469dc86ee499/spec/features/issues/filtered_search/visual_tokens_spec.rb#L61
// - With `width: 100%`: `e.target` = `.tokens-container`, https://i.imgur.com/jGq7wbx.png
// - Without `width: 100%`: `e.target` = `.filtered-search`, https://i.imgur.com/cNI2CyT.png
width: 100%;
min-width: 0;
}
@ -469,10 +463,10 @@
word-break: break-all;
}
}
}
.filter-dropdown-item.droplab-item-active .btn {
@extend %filter-dropdown-item-btn-hover;
&.droplab-item-active .btn {
@extend %filter-dropdown-item-btn-hover;
}
}
.filter-dropdown-loading {

View file

@ -352,7 +352,77 @@
.header-user .dropdown-menu-nav,
.header-new .dropdown-menu-nav {
margin-top: $dropdown-vertical-offset;
margin-top: 4px;
}
.search {
margin: 4px 8px 0;
form {
height: 32px;
border: 0;
border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, background-color ease-in-out 0.15s;
&:hover {
box-shadow: none;
}
}
.search-input {
color: $white-light;
background: none;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
transition: color ease-in-out 0.15s;
}
.location-badge {
font-size: 12px;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: 2px 0 0 2px;
height: 32px;
transition: border-color ease-in-out 0.15s;
}
&.search-active {
form {
background-color: rgba($indigo-200, .3);
box-shadow: none;
.search-input {
color: $gl-text-color;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
color: $gl-text-color-tertiary;
}
.search-input-wrap {
.search-icon,
.clear-icon {
color: $gl-text-color-tertiary;
transition: color ease-in-out 0.15s;
}
}
}
.location-badge {
background-color: $nav-badge-bg;
border-color: $border-color;
}
.search-input-wrap {
.clear-icon {
color: $white-light;
}
}
}
}
.breadcrumbs {

View file

@ -30,10 +30,10 @@ body {
.container {
padding-top: 0;
z-index: 5;
}
.container .content {
margin: 0;
.content {
margin: 0;
}
}
.navless-container {
@ -82,26 +82,26 @@ body {
transition: background-color 0.15s, border-color 0.15s;
background-color: $orange-500;
border-color: $orange-500;
}
.alert-warning + .alert-warning {
background-color: $orange-600;
border-color: $orange-600;
}
&:only-of-type {
background-color: $orange-500;
border-color: $orange-500;
}
.alert-warning + .alert-warning + .alert-warning {
background-color: $orange-700;
border-color: $orange-700;
}
+ .alert-warning {
background-color: $orange-600;
border-color: $orange-600;
.alert-warning + .alert-warning + .alert-warning + .alert-warning {
background-color: $orange-800;
border-color: $orange-800;
}
+ .alert-warning {
background-color: $orange-700;
border-color: $orange-700;
.alert-warning:only-of-type {
background-color: $orange-500;
border-color: $orange-500;
+ .alert-warning {
background-color: $orange-800;
border-color: $orange-800;
}
}
}
}
}

View file

@ -299,40 +299,40 @@ ul.indent-list {
}
}
.group-list-tree .avatar-container.content-loading {
position: relative;
.group-list-tree {
.avatar-container.content-loading {
position: relative;
> a,
> a .avatar {
height: 100%;
border-radius: 50%;
}
> a,
> a .avatar {
height: 100%;
border-radius: 50%;
}
> a {
padding: 2px;
}
> a {
padding: 2px;
> a .avatar {
border: 2px solid $white-normal;
.avatar {
border: 2px solid $white-normal;
&.identicon {
line-height: 30px;
&.identicon {
line-height: 30px;
}
}
}
&::after {
content: "";
position: absolute;
height: 100%;
width: 100%;
background-color: transparent;
border: 2px outset $kdb-border;
border-radius: 50%;
animation: spin-avatar 3s infinite linear;
}
}
&::after {
content: "";
position: absolute;
height: 100%;
width: 100%;
background-color: transparent;
border: 2px outset $kdb-border;
border-radius: 50%;
animation: spin-avatar 3s infinite linear;
}
}
.group-list-tree {
.folder-toggle-wrap {
float: left;
line-height: $list-text-height;

View file

@ -173,21 +173,8 @@
ul > li {
white-space: nowrap;
}
}
@media(max-width: $screen-xs-max) {
.atwho-view-ul {
width: 350px;
}
.atwho-view ul li {
overflow: hidden;
text-overflow: ellipsis;
}
}
// TODO: fallback to global style
.atwho-view {
// TODO: fallback to global style
.atwho-view-ul {
padding: 8px 1px;
@ -220,3 +207,14 @@
}
}
}
@media(max-width: $screen-xs-max) {
.atwho-view-ul {
width: 350px;
}
.atwho-view ul li {
overflow: hidden;
text-overflow: ellipsis;
}
}

View file

@ -3,57 +3,77 @@
max-width: #{$max + '%'};
}
.gl-responsive-table-row {
margin-top: 10px;
border: 1px solid $border-color;
.gl-responsive-table-row-layout {
width: 100%;
@media (min-width: $screen-md-min) {
padding: 15px 0;
margin: 0;
display: flex;
align-items: center;
border: none;
border-bottom: 1px solid $white-normal;
}
.table-section {
white-space: nowrap;
$section-widths: 10 15 20 25 30 40;
@each $width in $section-widths {
&.section-#{$width} {
flex: 0 0 #{$width + '%'};
@media (min-width: $screen-md-min) {
max-width: #{$width + '%'};
}
}
}
&:not(.table-button-footer) {
@media (max-width: $screen-sm-max) {
display: flex;
align-self: stretch;
padding: 10px;
align-items: center;
min-height: 62px;
&:not(:first-of-type) {
border-top: 1px solid $white-normal;
}
}
}
&.section-wrap {
white-space: normal;
@media (max-width: $screen-sm-max) {
flex-wrap: wrap;
}
& > &:not(:first-child) {
margin-top: $gl-padding;
}
}
}
.gl-responsive-table-row {
@extend .gl-responsive-table-row-layout;
margin-top: 10px;
border: 1px solid $border-color;
@media (min-width: $screen-md-min) {
margin: 0;
padding: $gl-padding 0;
border: none;
&:not(:last-child) {
border-bottom: 1px solid $white-normal;
}
}
}
.gl-responsive-table-row-col-span {
flex-wrap: wrap;
}
.table-section {
white-space: nowrap;
$section-widths: 10 15 20 25 30 40 100;
@each $width in $section-widths {
&.section-#{$width} {
flex: 0 0 #{$width + '%'};
@media (min-width: $screen-md-min) {
max-width: #{$width + '%'};
}
}
}
@media (max-width: $screen-sm-max) {
display: flex;
align-self: stretch;
padding: 10px;
align-items: center;
min-height: 62px;
&:not(:first-child) {
border-top: 1px solid $white-normal;
}
}
&.section-wrap {
white-space: normal;
@media (max-width: $screen-sm-max) {
flex-wrap: wrap;
}
}
&.section-align-top {
align-self: flex-start;
}
}
.table-button-footer {
@media (min-width: $screen-md-min) {
@ -61,12 +81,13 @@
}
@media (max-width: $screen-sm-max) {
background-color: $gray-normal;
display: block;
align-self: stretch;
min-height: 0;
background-color: $gray-normal;
border-top: 1px solid $border-color;
.table-action-buttons {
padding: 10px 5px;
display: flex;
.btn {
@ -77,7 +98,14 @@
> .external-url,
> .btn {
flex: 1 1 28px;
margin: 0 5px;
&:not(:first-child) {
margin-left: 5px;
}
&:not(:last-child) {
margin-right: 5px;
}
}
.dropdown-new {

View file

@ -340,11 +340,64 @@
}
}
.project-item-select-holder.btn-group {
display: flex;
max-width: 350px;
overflow: hidden;
float: right;
.page-with-layout-nav {
.right-sidebar {
top: ($header-height + 1) * 2;
}
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3;
&.affix {
top: $header-height;
}
}
}
}
.with-performance-bar .page-with-layout-nav {
.right-sidebar {
top: ($header-height + 1) * 2 + $performance-bar-height;
}
&.page-with-sub-nav {
.right-sidebar {
top: ($header-height + 1) * 3 + $performance-bar-height;
&.affix {
top: $header-height + $performance-bar-height;
}
}
}
}
@media (max-width: $screen-xs-max) {
.top-area {
flex-flow: row wrap;
.nav-controls {
$controls-margin: $btn-xs-side-margin - 2px;
flex: 0 0 100%;
&.controls-flex {
display: flex;
flex-flow: row wrap;
align-items: center;
justify-content: center;
padding: 0 0 $gl-padding-top;
}
.controls-item,
.controls-item-full,
.controls-item:last-child {
flex: 1 1 35%;
display: block;
width: 100%;
margin: $controls-margin;
}
}
}
.new-project-item-link {
white-space: nowrap;

View file

@ -60,22 +60,12 @@
border-radius: $border-radius-base;
border: 1px solid $dropdown-border-color;
min-width: 175px;
color: $gl-text-color;
z-index: 999;
color: $gl-grayish-blue;
}
.select2-drop-mask {
z-index: 998;
}
.select2-drop.select2-drop-above.select2-drop-active {
border-top: 1px solid $dropdown-border-color;
margin-top: -6px;
}
.select2-results li.select2-result-with-children > .select2-result-label {
font-weight: $gl-font-weight-bold;
color: $gl-text-color;
.select2-results .select2-result-label,
.select2-more-results {
padding: 10px 15px;
}
.select2-container-active {
@ -144,58 +134,46 @@
.select2-drop-auto-width & {
padding: 15px 15px 5px;
}
}
.select2-search input {
padding: 2px 25px 2px 5px;
background: $white-light image-url('select2.png');
background-repeat: no-repeat;
background-position: right 0 bottom 6px;
border: 1px solid $input-border;
border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
input {
padding: 2px 25px 2px 5px;
background: $white-light image-url('select2.png');
background-repeat: no-repeat;
background-position: right 0 bottom 6px;
border: 1px solid $input-border;
border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s;
&:focus {
border-color: $input-border-focus;
&:focus {
border-color: $input-border-focus;
}
&.select2-active {
background-color: $white-light;
background-image: image-url('select2-spinner.gif') !important;
background-repeat: no-repeat;
background-position: right 5px center !important;
background-size: 16px 16px !important;
}
}
}
.select2-search input.select2-active {
background-color: $white-light;
background-image: image-url('select2-spinner.gif') !important;
background-repeat: no-repeat;
background-position: right 5px center !important;
background-size: 16px 16px !important;
.select2-results .select2-no-results,
.select2-results .select2-searching,
.select2-results .select2-ajax-error,
.select2-results .select2-selection-limit {
background: $gray-light;
display: list-item;
padding: 10px 15px;
}
.select2-results {
margin: 0;
padding: #{$gl-padding / 2} 0;
padding: 10px 0;
.select2-no-results,
.select2-searching,
.select2-ajax-error,
.select2-selection-limit {
background: transparent;
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-result-label,
.select2-more-results {
padding: #{$gl-padding / 2} $gl-padding;
}
.select2-highlighted {
background: transparent;
li.select2-result-with-children > .select2-result-label {
font-weight: $gl-font-weight-bold;
color: $gl-text-color;
.select2-result-label {
background: $dropdown-item-hover-bg;
}
}
.select2-result {
padding: 0 1px;
}
}
@ -212,6 +190,8 @@
}
.select2-highlighted {
background: $gl-link-color !important;
.group-result {
.group-path {
color: $white-light;

View file

@ -217,13 +217,31 @@ $white-gc-bg: #eaf2f5;
.cp { color: $white-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $white-c1; font-style: italic; }
.cs { color: $white-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $white-gd; background-color: $white-gd-bg; }
.gd .x { color: $white-gd-x; background-color: $white-gd-x-bg; }
.gd {
color: $white-gd;
background-color: $white-gd-bg;
.x {
color: $white-gd-x;
background-color: $white-gd-x-bg;
}
}
.ge { font-style: italic; }
.gr { color: $white-gr; }
.gh { color: $white-gh; }
.gi { color: $white-gi; background-color: $white-gi-bg; }
.gi .x { color: $white-gi-x; background-color: $white-gi-x-bg; }
.gi {
color: $white-gi;
background-color: $white-gi-bg;
.x {
color: $white-gi-x;
background-color: $white-gi-x-bg;
}
}
.go { color: $white-go; }
.gp { color: $white-gp; }
.gs { font-weight: $gl-font-weight-bold; }

View file

@ -158,13 +158,31 @@ span.highlight_word {
.cp { color: $highlighted-cp; font-weight: $gl-font-weight-bold; }
.c1 { color: $highlighted-c1; font-style: italic; }
.cs { color: $highlighted-cs; font-weight: $gl-font-weight-bold; font-style: italic; }
.gd { color: $highlighted-gd; background-color: $highlighted-gd-bg; }
.gd .x { color: $highlighted-gd; background-color: $highlighted-gd-x-bg; }
.gd {
color: $highlighted-gd;
background-color: $highlighted-gd-bg;
.x {
color: $highlighted-gd;
background-color: $highlighted-gd-x-bg;
}
}
.ge { font-style: italic; }
.gr { color: $highlighted-gr; }
.gh { color: $highlighted-gh; }
.gi { color: $highlighted-gi; background-color: $highlighted-gi-bg; }
.gi .x { color: $highlighted-gi; background-color: $highlighted-gi-x-bg; }
.gi {
color: $highlighted-gi;
background-color: $highlighted-gi-bg;
.x {
color: $highlighted-gi;
background-color: $highlighted-gi-x-bg;
}
}
.go { color: $highlighted-go; }
.gp { color: $highlighted-gp; }
.gs { font-weight: $gl-font-weight-bold; }

View file

@ -72,7 +72,7 @@
}
.boards-list {
height: calc(100vh - 152px);
height: calc(100vh - 105px);
width: 100%;
padding-top: 25px;
padding-bottom: 25px;
@ -81,11 +81,12 @@
overflow-x: scroll;
white-space: nowrap;
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
// scss-lint:disable DuplicateProperty
height: calc(100vh - 222px);
// scss-lint:enable DuplicateProperty
@media (min-width: $screen-sm-min) and (max-width: $screen-sm-max) {
height: calc(100vh - 90px);
}
@media (min-width: $screen-md-min) {
height: calc(100vh - 160px);
min-height: 475px;
}
}

View file

@ -68,18 +68,18 @@
&.affix {
top: $header-height;
}
// with sidebar
&.affix.sidebar-expanded {
right: 306px;
left: 16px;
}
// with sidebar
&.sidebar-expanded {
right: 306px;
left: 16px;
}
// without sidebar
&.affix.sidebar-collapsed {
right: 16px;
left: 16px;
// without sidebar
&.sidebar-collapsed {
right: 16px;
left: 16px;
}
}
&.affix-top {
@ -333,8 +333,10 @@
svg {
position: relative;
top: 2px;
top: 3px;
margin-right: 3px;
width: 14px;
height: 14px;
}
}
@ -348,9 +350,10 @@
svg {
position: relative;
top: 2px;
top: 3px;
margin-right: 3px;
height: 13px;
height: 14px;
width: 14px;
}
a {
@ -369,7 +372,7 @@
.build-job {
position: relative;
.fa-arrow-right {
.icon-arrow-right {
position: absolute;
left: 15px;
top: 20px;
@ -379,7 +382,7 @@
&.active {
font-weight: $gl-font-weight-bold;
.fa-arrow-right {
.icon-arrow-right {
display: block;
}
}
@ -392,8 +395,7 @@
background-color: $row-hover;
}
.fa-refresh {
font-size: 13px;
.icon-retry {
margin-left: 3px;
}
}

View file

@ -2,8 +2,4 @@
.clipboard-addon {
background-color: $white-light;
}
.alert-block {
margin-bottom: 10px;
}
}

View file

@ -22,6 +22,11 @@
}
}
}
svg {
width: 136px;
height: 136px;
}
}
.col-headers {
@ -155,11 +160,6 @@
}
}
.landing svg {
width: 136px;
height: 136px;
}
.fa-spinner {
font-size: 28px;
position: relative;

View file

@ -380,6 +380,10 @@
}
}
}
.line_content {
white-space: pre-wrap;
}
}
.file-content .diff-file {
@ -387,10 +391,6 @@
border: none;
}
.diff-file .line_content {
white-space: pre-wrap;
}
.diff-wrap-lines .line_content {
white-space: pre-wrap;
}

View file

@ -133,12 +133,11 @@
}
.folder-row {
padding: 15px 0;
border-bottom: 1px solid $white-normal;
border-left: none;
border-right: none;
@media (max-width: $screen-sm-max) {
border-top: 1px solid $white-normal;
margin-top: 10px;
@media (min-width: $screen-sm-max) {
border-top: none;
}
}
@ -256,23 +255,6 @@
width: 100%;
padding: 0;
padding-bottom: 100%;
}
.prometheus-svg-container > svg {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
text {
fill: $gl-text-color;
stroke-width: 0;
}
.text-metric-bold {
font-weight: $gl-font-weight-bold;
}
.label-axis-text {
fill: $black;
@ -287,42 +269,51 @@
font-size: 12px;
}
.legend-axis-text {
fill: $black;
}
> svg {
position: absolute;
height: 100%;
width: 100%;
left: 0;
top: 0;
.tick {
> line {
stroke: $gray-darker;
}
> text {
.label-axis-text,
.text-metric-usage {
fill: $black;
font-weight: $gl-font-weight-normal;
font-size: 12px;
}
}
.text-metric-title {
font-size: 12px;
}
.y-label-text,
.x-label-text {
fill: $gray-darkest;
}
.axis-tick {
stroke: $gray-darker;
}
@media (max-width: $screen-sm-max) {
.label-axis-text,
.text-metric-usage,
.legend-axis-text {
font-size: 8px;
fill: $black;
}
.tick > text {
font-size: 8px;
font-size: 12px;
}
.text-metric-title {
font-size: 12px;
}
.y-label-text,
.x-label-text {
fill: $gray-darkest;
}
.axis-tick {
stroke: $gray-darker;
}
@media (max-width: $screen-sm-max) {
.label-axis-text,
.text-metric-usage,
.legend-axis-text {
font-size: 8px;
}
.tick > text {
font-size: 8px;
}
}
}
}

View file

@ -127,7 +127,16 @@
}
.right-sidebar {
a:not(.btn-retry),
position: absolute;
top: $header-height;
bottom: 0;
right: 0;
transition: width .3s;
background: $gray-light;
z-index: 200;
overflow: hidden;
a,
.btn-link {
color: inherit;
}
@ -228,17 +237,6 @@
.btn-clipboard:hover {
color: $gl-text-color;
}
}
.right-sidebar {
position: absolute;
top: $header-height;
bottom: 0;
right: 0;
transition: width $right-sidebar-transition-duration;
background: $gray-light;
z-index: 200;
overflow: hidden;
.issuable-sidebar {
width: calc(100% + 100px);

View file

@ -109,6 +109,30 @@
border-top-right-radius: $border-radius-default;
border-top-left-radius: $border-radius-default;
// Ldap configurations may need more tabs & the tab labels are user generated (arbitrarily long).
// These styles prevent this from breaking the layout, and only applied when providers are configured.
&.custom-provider-tabs {
flex-wrap: wrap;
li {
min-width: 85px;
flex-basis: auto;
// This styles tab elements that have wrapped to a second line. We cannot easily predict when this will happen.
// We are making somewhat of an assumption about the configuration here: that users do not have more than
// 3 LDAP servers configured (in addition to standard login) and they are not using especially long names for any
// of them. If either condition is false, this will work as expected. If both are true, there may be a missing border
// above one of the bottom row elements. If you know a better way, please implement it!
&:nth-child(n+5) {
border-top: 1px solid $border-color;
}
}
a {
font-size: 16px;
}
}
li {
flex: 1;
text-align: center;
@ -154,32 +178,6 @@
}
}
// Ldap configurations may need more tabs & the tab labels are user generated (arbitrarily long).
// These styles prevent this from breaking the layout, and only applied when providers are configured.
.new-session-tabs.custom-provider-tabs {
flex-wrap: wrap;
li {
min-width: 85px;
flex-basis: auto;
// This styles tab elements that have wrapped to a second line. We cannot easily predict when this will happen.
// We are making somewhat of an assumption about the configuration here: that users do not have more than
// 3 LDAP servers configured (in addition to standard login) and they are not using especially long names for any
// of them. If either condition is false, this will work as expected. If both are true, there may be a missing border
// above one of the bottom row elements. If you know a better way, please implement it!
&:nth-child(n+5) {
border-top: 1px solid $border-color;
}
}
a {
font-size: 16px;
}
}
.form-control {
&:active,
&:focus {
@ -231,35 +229,35 @@
margin: 0;
padding: 0;
height: 100%;
}
// Fixes footer container to bottom of viewport
.devise-layout-html body {
// offset height of fixed header + 1 to avoid scroll
height: calc(100% - 51px);
margin: 0;
padding: 0;
// Fixes footer container to bottom of viewport
body {
// offset height of fixed header + 1 to avoid scroll
height: calc(100% - 51px);
margin: 0;
padding: 0;
.page-wrap {
min-height: 100%;
position: relative;
}
.page-wrap {
min-height: 100%;
position: relative;
}
.footer-container,
hr.footer-fixed {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: $white-light;
}
.footer-container,
hr.footer-fixed {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: $white-light;
}
.navless-container {
padding: 65px 15px; // height of footer + bottom padding of email confirmation link
.navless-container {
padding: 65px 15px; // height of footer + bottom padding of email confirmation link
@media (max-width: $screen-xs-max) {
padding: 0 15px 65px;
@media (max-width: $screen-xs-max) {
padding: 0 15px 65px;
}
}
}
}

View file

@ -49,9 +49,17 @@
width: auto;
}
}
&.existing-title {
@media (min-width: $screen-sm-min) {
float: left;
}
}
}
.member-form-control {
@include new-style-dropdown;
@media (max-width: $screen-xs-max) {
padding-bottom: 5px;
margin-left: 0;
@ -64,12 +72,6 @@
line-height: 43px;
}
.member.existing-title {
@media (min-width: $screen-sm-min) {
float: left;
}
}
.member-search-form {
@include new-style-dropdown;
@ -281,7 +283,3 @@
}
}
}
.member-form-control {
@include new-style-dropdown;
}

View file

@ -156,6 +156,10 @@
&.media > *:first-child {
margin-right: 10px;
}
.approve-btn {
margin-right: 5px;
}
}
.mr-widget-pipeline-graph {
@ -165,8 +169,9 @@
z-index: 300;
}
.ci-action-icon-wrapper {
line-height: 16px;
.ci-action-icon-wrapper svg {
width: 16px;
height: 16px;
}
}
@ -190,6 +195,10 @@
overflow: hidden;
word-break: break-all;
&.media > *:first-child {
margin-right: 10px;
}
&.label-truncated {
position: relative;
display: inline-block;
@ -207,14 +216,7 @@
background-color: $gray-light;
}
}
}
.mr-widget-help {
padding: 10px 16px 10px 48px;
font-style: italic;
}
.mr-widget-body {
h4 {
float: left;
font-weight: $gl-font-weight-bold;
@ -237,6 +239,10 @@
margin-right: 7px;
}
.approve-btn {
margin-right: 5px;
}
label {
font-weight: $gl-font-weight-normal;
}
@ -336,6 +342,22 @@
}
}
.mini-pipeline-graph-dropdown-menu .mini-pipeline-graph-dropdown-item {
display: flex;
align-items: center;
.ci-status-text,
.ci-status-icon {
top: 0;
margin-right: 10px;
}
}
.mr-widget-help {
padding: 10px 16px 10px 48px;
font-style: italic;
}
.ci-coverage {
float: right;
}
@ -350,12 +372,6 @@
}
}
.mr-state-widget .mr-widget-body {
.approve-btn {
margin-right: 5px;
}
}
.mr-widget-body-controls {
flex-wrap: wrap;
}
@ -469,16 +485,16 @@
padding-bottom: 0;
}
}
}
.mr-info-list.mr-memory-usage {
p {
float: left;
}
&.mr-memory-usage {
p {
float: left;
}
.memory-graph-container {
float: left;
margin-left: 5px;
.memory-graph-container {
float: left;
margin-left: 5px;
}
}
}

View file

@ -66,6 +66,15 @@
height: 6px;
margin: 0;
}
.sidebar-collapsed-icon {
clear: both;
padding: 15px 5px 5px;
.progress {
margin: 5px 0;
}
}
}
.collapsed-milestone-date {
@ -93,17 +102,6 @@
margin-right: 0;
}
.milestone-progress {
.sidebar-collapsed-icon {
clear: both;
padding: 15px 5px 5px;
.progress {
margin: 5px 0;
}
}
}
.right-sidebar-collapsed & {
.reference {
border-top: 1px solid $border-gray-normal;
@ -156,18 +154,16 @@
.status-box {
margin-top: 0;
}
.milestone-buttons {
margin-left: auto;
}
.status-box {
order: 1;
}
.milestone-buttons {
margin-left: auto;
order: 2;
.verbose {
display: none;
}
}
.header-text-content {
@ -175,10 +171,6 @@
width: 100%;
}
.milestone-buttons .verbose {
display: none;
}
@media (min-width: $screen-xs-min) {
.milestone-buttons .verbose {
display: inline;

View file

@ -111,24 +111,9 @@
margin: auto;
align-items: center;
.icon {
margin-right: $issuable-warning-icon-margin;
}
}
.disabled-comment .issuable-note-warning {
border: none;
border-radius: $label-border-radius;
padding-top: $gl-vert-padding;
padding-bottom: $gl-vert-padding;
.icon svg {
position: relative;
top: 2px;
margin-right: $btn-xs-side-margin;
width: $gl-font-size;
height: $gl-font-size;
fill: $orange-600;
+ .md-area {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
}
@ -155,11 +140,6 @@
}
}
.issuable-note-warning + .md-area {
border-top-left-radius: 0;
border-top-right-radius: 0;
}
.discussion-form {
background-color: $white-light;
}

View file

@ -312,57 +312,72 @@ ul.notes {
}
}
.diff-file .notes_holder {
font-family: $regular_font;
td {
border: 1px solid $white-normal;
border-left: none;
&.notes_line {
vertical-align: middle;
text-align: center;
padding: 10px 0;
background: $gray-light;
color: $text-color;
.diff-file {
.is-over {
.add-diff-note {
display: inline-block;
}
}
&.notes_line2 {
text-align: center;
padding: 10px 0;
border-left: 1px solid $note-line2-border !important;
}
// Merge request notes in diffs
// Diff is inline
.notes_content .note-header .note-headline-light {
display: inline-block;
position: relative;
}
&.notes_content {
background-color: $gray-light;
border-width: 1px 0;
padding: 0;
vertical-align: top;
white-space: normal;
.notes_holder {
font-family: $regular_font;
&.parallel {
border-width: 1px;
td {
border: 1px solid $white-normal;
border-left: none;
&.notes_line {
vertical-align: middle;
text-align: center;
padding: 10px 0;
background: $gray-light;
color: $text-color;
}
.discussion-notes {
&:not(:first-child) {
border-top: 1px solid $white-normal;
margin-top: 20px;
&.notes_line2 {
text-align: center;
padding: 10px 0;
border-left: 1px solid $note-line2-border !important;
}
&.notes_content {
background-color: $gray-light;
border-width: 1px 0;
padding: 0;
vertical-align: top;
white-space: normal;
&.parallel {
border-width: 1px;
}
&:not(:last-child) {
border-bottom: 1px solid $white-normal;
margin-bottom: 20px;
.discussion-notes {
&:not(:first-child) {
border-top: 1px solid $white-normal;
margin-top: 20px;
}
&:not(:last-child) {
border-bottom: 1px solid $white-normal;
margin-bottom: 20px;
}
}
}
.notes {
background-color: $white-light;
}
.notes {
background-color: $white-light;
}
a code {
top: 0;
margin-right: 0;
a code {
top: 0;
margin-right: 0;
}
}
}
}
@ -457,8 +472,9 @@ ul.notes {
margin-left: 10px;
color: $gray-darkest;
.btn-group > .discussion-next-btn {
margin-left: -1px;
@include notes-media('max', $screen-md-max) {
float: none;
margin-left: 0;
}
}
@ -469,8 +485,6 @@ ul.notes {
flex-shrink: 0;
display: inline-flex;
align-items: center;
// For PhantomJS that does not support flex
float: right;
margin-left: 10px;
color: $gray-darkest;
@ -481,7 +495,6 @@ ul.notes {
}
.more-actions {
float: right; // phantomjs fallback
display: flex;
align-items: flex-end;
@ -502,13 +515,6 @@ ul.notes {
min-width: 180px;
}
.discussion-actions {
@include notes-media('max', $screen-md-max) {
float: none;
margin-left: 0;
}
}
.note-actions-item {
margin-left: 12px;
display: flex;
@ -665,14 +671,6 @@ ul.notes {
}
}
.diff-file {
.is-over {
.add-diff-note {
display: inline-block;
}
}
}
.disabled-comment {
background-color: $gray-light;
border-radius: $border-radius-base;
@ -714,20 +712,20 @@ ul.notes {
svg path {
fill: $gray-darkest;
}
}
.btn.discussion-create-issue-btn {
margin-left: -4px;
border-radius: 0;
border-right: 0;
&.discussion-create-issue-btn {
margin-left: -4px;
border-radius: 0;
border-right: 0;
a {
padding: 0;
line-height: 0;
a {
padding: 0;
line-height: 0;
&:hover {
text-decoration: none;
border: 0;
&:hover {
text-decoration: none;
border: 0;
}
}
}
}
@ -801,12 +799,3 @@ ul.notes {
.line-resolve-text {
vertical-align: middle;
}
// Merge request notes in diffs
.diff-file {
// Diff is inline
.notes_content .note-header .note-headline-light {
display: inline-block;
position: relative;
}
}

View file

@ -31,7 +31,6 @@
}
.pipeline-actions {
padding-right: 0;
min-width: 170px; //Guarantees buttons don't break in several lines.
.btn-default {
@ -176,6 +175,25 @@
}
}
/**
* Play button with icon in dropdowns
*/
.no-btn {
border: none;
background: none;
outline: none;
width: 100%;
text-align: left;
.icon-play {
position: relative;
top: 2px;
margin-right: 5px;
height: 13px;
width: 12px;
}
}
.duration,
.finished-at {
color: $gl-text-color-secondary;
@ -451,36 +469,46 @@
@extend .build-content:hover;
}
// Action Icons in big pipeline-graph nodes
.ci-action-icon-container .ci-action-icon-wrapper {
height: 30px;
width: 30px;
background: $white-light;
border: 1px solid $border-color;
border-radius: 100%;
display: block;
&:hover {
background-color: $stage-hover-bg;
border: 1px solid $dropdown-toggle-active-border-color;
}
svg {
fill: $gl-text-color-secondary;
position: relative;
left: -1px;
top: -1px;
}
&:hover svg {
fill: $gl-text-color;
}
}
.ci-action-icon-container {
position: absolute;
right: 5px;
top: 5px;
// Action Icons in big pipeline-graph nodes
&.ci-action-icon-wrapper {
height: 30px;
width: 30px;
background: $white-light;
border: 1px solid $border-color;
border-radius: 100%;
display: block;
&:hover {
background-color: $stage-hover-bg;
border: 1px solid $dropdown-toggle-active-border-color;
svg {
fill: $gl-text-color;
}
}
svg {
fill: $gl-text-color-secondary;
position: relative;
left: 5px;
top: 2px;
width: 18px;
height: 18px;
}
&.play {
svg {
width: #{$ci-action-icon-size - 8};
height: #{$ci-action-icon-size - 8};
left: 8px;
}
}
}
}
.ci-status-icon svg {
@ -721,17 +749,50 @@ button.mini-pipeline-graph-dropdown-toggle {
svg {
fill: $gl-text-color-secondary;
width: $ci-action-icon-size;
height: $ci-action-icon-size;
left: -6px;
width: #{$ci-action-icon-size - 6};
height: #{$ci-action-icon-size - 6};
left: -3px;
position: relative;
top: -3px;
top: -2px;
&.icon-action-stop,
&.icon-action-cancel {
width: 12px;
height: 12px;
top: 1px;
left: -1px;
}
&.icon-action-play {
width: 11px;
height: 11px;
top: 1px;
left: 1px;
}
&.icon-action-retry {
width: 16px;
height: 16px;
top: 0;
left: -3px;
}
}
&:hover svg,
&:focus svg {
fill: $gl-text-color;
}
&.icon-action-retry,
&.icon-action-play {
svg {
width: #{$ci-action-icon-size - 6};
height: #{$ci-action-icon-size - 6};
left: 8px;
}
}
}
// link to the build
@ -799,13 +860,10 @@ button.mini-pipeline-graph-dropdown-toggle {
left: 100%;
top: -10px;
box-shadow: 0 1px 5px $black-transparent;
}
/**
* Top arrow in the dropdown in the big pipeline graph
*/
.big-pipeline-graph-dropdown-menu {
/**
* Top arrow in the dropdown in the big pipeline graph
*/
&::before,
&::after {
content: '';
@ -867,22 +925,23 @@ button.mini-pipeline-graph-dropdown-toggle {
margin-top: 1px;
border-bottom-color: $white-light;
}
}
/**
* Center dropdown menu in mini graph
*/
.mini-pipeline-graph-dropdown-menu.dropdown-menu {
transform: translate(-80%, 0);
min-width: 150px;
/**
* Center dropdown menu in mini graph
*/
&.dropdown-menu {
transform: translate(-80%, 0);
min-width: 150px;
@media(min-width: $screen-md-min) {
transform: translate(-50%, 0);
right: auto;
left: 50%;
min-width: 240px;
@media(min-width: $screen-md-min) {
transform: translate(-50%, 0);
right: auto;
left: 50%;
min-width: 240px;
}
}
}
/**
* Terminal
*/
@ -906,25 +965,6 @@ button.mini-pipeline-graph-dropdown-toggle {
}
}
/**
* Play button with icon in dropdowns
*/
.ci-table .no-btn {
border: none;
background: none;
outline: none;
width: 100%;
text-align: left;
.icon-play {
position: relative;
top: 2px;
margin-right: 5px;
height: 13px;
width: 12px;
}
}
.ci-header-container {
min-height: 55px;

View file

@ -88,7 +88,8 @@
transition: background 2s ease-out;
&:disabled {
opacity: 0.75;
opacity: 0.5;
pointer-events: none;
}
.highlight-changes & {
@ -778,35 +779,35 @@ a.deploy-project-label {
.nav {
padding-top: 12px;
padding-bottom: 12px;
}
.nav > li {
display: inline-block;
> li {
display: inline-block;
&:not(:last-child) {
margin-right: $gl-padding;
}
&.right {
vertical-align: top;
margin-top: 0;
@media (min-width: $screen-lg-min) {
float: right;
&:not(:last-child) {
margin-right: $gl-padding;
}
}
}
.nav > li > a {
padding: 0;
background-color: transparent;
font-size: 14px;
line-height: 29px;
color: $notes-light-color;
&.right {
vertical-align: top;
margin-top: 0;
&:hover,
&:focus {
color: $gl-text-color;
@media (min-width: $screen-lg-min) {
float: right;
}
}
> a {
padding: 0;
background-color: transparent;
font-size: 14px;
line-height: 29px;
color: $notes-light-color;
&:hover,
&:focus {
color: $gl-text-color;
}
}
}
}
@ -1160,13 +1161,6 @@ pre.light-well {
}
}
.project-repo-select {
&.disabled {
opacity: 0.5;
pointer-events: none;
}
}
.variables-table {
table-layout: fixed;

View file

@ -78,6 +78,10 @@ input[type="checkbox"]:hover {
}
.search-input-wrap {
// Fallback if flexbox is not supported
display: inline-block;
width: 100%;
.search-icon,
.clear-icon {
position: absolute;

View file

@ -23,15 +23,14 @@
}
.settings {
overflow: hidden;
border-bottom: 1px solid $gray-darker;
&:first-of-type {
margin-top: 10px;
}
&.expanded {
overflow: visible;
&.animating {
overflow: hidden;
}
}
@ -56,14 +55,18 @@
overflow-y: scroll;
padding-right: 110px;
animation: collapseMaxHeight 300ms ease-out;
// Keep the section from expanding when we scroll over it
pointer-events: none;
&.expanded {
.settings.expanded & {
max-height: none;
overflow-y: visible;
animation: expandMaxHeight 300ms ease-in;
// Reset and allow clicks again when expanded
pointer-events: auto;
}
&.no-animate {
.settings.no-animate & {
animation: none;
}
@ -238,11 +241,11 @@
margin-left: 5px;
background: $badge-bg;
}
}
/* Ensure we don't add border if there's only single li */
li + li {
border-top: 1px solid $border-color;
/* Ensure we don't add border if there's only single li */
+ li {
border-top: 1px solid $border-color;
}
}
}
}

View file

@ -5,10 +5,10 @@ table .sherlock-code {
.sherlock-code {
pre {
word-wrap: normal;
}
pre code {
white-space: pre;
code {
white-space: pre;
}
}
}
@ -21,13 +21,13 @@ table .sherlock-code {
text-align: right;
padding: 0 10px !important;
}
.slow {
color: $red-500;
font-weight: $gl-font-weight-bold;
}
}
.sherlock-file-sample pre {
padding-top: 28px !important;
}
.sherlock-line-samples-table .slow {
color: $red-500;
font-weight: $gl-font-weight-bold;
}

View file

@ -40,16 +40,16 @@
@media (max-width: $screen-xs-max) {
width: 100%;
}
}
.person .spark {
display: block;
background: $stat-graph-common-bg;
width: 100%;
}
.spark {
display: block;
background: $stat-graph-common-bg;
width: 100%;
}
.person .area-contributor {
fill: $stat-graph-orange-fill;
.area-contributor {
fill: $stat-graph-orange-fill;
}
}
}

View file

@ -161,10 +161,10 @@ ul.wiki-pages-list.content-list {
list-style: none;
margin-left: 0;
padding-left: 15px;
}
ul li {
padding: 5px 0;
li {
padding: 5px 0;
}
}
}

View file

@ -4,11 +4,6 @@
-ms-transition: none !important;
-webkit-transition: none !important;
transition: none !important;
-o-transform: none !important;
-moz-transform: none !important;
-ms-transform: none !important;
-webkit-transform: none !important;
transform: none !important;
-webkit-animation: none !important;
-moz-animation: none !important;
-o-animation: none !important;

View file

@ -19,10 +19,12 @@ class Admin::ApplicationsController < Admin::ApplicationController
end
def create
@application = Doorkeeper::Application.new(application_params)
@application = Applications::CreateService.new(current_user, application_params).execute(request)
if @application.save
redirect_to_admin_page
if @application.persisted?
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to admin_application_url(@application)
else
render :new
end
@ -41,13 +43,6 @@ class Admin::ApplicationsController < Admin::ApplicationController
redirect_to admin_applications_url, status: 302, notice: 'Application was successfully destroyed.'
end
protected
def redirect_to_admin_page
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to admin_application_url(@application)
end
private
def set_application

View file

@ -44,7 +44,7 @@ class Admin::ImpersonationTokensController < Admin::ApplicationController
end
def set_index_vars
@scopes = Gitlab::Auth::API_SCOPES
@scopes = Gitlab::Auth.available_scopes(current_user)
@impersonation_token ||= finder.build
@inactive_impersonation_tokens = finder(state: 'inactive').execute

View file

@ -11,7 +11,7 @@ class ApplicationController < ActionController::Base
include EnforcesTwoFactorAuthentication
include WithPerformanceBar
before_action :authenticate_user_from_private_token!
before_action :authenticate_user_from_personal_access_token!
before_action :authenticate_user_from_rss_token!
before_action :authenticate_user!
before_action :validate_user_service_ticket!
@ -100,13 +100,12 @@ class ApplicationController < ActionController::Base
return try(:authenticated_user)
end
# This filter handles both private tokens and personal access tokens
def authenticate_user_from_private_token!
def authenticate_user_from_personal_access_token!
token = params[:private_token].presence || request.headers['PRIVATE-TOKEN'].presence
return unless token.present?
user = User.find_by_authentication_token(token) || User.find_by_personal_access_token(token)
user = User.find_by_personal_access_token(token)
sessionless_sign_in(user)
end

View file

@ -7,6 +7,54 @@ module IssuableActions
before_action :authorize_admin_issuable!, only: :bulk_update
end
def show
respond_to do |format|
format.html do
render show_view
end
format.json do
render json: serializer.represent(issuable, serializer: params[:serializer])
end
end
end
def update
@issuable = update_service.execute(issuable)
respond_to do |format|
format.html do
recaptcha_check_with_fallback { render :edit }
end
format.json do
render_entity_json
end
end
rescue ActiveRecord::StaleObjectError
render_conflict_response
end
def realtime_changes
Gitlab::PollingInterval.set_header(response, interval: 3_000)
response = {
title: view_context.markdown_field(issuable, :title),
title_text: issuable.title,
description: view_context.markdown_field(issuable, :description),
description_text: issuable.description,
task_status: issuable.task_status
}
if issuable.edited?
response[:updated_at] = issuable.updated_at
response[:updated_by_name] = issuable.last_edited_by.name
response[:updated_by_path] = user_path(issuable.last_edited_by)
end
render json: response
end
def destroy
issuable.destroy
destroy_method = "destroy_#{issuable.class.name.underscore}".to_sym
@ -68,6 +116,10 @@ module IssuableActions
end
end
def authorize_update_issuable!
render_404 unless can?(current_user, :"update_#{resource_name}", issuable)
end
def bulk_update_params
permitted_keys = [
:issuable_ids,
@ -92,4 +144,24 @@ module IssuableActions
def resource_name
@resource_name ||= controller_name.singularize
end
def render_entity_json
if @issuable.valid?
render json: serializer.represent(@issuable)
else
render json: { errors: @issuable.errors.full_messages }, status: :unprocessable_entity
end
end
def show_view
'show'
end
def serializer
raise NotImplementedError
end
def update_service
raise NotImplementedError
end
end

View file

@ -94,10 +94,9 @@ module LfsRequest
@storage_project ||= begin
result = project
loop do
break unless result.forked?
result = result.forked_from_project
end
# TODO: Make this go to the fork_network root immeadiatly
# dependant on the discussion in: https://gitlab.com/gitlab-org/gitlab-ce/issues/39769
result = result.fork_source while result.forked?
result
end

View file

@ -4,6 +4,7 @@ module NotesActions
included do
before_action :set_polling_interval_header, only: [:index]
before_action :noteable, only: :index
before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :note_project, only: [:create]
end
@ -188,7 +189,7 @@ module NotesActions
end
def noteable
@noteable ||= notes_finder.target
@noteable ||= notes_finder.target || render_404
end
def last_fetched_at

View file

@ -30,11 +30,11 @@ class JwtController < ApplicationController
render_unauthorized
end
end
rescue Gitlab::Auth::MissingPersonalTokenError
render_missing_personal_token
rescue Gitlab::Auth::MissingPersonalAccessTokenError
render_missing_personal_access_token
end
def render_missing_personal_token
def render_missing_personal_access_token
render json: {
errors: [
{ code: 'UNAUTHORIZED',

View file

@ -16,25 +16,18 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
end
def create
@application = Doorkeeper::Application.new(application_params)
@application = Applications::CreateService.new(current_user, create_application_params).execute(request)
@application.owner = current_user
if @application.persisted?
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
if @application.save
redirect_to_oauth_application_page
redirect_to oauth_application_url(@application)
else
set_index_vars
render :index
end
end
protected
def redirect_to_oauth_application_page
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to oauth_application_url(@application)
end
private
def verify_user_oauth_applications_enabled
@ -61,4 +54,10 @@ class Oauth::ApplicationsController < Doorkeeper::ApplicationsController
rescue_from ActiveRecord::RecordNotFound do |exception|
render "errors/not_found", layout: "errors", status: 404
end
def create_application_params
application_params.tap do |params|
params[:owner] = current_user
end
end
end

View file

@ -11,10 +11,10 @@ class Profiles::KeysController < Profiles::ApplicationController
end
def create
@key = Keys::CreateService.new(current_user, key_params).execute
@key = Keys::CreateService.new(current_user, key_params.merge(ip_address: request.remote_ip)).execute
if @key.persisted?
redirect_to_profile_key_path
redirect_to profile_key_path(@key)
else
@keys = current_user.keys.select(&:persisted?)
render :index
@ -50,12 +50,6 @@ class Profiles::KeysController < Profiles::ApplicationController
end
end
protected
def redirect_to_profile_key_path
redirect_to profile_key_path(@key)
end
private
def key_params

View file

@ -39,7 +39,7 @@ class Profiles::PersonalAccessTokensController < Profiles::ApplicationController
end
def set_index_vars
@scopes = Gitlab::Auth.available_scopes
@scopes = Gitlab::Auth.available_scopes(current_user)
@inactive_personal_access_tokens = finder(state: 'inactive').execute
@active_personal_access_tokens = finder(state: 'active').execute.order(:expires_at)

View file

@ -24,16 +24,6 @@ class ProfilesController < Profiles::ApplicationController
end
end
def reset_private_token
Users::UpdateService.new(current_user, user: @user).execute! do |user|
user.reset_authentication_token!
end
flash[:notice] = "Private token was successfully reset"
redirect_to profile_account_path
end
def reset_incoming_email_token
Users::UpdateService.new(current_user, user: @user).execute! do |user|
user.reset_incoming_email_token!
@ -41,7 +31,7 @@ class ProfilesController < Profiles::ApplicationController
flash[:notice] = "Incoming email token was successfully reset"
redirect_to profile_account_path
redirect_to profile_personal_access_tokens_path
end
def reset_rss_token
@ -51,7 +41,7 @@ class ProfilesController < Profiles::ApplicationController
flash[:notice] = "RSS token was successfully reset"
redirect_to profile_account_path
redirect_to profile_personal_access_tokens_path
end
def audit_log

View file

@ -53,8 +53,8 @@ class Projects::GitHttpClientController < Projects::ApplicationController
send_challenges
render plain: "HTTP Basic: Access denied\n", status: 401
rescue Gitlab::Auth::MissingPersonalTokenError
render_missing_personal_token
rescue Gitlab::Auth::MissingPersonalAccessTokenError
render_missing_personal_access_token
end
def basic_auth_provided?
@ -78,7 +78,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
@project, @wiki, @redirected_path = Gitlab::RepoPath.parse("#{params[:namespace_id]}/#{params[:project_id]}")
end
def render_missing_personal_token
def render_missing_personal_access_token
render plain: "HTTP Basic: Access denied\n" \
"You must use a personal access token with 'api' scope for Git over HTTP.\n" \
"You can generate one at #{profile_personal_access_tokens_url}",

View file

@ -16,7 +16,7 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :authorize_create_issue!, only: [:new, :create]
# Allow modify issue
before_action :authorize_update_issue!, only: [:edit, :update, :move]
before_action :authorize_update_issuable!, only: [:edit, :update, :move]
# Allow create a new branch and empty WIP merge request from current issue
before_action :authorize_create_merge_request!, only: [:create_merge_request]
@ -67,18 +67,6 @@ class Projects::IssuesController < Projects::ApplicationController
respond_with(@issue)
end
def show
@noteable = @issue
@note = @project.notes.new(noteable: @issue)
respond_to do |format|
format.html
format.json do
render json: serializer.represent(@issue, serializer: params[:serializer])
end
end
end
def discussions
notes = @issue.notes
.inc_relations_for_view
@ -120,25 +108,6 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
def update
update_params = issue_params.merge(spammable_params)
@issue = Issues::UpdateService.new(project, current_user, update_params).execute(issue)
respond_to do |format|
format.html do
recaptcha_check_with_fallback { render :edit }
end
format.json do
render_issue_json
end
end
rescue ActiveRecord::StaleObjectError
render_conflict_response
end
def move
params.require(:move_to_project_id)
@ -196,26 +165,6 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
def realtime_changes
Gitlab::PollingInterval.set_header(response, interval: 3_000)
response = {
title: view_context.markdown_field(@issue, :title),
title_text: @issue.title,
description: view_context.markdown_field(@issue, :description),
description_text: @issue.description,
task_status: @issue.task_status
}
if @issue.edited?
response[:updated_at] = @issue.updated_at
response[:updated_by_name] = @issue.last_edited_by.name
response[:updated_by_path] = user_path(@issue.last_edited_by)
end
render json: response
end
def create_merge_request
result = ::MergeRequests::CreateFromIssueService.new(project, current_user, issue_iid: issue.iid).execute
@ -231,7 +180,8 @@ class Projects::IssuesController < Projects::ApplicationController
def issue
return @issue if defined?(@issue)
# The Sortable default scope causes performance issues when used with find_by
@noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take!
@issuable = @noteable = @issue ||= @project.issues.where(iid: params[:id]).reorder(nil).take!
@note = @project.notes.new(noteable: @issuable)
return render_404 unless can?(current_user, :read_issue, @issue)
@ -246,14 +196,6 @@ class Projects::IssuesController < Projects::ApplicationController
project_issue_path(@project, @issue)
end
def authorize_update_issue!
render_404 unless can?(current_user, :update_issue, @issue)
end
def authorize_admin_issues!
render_404 unless can?(current_user, :admin_issue, @project)
end
def authorize_create_merge_request!
render_404 unless can?(current_user, :push_code, @project) && @issue.can_be_worked_on?(current_user)
end
@ -305,4 +247,9 @@ class Projects::IssuesController < Projects::ApplicationController
def serializer
IssueSerializer.new(current_user: current_user, project: issue.project)
end
def update_service
update_params = issue_params.merge(spammable_params)
Issues::UpdateService.new(project, current_user, update_params)
end
end

View file

@ -9,7 +9,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
skip_before_action :merge_request, only: [:index, :bulk_update]
skip_before_action :ensure_ref_fetched, only: [:index, :bulk_update]
before_action :authorize_update_merge_request!, only: [:close, :edit, :update, :remove_wip, :sort]
before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort]
before_action :authenticate_user!, only: [:assign_related_issues]
@ -256,14 +256,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
alias_method :issuable, :merge_request
alias_method :awardable, :merge_request
def authorize_update_merge_request!
return render_404 unless can?(current_user, :update_merge_request, @merge_request)
end
def authorize_admin_merge_request!
return render_404 unless can?(current_user, :admin_merge_request, @merge_request)
end
def validates_merge_request
# Show git not found page
# if there is no saved commits between source & target branch

View file

@ -63,34 +63,34 @@ module CiStatusHelper
def ci_icon_for_status(status)
if detailed_status?(status)
return custom_icon(status.icon)
return sprite_icon(status.icon)
end
icon_name =
case status
when 'success'
'icon_status_success'
'status_success'
when 'success_with_warnings'
'icon_status_warning'
'status_warning'
when 'failed'
'icon_status_failed'
'status_failed'
when 'pending'
'icon_status_pending'
'status_pending'
when 'running'
'icon_status_running'
'status_running'
when 'play'
'icon_play'
'play'
when 'created'
'icon_status_created'
'status_created'
when 'skipped'
'icon_status_skipped'
'status_skipped'
when 'manual'
'icon_status_manual'
'status_manual'
else
'icon_status_canceled'
'status_canceled'
end
custom_icon(icon_name)
sprite_icon(icon_name, size: 16)
end
def pipeline_status_cache_key(pipeline_status)

View file

@ -71,11 +71,13 @@ module GitlabRoutingHelper
project_commit_url(entity.project, entity.sha, *args)
end
def preview_markdown_path(project, *args)
def preview_markdown_path(parent, *args)
return group_preview_markdown_path(parent) if parent.is_a?(Group)
if @snippet.is_a?(PersonalSnippet)
preview_markdown_snippets_path
else
preview_markdown_project_path(project, *args)
preview_markdown_project_path(parent, *args)
end
end

View file

@ -211,15 +211,13 @@ module IssuablesHelper
def issuable_initial_data(issuable)
data = {
endpoint: project_issue_path(@project, issuable),
canUpdate: can?(current_user, :update_issue, issuable),
canDestroy: can?(current_user, :destroy_issue, issuable),
endpoint: issuable_path(issuable),
canUpdate: can?(current_user, :"update_#{issuable.to_ability_name}", issuable),
canDestroy: can?(current_user, :"destroy_#{issuable.to_ability_name}", issuable),
issuableRef: issuable.to_reference,
markdownPreviewPath: preview_markdown_path(@project),
markdownPreviewPath: preview_markdown_path(parent),
markdownDocsPath: help_page_path('user/markdown'),
issuableTemplates: issuable_templates(issuable),
projectPath: ref_project.path,
projectNamespace: ref_project.namespace.full_path,
initialTitleHtml: markdown_field(issuable, :title),
initialTitleText: issuable.title,
initialDescriptionHtml: markdown_field(issuable, :description),
@ -227,6 +225,12 @@ module IssuablesHelper
initialTaskStatus: issuable.task_status
}
if parent.is_a?(Group)
data[:groupPath] = parent.path
else
data.merge!(projectPath: ref_project.path, projectNamespace: ref_project.namespace.full_path)
end
data.merge!(updated_at_by(issuable))
data.to_json
@ -263,12 +267,7 @@ module IssuablesHelper
end
def issuable_path(issuable, *options)
case issuable
when Issue
issue_path(issuable, *options)
when MergeRequest
merge_request_path(issuable, *options)
end
polymorphic_path(issuable, *options)
end
def issuable_url(issuable, *options)
@ -369,4 +368,8 @@ module IssuablesHelper
fullPath: @project.full_path
}
end
def parent
@project || @group
end
end

View file

@ -110,7 +110,15 @@ module ProjectsHelper
def remove_fork_project_message(project)
_("You are going to remove the fork relationship to source project %{forked_from_project}. Are you ABSOLUTELY sure?") %
{ forked_from_project: @project.forked_from_project.name_with_namespace }
{ forked_from_project: fork_source_name(project) }
end
def fork_source_name(project)
if @project.fork_source
@project.fork_source.full_name
else
@project.fork_network&.deleted_root_project_name
end
end
def project_nav_tabs
@ -140,8 +148,8 @@ module ProjectsHelper
def can_change_visibility_level?(project, current_user)
return false unless can?(current_user, :change_visibility_level, project)
if project.forked?
project.forked_from_project.visibility_level > Gitlab::VisibilityLevel::PRIVATE
if project.fork_source
project.fork_source.visibility_level > Gitlab::VisibilityLevel::PRIVATE
else
true
end

View file

@ -49,7 +49,8 @@ module CacheMarkdownField
# Always include a project key, or Banzai complains
project = self.project if self.respond_to?(:project)
context = cached_markdown_fields[field].merge(project: project)
group = self.group if self.respond_to?(:group)
context = cached_markdown_fields[field].merge(project: project, group: group)
# Banzai is less strict about authors, so don't always have an author key
context[:author] = self.author if self.respond_to?(:author)

View file

@ -14,7 +14,6 @@ module Issuable
include StripAttribute
include Awardable
include Taskable
include TimeTrackable
include Importable
include Editable
include AfterCommitQueue
@ -95,8 +94,6 @@ module Issuable
strip_attributes :title
acts_as_paranoid
after_save :record_metrics, unless: :imported?
# We want to use optimistic lock for cases when only title or description are involved

View file

@ -30,7 +30,6 @@ class Environment < ActiveRecord::Base
message: Gitlab::Regex.environment_slug_regex_message }
validates :external_url,
uniqueness: { scope: :project_id },
length: { maximum: 255 },
allow_nil: true,
addressable_url: true
@ -110,7 +109,7 @@ class Environment < ActiveRecord::Base
end
def ref_path
"refs/#{Repository::REF_ENVIRONMENTS}/#{generate_slug}"
"refs/#{Repository::REF_ENVIRONMENTS}/#{slug}"
end
def formatted_external_url
@ -164,6 +163,10 @@ class Environment < ActiveRecord::Base
end
end
def slug
super.presence || generate_slug
end
# An environment name is not necessarily suitable for use in URLs, DNS
# or other third-party contexts, so provide a slugified version. A slug has
# the following properties:

7
app/models/epic.rb Normal file
View file

@ -0,0 +1,7 @@
# Placeholder class for model that is implemented in EE
# It will reserve (ee#3853) '&' as a reference prefix, but the table does not exists in CE
class Epic < ActiveRecord::Base
# TODO: this will be implemented as part of #3853
def to_reference
end
end

View file

@ -12,4 +12,8 @@ class ForkNetwork < ActiveRecord::Base
def find_forks_in(other_projects)
projects.where(id: other_projects)
end
def merge_requests
MergeRequest.where(target_project: projects)
end
end

View file

@ -42,6 +42,7 @@ class Group < Namespace
after_create :post_create_hook
after_destroy :post_destroy_hook
after_save :update_two_factor_requirement
after_update :path_changed_hook, if: :path_changed?
class << self
def supports_nested_groups?
@ -180,6 +181,12 @@ class Group < Namespace
add_user(user, :owner, current_user: current_user)
end
def member?(user, min_access_level = Gitlab::Access::GUEST)
return false unless user
max_member_access_for_user(user) >= min_access_level
end
def has_owner?(user)
return false unless user
@ -289,6 +296,12 @@ class Group < Namespace
list_of_ids.reverse.map { |group| variables[group.id] }.compact.flatten
end
def full_path_was
return path_was unless has_parent?
"#{parent.full_path}/#{path_was}"
end
private
def update_two_factor_requirement
@ -297,6 +310,10 @@ class Group < Namespace
users.find_each(&:update_two_factor_requirement)
end
def path_changed_hook
system_hook_service.execute_hooks_for(self, :rename)
end
def visibility_level_allowed_by_parent
return if visibility_level_allowed_by_parent?

View file

@ -10,6 +10,7 @@ class Issue < ActiveRecord::Base
include FasterCacheKeys
include RelativePositioning
include CreatedAtFilterable
include TimeTrackable
DueDateStruct = Struct.new(:title, :name).freeze
NoDueDate = DueDateStruct.new('No Due Date', '0').freeze
@ -74,6 +75,8 @@ class Issue < ActiveRecord::Base
end
end
acts_as_paranoid
def self.reference_prefix
'#'
end

View file

@ -6,6 +6,7 @@ class MergeRequest < ActiveRecord::Base
include Sortable
include IgnorableColumn
include CreatedAtFilterable
include TimeTrackable
ignore_column :locked_at
@ -119,6 +120,8 @@ class MergeRequest < ActiveRecord::Base
after_save :keep_around_commit
acts_as_paranoid
def self.reference_prefix
'!'
end

View file

@ -48,6 +48,10 @@ class MergeRequestDiff < ActiveRecord::Base
# Collect information about commits and diff from repository
# and save it to the database as serialized data
def save_git_content
MergeRequest
.where('id = ? AND COALESCE(latest_merge_request_diff_id, 0) < ?', self.merge_request_id, self.id)
.update_all(latest_merge_request_diff_id: self.id)
ensure_commit_shas
save_commits
save_diffs

View file

@ -69,7 +69,7 @@ class Note < ActiveRecord::Base
delegate :title, to: :noteable, allow_nil: true
validates :note, presence: true
validates :project, presence: true, unless: :for_personal_snippet?
validates :project, presence: true, if: :for_project_noteable?
# Attachments are deprecated and are handled by Markdown uploader
validates :attachment, file_size: { maximum: :max_attachment_size }
@ -114,7 +114,7 @@ class Note < ActiveRecord::Base
after_initialize :ensure_discussion_id
before_validation :nullify_blank_type, :nullify_blank_line_code
before_validation :set_discussion_id, on: :create
after_save :keep_around_commit, unless: :for_personal_snippet?
after_save :keep_around_commit, if: :for_project_noteable?
after_save :expire_etag_cache
after_destroy :expire_etag_cache
@ -208,6 +208,10 @@ class Note < ActiveRecord::Base
noteable.is_a?(PersonalSnippet)
end
def for_project_noteable?
!for_personal_snippet?
end
def skip_project_check?
for_personal_snippet?
end

View file

@ -2,5 +2,13 @@ class OauthAccessToken < Doorkeeper::AccessToken
belongs_to :resource_owner, class_name: 'User'
belongs_to :application, class_name: 'Doorkeeper::Application'
alias_method :user, :resource_owner
alias_attribute :user, :resource_owner
def scopes=(value)
if value.is_a?(Array)
super(Doorkeeper::OAuth::Scopes.from_array(value).to_s)
else
super
end
end
end

Some files were not shown because too many files have changed in this diff Show more