Merge branch 'master' into new-nav-fix-contextual-breadcrumbs
This commit is contained in:
commit
e5183d907e
|
@ -60,3 +60,4 @@ eslint-report.html
|
|||
/.gitlab_workhorse_secret
|
||||
/webpack-report/
|
||||
/locale/**/LC_MESSAGES
|
||||
/.rspec
|
||||
|
|
|
@ -474,8 +474,6 @@ codeclimate:
|
|||
services:
|
||||
- docker:dind
|
||||
script:
|
||||
- docker pull stedolan/jq
|
||||
- docker pull codeclimate/codeclimate
|
||||
- docker run --env CODECLIMATE_CODE="$PWD" --volume "$PWD":/code --volume /var/run/docker.sock:/var/run/docker.sock --volume /tmp/cc:/tmp/cc codeclimate/codeclimate analyze -f json > raw_codeclimate.json
|
||||
- cat raw_codeclimate.json | docker run -i stedolan/jq -c 'map({check_name,fingerprint,location})' > codeclimate.json
|
||||
artifacts:
|
||||
|
|
10
.rubocop.yml
10
.rubocop.yml
|
@ -965,6 +965,10 @@ RSpec/AnyInstance:
|
|||
RSpec/BeEql:
|
||||
Enabled: true
|
||||
|
||||
# We don't enforce this as we use this technique in a few places.
|
||||
RSpec/BeforeAfterAll:
|
||||
Enabled: false
|
||||
|
||||
# Check that the first argument to the top level describe is the tested class or
|
||||
# module.
|
||||
RSpec/DescribeClass:
|
||||
|
@ -1024,6 +1028,12 @@ RSpec/FilePath:
|
|||
RSpec/Focus:
|
||||
Enabled: true
|
||||
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: is_expected, should
|
||||
RSpec/ImplicitExpect:
|
||||
Enabled: true
|
||||
EnforcedStyle: is_expected
|
||||
|
||||
# Checks for the usage of instance variables.
|
||||
RSpec/InstanceVariable:
|
||||
Enabled: false
|
||||
|
|
|
@ -6,10 +6,6 @@
|
|||
# Note that changes in the inspected code, or installation of new
|
||||
# versions of RuboCop, may require this file to be generated again.
|
||||
|
||||
# Offense count: 54
|
||||
RSpec/BeforeAfterAll:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 233
|
||||
RSpec/EmptyLineAfterFinalLet:
|
||||
Enabled: false
|
||||
|
@ -24,12 +20,6 @@ RSpec/EmptyLineAfterSubject:
|
|||
RSpec/HookArgument:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 12
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: is_expected, should
|
||||
RSpec/ImplicitExpect:
|
||||
Enabled: false
|
||||
|
||||
# Offense count: 11
|
||||
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
||||
# SupportedStyles: it_behaves_like, it_should_behave_like
|
||||
|
|
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -2,6 +2,18 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 9.3.5 (2017-07-05)
|
||||
|
||||
- Remove "Remove from board" button from backlog and closed list. !12430
|
||||
- Do not delete protected branches when deleting all merged branches. !12624
|
||||
- Set default for Remove source branch to false.
|
||||
- Prevent accidental deletion of protected MR source branch by repeating checks before actual deletion.
|
||||
- Expires full_path cache after a repository is renamed/transferred.
|
||||
|
||||
## 9.3.4 (2017-07-03)
|
||||
|
||||
- No changes.
|
||||
|
||||
## 9.3.3 (2017-06-30)
|
||||
|
||||
- Fix head pipeline stored in merge request for external pipelines. !12478
|
||||
|
|
|
@ -1 +1 @@
|
|||
5.0.6
|
||||
5.1.1
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -255,7 +255,7 @@ gem 'net-ssh', '~> 3.0.1'
|
|||
gem 'base32', '~> 0.3.0'
|
||||
|
||||
# Sentry integration
|
||||
gem 'sentry-raven', '~> 2.4.0'
|
||||
gem 'sentry-raven', '~> 2.5.3'
|
||||
|
||||
gem 'premailer-rails', '~> 1.9.7'
|
||||
|
||||
|
@ -285,6 +285,7 @@ group :metrics do
|
|||
|
||||
# Prometheus
|
||||
gem 'prometheus-client-mmap', '~>0.7.0.beta5'
|
||||
gem 'raindrops', '~> 0.18'
|
||||
end
|
||||
|
||||
group :development do
|
||||
|
|
11
Gemfile.lock
11
Gemfile.lock
|
@ -599,8 +599,8 @@ GEM
|
|||
premailer-rails (1.9.7)
|
||||
actionmailer (>= 3, < 6)
|
||||
premailer (~> 1.7, >= 1.7.9)
|
||||
prometheus-client-mmap (0.7.0.beta5)
|
||||
mmap2 (~> 2.2.6)
|
||||
prometheus-client-mmap (0.7.0.beta8)
|
||||
mmap2 (~> 2.2, >= 2.2.7)
|
||||
pry (0.10.4)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
|
@ -658,7 +658,7 @@ GEM
|
|||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.2.2)
|
||||
rake
|
||||
raindrops (0.17.0)
|
||||
raindrops (0.18.0)
|
||||
rake (10.5.0)
|
||||
rblineprof (0.3.6)
|
||||
debugger-ruby_core_source (~> 1.3)
|
||||
|
@ -775,7 +775,7 @@ GEM
|
|||
activesupport (>= 3.1)
|
||||
select2-rails (3.5.9.3)
|
||||
thor (~> 0.14)
|
||||
sentry-raven (2.4.0)
|
||||
sentry-raven (2.5.3)
|
||||
faraday (>= 0.7.6, < 1.0)
|
||||
settingslogic (2.0.9)
|
||||
sexp_processor (4.9.0)
|
||||
|
@ -1062,6 +1062,7 @@ DEPENDENCIES
|
|||
rails-deprecated_sanitizer (~> 1.0.3)
|
||||
rails-i18n (~> 4.0.9)
|
||||
rainbow (~> 2.2)
|
||||
raindrops (~> 0.18)
|
||||
rblineprof (~> 0.3.6)
|
||||
rdoc (~> 4.2)
|
||||
recaptcha (~> 3.0)
|
||||
|
@ -1089,7 +1090,7 @@ DEPENDENCIES
|
|||
scss_lint (~> 0.47.0)
|
||||
seed-fu (~> 2.3.5)
|
||||
select2-rails (~> 3.5.9)
|
||||
sentry-raven (~> 2.4.0)
|
||||
sentry-raven (~> 2.5.3)
|
||||
settingslogic (~> 2.0.9)
|
||||
sham_rack (~> 1.3.6)
|
||||
shoulda-matchers (~> 2.8.0)
|
||||
|
|
|
@ -1,23 +1,8 @@
|
|||
import autosize from 'vendor/autosize';
|
||||
|
||||
$(() => {
|
||||
const $fields = $('.js-autosize');
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const autosizeEls = document.querySelectorAll('.js-autosize');
|
||||
|
||||
$fields.on('autosize:resized', function resized() {
|
||||
const $field = $(this);
|
||||
$field.data('height', $field.outerHeight());
|
||||
});
|
||||
|
||||
$fields.on('resize.autosize', function resize() {
|
||||
const $field = $(this);
|
||||
if ($field.data('height') !== $field.outerHeight()) {
|
||||
$field.data('height', $field.outerHeight());
|
||||
autosize.destroy($field);
|
||||
$field.css('max-height', window.outerHeight);
|
||||
}
|
||||
});
|
||||
|
||||
autosize($fields);
|
||||
autosize.update($fields);
|
||||
$fields.css('resize', 'vertical');
|
||||
autosize(autosizeEls);
|
||||
autosize.update(autosizeEls);
|
||||
});
|
||||
|
|
|
@ -13,25 +13,21 @@ window.Build = (function () {
|
|||
this.options = options || $('.js-build-options').data();
|
||||
|
||||
this.pageUrl = this.options.pageUrl;
|
||||
this.buildUrl = this.options.buildUrl;
|
||||
this.buildStatus = this.options.buildStatus;
|
||||
this.state = this.options.logState;
|
||||
this.buildStage = this.options.buildStage;
|
||||
this.$document = $(document);
|
||||
this.logBytes = 0;
|
||||
this.scrollOffsetPadding = 30;
|
||||
this.hasBeenScrolled = false;
|
||||
|
||||
this.updateDropdown = this.updateDropdown.bind(this);
|
||||
this.getBuildTrace = this.getBuildTrace.bind(this);
|
||||
this.scrollToBottom = this.scrollToBottom.bind(this);
|
||||
|
||||
this.$body = $('body');
|
||||
this.$buildTrace = $('#build-trace');
|
||||
this.$buildRefreshAnimation = $('.js-build-refresh');
|
||||
this.$truncatedInfo = $('.js-truncated-info');
|
||||
this.$buildTraceOutput = $('.js-build-output');
|
||||
this.$scrollContainer = $('.js-scroll-container');
|
||||
this.$topBar = $('.js-top-bar');
|
||||
|
||||
// Scroll controllers
|
||||
this.$scrollTopBtn = $('.js-scroll-up');
|
||||
|
@ -63,13 +59,22 @@ window.Build = (function () {
|
|||
.off('click')
|
||||
.on('click', this.scrollToBottom.bind(this));
|
||||
|
||||
const scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
|
||||
this.scrollThrottled = _.throttle(this.toggleScroll.bind(this), 100);
|
||||
|
||||
this.$scrollContainer
|
||||
$(window)
|
||||
.off('scroll')
|
||||
.on('scroll', () => {
|
||||
this.hasBeenScrolled = true;
|
||||
scrollThrottled();
|
||||
const contentHeight = this.$buildTraceOutput.prop('scrollHeight');
|
||||
if (contentHeight > this.windowSize) {
|
||||
// means the user did not scroll, the content was updated.
|
||||
this.windowSize = contentHeight;
|
||||
} else {
|
||||
// User scrolled
|
||||
this.hasBeenScrolled = true;
|
||||
this.toggleScrollAnimation(false);
|
||||
}
|
||||
|
||||
this.scrollThrottled();
|
||||
});
|
||||
|
||||
$(window)
|
||||
|
@ -77,59 +82,73 @@ window.Build = (function () {
|
|||
.on('resize.build', _.throttle(this.sidebarOnResize.bind(this), 100));
|
||||
|
||||
this.updateArtifactRemoveDate();
|
||||
this.initAffixTopArea();
|
||||
|
||||
// eslint-disable-next-line
|
||||
this.getBuildTrace()
|
||||
.then(() => this.toggleScroll())
|
||||
.then(() => {
|
||||
if (!this.hasBeenScrolled) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
})
|
||||
.then(() => this.verifyTopPosition());
|
||||
this.getBuildTrace();
|
||||
}
|
||||
|
||||
Build.prototype.canScroll = function () {
|
||||
return (this.$scrollContainer.prop('scrollHeight') - this.scrollOffsetPadding) > this.$scrollContainer.height();
|
||||
Build.prototype.initAffixTopArea = function () {
|
||||
/**
|
||||
If the browser does not support position sticky, it returns the position as static.
|
||||
If the browser does support sticky, then we allow the browser to handle it, if not
|
||||
then we default back to Bootstraps affix
|
||||
**/
|
||||
if (this.$topBar.css('position') !== 'static') return;
|
||||
|
||||
const offsetTop = this.$buildTrace.offset().top;
|
||||
|
||||
this.$topBar.affix({
|
||||
offset: {
|
||||
top: offsetTop,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
Build.prototype.canScroll = function () {
|
||||
return document.body.scrollHeight > window.innerHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* | | Up | Down |
|
||||
* |--------------------------|----------|----------|
|
||||
* | on scroll bottom | active | disabled |
|
||||
* | on scroll top | disabled | active |
|
||||
* | no scroll | disabled | disabled |
|
||||
* | on.('scroll') is on top | disabled | active |
|
||||
* | on('scroll) is on bottom | active | disabled |
|
||||
*
|
||||
*/
|
||||
Build.prototype.toggleScroll = function () {
|
||||
const currentPosition = this.$scrollContainer.scrollTop();
|
||||
const bottomScroll = currentPosition + this.$scrollContainer.innerHeight();
|
||||
const currentPosition = document.body.scrollTop;
|
||||
const windowHeight = window.innerHeight;
|
||||
|
||||
if (this.canScroll()) {
|
||||
if (currentPosition === 0) {
|
||||
if (currentPosition > 0 &&
|
||||
(document.body.scrollHeight - currentPosition !== windowHeight)) {
|
||||
// User is in the middle of the log
|
||||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
||||
} else if (currentPosition === 0) {
|
||||
// User is at Top of Build Log
|
||||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, true);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
||||
} else if (bottomScroll === this.$scrollContainer.prop('scrollHeight')) {
|
||||
} else if (document.body.scrollHeight - currentPosition === windowHeight) {
|
||||
// User is at the bottom of the build log.
|
||||
|
||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, true);
|
||||
} else {
|
||||
this.toggleDisableButton(this.$scrollTopBtn, false);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, false);
|
||||
}
|
||||
} else {
|
||||
this.toggleDisableButton(this.$scrollTopBtn, true);
|
||||
this.toggleDisableButton(this.$scrollBottomBtn, true);
|
||||
}
|
||||
};
|
||||
|
||||
Build.prototype.scrollToTop = function () {
|
||||
this.hasBeenScrolled = true;
|
||||
this.$scrollContainer.scrollTop(0);
|
||||
this.toggleScroll();
|
||||
Build.prototype.scrollDown = function () {
|
||||
document.body.scrollTop = document.body.scrollHeight;
|
||||
};
|
||||
|
||||
Build.prototype.scrollToBottom = function () {
|
||||
this.scrollDown();
|
||||
this.hasBeenScrolled = true;
|
||||
this.toggleScroll();
|
||||
};
|
||||
|
||||
Build.prototype.scrollToTop = function () {
|
||||
document.body.scrollTop = 0;
|
||||
this.hasBeenScrolled = true;
|
||||
this.$scrollContainer.scrollTop(this.$scrollContainer.prop('scrollHeight'));
|
||||
this.toggleScroll();
|
||||
};
|
||||
|
||||
|
@ -142,47 +161,6 @@ window.Build = (function () {
|
|||
this.$scrollBottomBtn.toggleClass('animate', toggle);
|
||||
};
|
||||
|
||||
/**
|
||||
* Build trace top position depends on the space ocupied by the elments rendered before
|
||||
*/
|
||||
Build.prototype.verifyTopPosition = function () {
|
||||
const $buildPage = $('.build-page');
|
||||
|
||||
const $flashError = $('.alert-wrapper');
|
||||
const $header = $('.build-header', $buildPage);
|
||||
const $runnersStuck = $('.js-build-stuck', $buildPage);
|
||||
const $startsEnvironment = $('.js-environment-container', $buildPage);
|
||||
const $erased = $('.js-build-erased', $buildPage);
|
||||
const prependTopDefault = 20;
|
||||
|
||||
// header + navigation + margin
|
||||
let topPostion = 168;
|
||||
|
||||
if ($header.length) {
|
||||
topPostion += $header.outerHeight();
|
||||
}
|
||||
|
||||
if ($runnersStuck.length) {
|
||||
topPostion += $runnersStuck.outerHeight();
|
||||
}
|
||||
|
||||
if ($startsEnvironment.length) {
|
||||
topPostion += $startsEnvironment.outerHeight() + prependTopDefault;
|
||||
}
|
||||
|
||||
if ($erased.length) {
|
||||
topPostion += $erased.outerHeight() + prependTopDefault;
|
||||
}
|
||||
|
||||
if ($flashError.length) {
|
||||
topPostion += $flashError.outerHeight() + prependTopDefault;
|
||||
}
|
||||
|
||||
this.$buildTrace.css({
|
||||
top: topPostion,
|
||||
});
|
||||
};
|
||||
|
||||
Build.prototype.initSidebar = function () {
|
||||
this.$sidebar = $('.js-build-sidebar');
|
||||
this.$sidebar.niceScroll();
|
||||
|
@ -200,6 +178,8 @@ window.Build = (function () {
|
|||
this.state = log.state;
|
||||
}
|
||||
|
||||
this.windowSize = this.$buildTraceOutput.prop('scrollHeight');
|
||||
|
||||
if (log.append) {
|
||||
this.$buildTraceOutput.append(log.html);
|
||||
this.logBytes += log.size;
|
||||
|
@ -227,14 +207,7 @@ window.Build = (function () {
|
|||
}
|
||||
|
||||
Build.timeout = setTimeout(() => {
|
||||
//eslint-disable-next-line
|
||||
this.getBuildTrace()
|
||||
.then(() => {
|
||||
if (!this.hasBeenScrolled) {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
})
|
||||
.then(() => this.verifyTopPosition());
|
||||
this.getBuildTrace();
|
||||
}, 4000);
|
||||
} else {
|
||||
this.$buildRefreshAnimation.remove();
|
||||
|
@ -247,7 +220,13 @@ window.Build = (function () {
|
|||
})
|
||||
.fail(() => {
|
||||
this.$buildRefreshAnimation.remove();
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
if (!this.hasBeenScrolled) {
|
||||
this.scrollDown();
|
||||
}
|
||||
})
|
||||
.then(() => this.toggleScroll());
|
||||
};
|
||||
|
||||
Build.prototype.shouldHideSidebarForViewport = function () {
|
||||
|
@ -259,14 +238,11 @@ window.Build = (function () {
|
|||
const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
|
||||
const $toggleButton = $('.js-sidebar-build-toggle-header');
|
||||
|
||||
this.$buildTrace
|
||||
.toggleClass('sidebar-expanded', shouldShow)
|
||||
.toggleClass('sidebar-collapsed', shouldHide);
|
||||
this.$sidebar
|
||||
.toggleClass('right-sidebar-expanded', shouldShow)
|
||||
.toggleClass('right-sidebar-collapsed', shouldHide);
|
||||
|
||||
$('.js-build-page')
|
||||
this.$topBar
|
||||
.toggleClass('sidebar-expanded', shouldShow)
|
||||
.toggleClass('sidebar-collapsed', shouldHide);
|
||||
|
||||
|
@ -279,17 +255,10 @@ window.Build = (function () {
|
|||
|
||||
Build.prototype.sidebarOnResize = function () {
|
||||
this.toggleSidebar(this.shouldHideSidebarForViewport());
|
||||
|
||||
this.verifyTopPosition();
|
||||
|
||||
if (this.canScroll()) {
|
||||
this.toggleScroll();
|
||||
}
|
||||
};
|
||||
|
||||
Build.prototype.sidebarOnClick = function () {
|
||||
if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
|
||||
this.verifyTopPosition();
|
||||
};
|
||||
|
||||
Build.prototype.updateArtifactRemoveDate = function () {
|
||||
|
|
|
@ -57,6 +57,7 @@ import GfmAutoComplete from './gfm_auto_complete';
|
|||
import ShortcutsBlob from './shortcuts_blob';
|
||||
import initSettingsPanels from './settings_panels';
|
||||
import initExperimentalFlags from './experimental_flags';
|
||||
import OAuthRememberMe from './oauth_remember_me';
|
||||
|
||||
(function() {
|
||||
var Dispatcher;
|
||||
|
@ -128,6 +129,7 @@ import initExperimentalFlags from './experimental_flags';
|
|||
case 'sessions:new':
|
||||
new UsernameValidator();
|
||||
new ActiveTabMemoizer();
|
||||
new OAuthRememberMe({ container: $(".omniauth-container") }).bindEvents();
|
||||
break;
|
||||
case 'projects:boards:show':
|
||||
case 'projects:boards:index':
|
||||
|
|
|
@ -32,7 +32,6 @@ export default {
|
|||
state: store.state,
|
||||
visibility: 'available',
|
||||
isLoading: false,
|
||||
isLoadingFolderContent: false,
|
||||
cssContainerClass: environmentsData.cssClass,
|
||||
endpoint: environmentsData.environmentsDataEndpoint,
|
||||
canCreateDeployment: environmentsData.canCreateDeployment,
|
||||
|
@ -86,9 +85,6 @@ export default {
|
|||
errorCallback: this.errorCallback,
|
||||
notificationCallback: (isMakingRequest) => {
|
||||
this.isMakingRequest = isMakingRequest;
|
||||
|
||||
// We need to verify if any folder is open to also fecth it
|
||||
this.openFolders = this.store.getOpenFolders();
|
||||
},
|
||||
});
|
||||
|
||||
|
@ -119,7 +115,7 @@ export default {
|
|||
this.store.toggleFolder(folder);
|
||||
|
||||
if (!folder.isOpen) {
|
||||
this.fetchChildEnvironments(folder, folderUrl);
|
||||
this.fetchChildEnvironments(folder, folderUrl, true);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -147,19 +143,17 @@ export default {
|
|||
.catch(this.errorCallback);
|
||||
},
|
||||
|
||||
fetchChildEnvironments(folder, folderUrl) {
|
||||
this.isLoadingFolderContent = true;
|
||||
fetchChildEnvironments(folder, folderUrl, showLoader = false) {
|
||||
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader);
|
||||
|
||||
this.service.getFolderContent(folderUrl)
|
||||
.then(resp => resp.json())
|
||||
.then((response) => {
|
||||
this.store.setfolderContent(folder, response.environments);
|
||||
this.isLoadingFolderContent = false;
|
||||
})
|
||||
.then(response => this.store.setfolderContent(folder, response.environments))
|
||||
.then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false))
|
||||
.catch(() => {
|
||||
this.isLoadingFolderContent = false;
|
||||
// eslint-disable-next-line no-new
|
||||
new Flash('An error occurred while fetching the environments.');
|
||||
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -176,13 +170,13 @@ export default {
|
|||
successCallback(resp) {
|
||||
this.saveData(resp);
|
||||
|
||||
// If folders are open while polling we need to open them again
|
||||
if (this.openFolders.length) {
|
||||
this.openFolders.map((folder) => {
|
||||
// We need to verify if any folder is open to also update it
|
||||
const openFolders = this.store.getOpenFolders();
|
||||
if (openFolders.length) {
|
||||
openFolders.forEach((folder) => {
|
||||
// TODO - Move this to the backend
|
||||
const folderUrl = `${window.location.pathname}/folders/${folder.folderName}`;
|
||||
|
||||
this.store.updateFolder(folder, 'isOpen', true);
|
||||
return this.fetchChildEnvironments(folder, folderUrl);
|
||||
});
|
||||
}
|
||||
|
@ -267,7 +261,7 @@ export default {
|
|||
:environments="state.environments"
|
||||
:can-create-deployment="canCreateDeploymentParsed"
|
||||
:can-read-environment="canReadEnvironmentParsed"
|
||||
:is-loading-folder-content="isLoadingFolderContent" />
|
||||
/>
|
||||
</div>
|
||||
|
||||
<table-pagination
|
||||
|
|
|
@ -29,12 +29,6 @@ export default {
|
|||
required: false,
|
||||
default: false,
|
||||
},
|
||||
|
||||
isLoadingFolderContent: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
|
@ -74,7 +68,7 @@ export default {
|
|||
/>
|
||||
|
||||
<template v-if="model.isFolder && model.isOpen && model.children && model.children.length > 0">
|
||||
<div v-if="isLoadingFolderContent">
|
||||
<div v-if="model.isLoadingFolderContent">
|
||||
<loading-icon size="2" />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -35,14 +35,18 @@ export default class EnvironmentsStore {
|
|||
*/
|
||||
storeEnvironments(environments = []) {
|
||||
const filteredEnvironments = environments.map((env) => {
|
||||
const oldEnvironmentState = this.state.environments
|
||||
.find(element => element.id === env.latest.id) || {};
|
||||
|
||||
let filtered = {};
|
||||
|
||||
if (env.size > 1) {
|
||||
filtered = Object.assign({}, env, {
|
||||
isFolder: true,
|
||||
isLoadingFolderContent: oldEnvironmentState.isLoading || false,
|
||||
folderName: env.name,
|
||||
isOpen: false,
|
||||
children: [],
|
||||
isOpen: oldEnvironmentState.isOpen || false,
|
||||
children: oldEnvironmentState.children || [],
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -98,7 +102,7 @@ export default class EnvironmentsStore {
|
|||
* @return {Array}
|
||||
*/
|
||||
toggleFolder(folder) {
|
||||
return this.updateFolder(folder, 'isOpen', !folder.isOpen);
|
||||
return this.updateEnvironmentProp(folder, 'isOpen', !folder.isOpen);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,23 +129,23 @@ export default class EnvironmentsStore {
|
|||
return updated;
|
||||
});
|
||||
|
||||
return this.updateFolder(folder, 'children', updatedEnvironments);
|
||||
return this.updateEnvironmentProp(folder, 'children', updatedEnvironments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a folder a prop and a new value updates the correct folder.
|
||||
* Given a environment, a prop and a new value updates the correct environment.
|
||||
*
|
||||
* @param {Object} folder
|
||||
* @param {Object} environment
|
||||
* @param {String} prop
|
||||
* @param {String|Boolean|Object|Array} newValue
|
||||
* @return {Array}
|
||||
*/
|
||||
updateFolder(folder, prop, newValue) {
|
||||
updateEnvironmentProp(environment, prop, newValue) {
|
||||
const environments = this.state.environments;
|
||||
|
||||
const updatedEnvironments = environments.map((env) => {
|
||||
const updateEnv = Object.assign({}, env);
|
||||
if (env.isFolder && env.id === folder.id) {
|
||||
if (env.id === environment.id) {
|
||||
updateEnv[prop] = newValue;
|
||||
}
|
||||
|
||||
|
@ -149,8 +153,6 @@ export default class EnvironmentsStore {
|
|||
});
|
||||
|
||||
this.state.environments = updatedEnvironments;
|
||||
|
||||
return updatedEnvironments;
|
||||
}
|
||||
|
||||
getOpenFolders() {
|
||||
|
|
|
@ -26,14 +26,6 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||
mounted() {
|
||||
this.mediator.initBuildClass();
|
||||
},
|
||||
updated() {
|
||||
// Wait for flash message to be appended
|
||||
Vue.nextTick(() => {
|
||||
if (this.mediator.build) {
|
||||
this.mediator.build.verifyTopPosition();
|
||||
}
|
||||
});
|
||||
},
|
||||
render(createElement) {
|
||||
return createElement('job-header', {
|
||||
props: {
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
|
||||
data() {
|
||||
return {
|
||||
graphHeight: 500,
|
||||
graphHeight: 450,
|
||||
graphWidth: 600,
|
||||
graphHeightOffset: 120,
|
||||
xScale: {},
|
||||
|
@ -88,7 +88,9 @@
|
|||
},
|
||||
|
||||
paddingBottomRootSvg() {
|
||||
return (Math.ceil(this.graphHeight * 100) / this.graphWidth) || 0;
|
||||
return {
|
||||
paddingBottom: `${(Math.ceil(this.graphHeight * 100) / this.graphWidth) || 0}%`,
|
||||
};
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -104,7 +106,7 @@
|
|||
}
|
||||
this.data = query.result[0].values;
|
||||
this.unitOfDisplay = query.unit || 'N/A';
|
||||
this.yAxisLabel = this.columnData.y_axis || 'Values';
|
||||
this.yAxisLabel = this.columnData.y_label || 'Values';
|
||||
this.legendTitle = query.legend || 'Average';
|
||||
this.graphWidth = this.$refs.baseSvg.clientWidth -
|
||||
this.margin.left - this.margin.right;
|
||||
|
@ -157,12 +159,12 @@
|
|||
|
||||
const xAxis = d3.svg.axis()
|
||||
.scale(axisXScale)
|
||||
.ticks(measurements.ticks)
|
||||
.ticks(measurements.xTicks)
|
||||
.orient('bottom');
|
||||
|
||||
const yAxis = d3.svg.axis()
|
||||
.scale(this.yScale)
|
||||
.ticks(measurements.ticks)
|
||||
.ticks(measurements.yTicks)
|
||||
.orient('left');
|
||||
|
||||
d3.select(this.$refs.baseSvg).select('.x-axis').call(xAxis);
|
||||
|
@ -170,8 +172,12 @@
|
|||
const width = this.graphWidth;
|
||||
d3.select(this.$refs.baseSvg).select('.y-axis').call(yAxis)
|
||||
.selectAll('.tick')
|
||||
.each(function createTickLines() {
|
||||
d3.select(this).select('line').attr('x2', width);
|
||||
.each(function createTickLines(d, i) {
|
||||
if (i > 0) {
|
||||
d3.select(this).select('line')
|
||||
.attr('x2', width)
|
||||
.attr('class', 'axis-tick');
|
||||
} // Avoid adding the class to the first tick, to prevent coloring
|
||||
}); // This will select all of the ticks once they're rendered
|
||||
|
||||
this.xScale = d3.time.scale()
|
||||
|
@ -198,7 +204,7 @@
|
|||
watch: {
|
||||
updateAspectRatio() {
|
||||
if (this.updateAspectRatio) {
|
||||
this.graphHeight = 500;
|
||||
this.graphHeight = 450;
|
||||
this.graphWidth = 600;
|
||||
this.measurements = measurements.large;
|
||||
this.draw();
|
||||
|
@ -216,14 +222,14 @@
|
|||
<div
|
||||
:class="classType">
|
||||
<h5
|
||||
class="text-center">
|
||||
class="text-center graph-title">
|
||||
{{columnData.title}}
|
||||
</h5>
|
||||
<div
|
||||
class="prometheus-svg-container">
|
||||
<div
|
||||
class="prometheus-svg-container"
|
||||
:style="paddingBottomRootSvg">
|
||||
<svg
|
||||
:viewBox="outterViewBox"
|
||||
:style="{ 'padding-bottom': paddingBottomRootSvg }"
|
||||
ref="baseSvg">
|
||||
<g
|
||||
class="x-axis"
|
||||
|
|
|
@ -87,14 +87,14 @@
|
|||
</rect>
|
||||
<text
|
||||
class="text-metric text-metric-bold"
|
||||
x="8"
|
||||
x="16"
|
||||
y="35"
|
||||
transform="translate(-5, 20)">
|
||||
{{formatTime}}
|
||||
</text>
|
||||
<text
|
||||
class="text-metric-date"
|
||||
x="8"
|
||||
class="text-metric"
|
||||
x="16"
|
||||
y="15"
|
||||
transform="translate(-5, 20)">
|
||||
{{formatDate}}
|
||||
|
|
|
@ -109,13 +109,13 @@
|
|||
</text>
|
||||
<rect
|
||||
class="rect-axis-text"
|
||||
:x="xPosition + 50"
|
||||
:x="xPosition + 60"
|
||||
:y="graphHeight - 80"
|
||||
width="50"
|
||||
width="35"
|
||||
height="50">
|
||||
</rect>
|
||||
<text
|
||||
class="label-axis-text"
|
||||
class="label-axis-text x-label-text"
|
||||
:x="xPosition + 60"
|
||||
:y="yPosition"
|
||||
dy=".35em">
|
||||
|
@ -131,13 +131,13 @@
|
|||
<text
|
||||
class="text-metric-title"
|
||||
x="50"
|
||||
:y="graphHeight - 40">
|
||||
:y="graphHeight - 25">
|
||||
{{legendTitle}}
|
||||
</text>
|
||||
<text
|
||||
class="text-metric-usage"
|
||||
x="50"
|
||||
:y="graphHeight - 25">
|
||||
:y="graphHeight - 10">
|
||||
{{metricUsage}}
|
||||
</text>
|
||||
</g>
|
||||
|
|
|
@ -8,14 +8,14 @@ export default {
|
|||
},
|
||||
legends: {
|
||||
width: 15,
|
||||
height: 30,
|
||||
height: 25,
|
||||
},
|
||||
backgroundLegend: {
|
||||
width: 30,
|
||||
height: 50,
|
||||
},
|
||||
axisLabelLineOffset: -20,
|
||||
legendOffset: 52,
|
||||
legendOffset: 35,
|
||||
},
|
||||
large: { // This covers both md and lg screen sizes
|
||||
margin: {
|
||||
|
@ -26,14 +26,15 @@ export default {
|
|||
},
|
||||
legends: {
|
||||
width: 20,
|
||||
height: 35,
|
||||
height: 30,
|
||||
},
|
||||
backgroundLegend: {
|
||||
width: 30,
|
||||
height: 150,
|
||||
},
|
||||
axisLabelLineOffset: 20,
|
||||
legendOffset: 55,
|
||||
legendOffset: 38,
|
||||
},
|
||||
ticks: 3,
|
||||
xTicks: 8,
|
||||
yTicks: 3,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* OAuth-based login buttons have a separate "remember me" checkbox.
|
||||
*
|
||||
* Toggling this checkbox adds/removes a `remember_me` parameter to the
|
||||
* login buttons' href, which is passed on to the omniauth callback.
|
||||
**/
|
||||
|
||||
export default class OAuthRememberMe {
|
||||
constructor(opts = {}) {
|
||||
this.container = opts.container || '';
|
||||
this.loginLinkSelector = '.oauth-login';
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
$('#remember_me', this.container).on('click', this.toggleRememberMe);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line class-methods-use-this
|
||||
toggleRememberMe(event) {
|
||||
const rememberMe = $(event.target).is(':checked');
|
||||
|
||||
$('.oauth-login', this.container).each((i, element) => {
|
||||
const href = $(element).attr('href');
|
||||
|
||||
if (rememberMe) {
|
||||
$(element).attr('href', `${href}?remember_me=1`);
|
||||
} else {
|
||||
$(element).attr('href', href.replace('?remember_me=1', ''));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -2,56 +2,54 @@
|
|||
/* eslint no-new: "off" */
|
||||
import AccessorUtilities from './lib/utils/accessor';
|
||||
|
||||
((global) => {
|
||||
/**
|
||||
* Memorize the last selected tab after reloading a page.
|
||||
* Does that setting the current selected tab in the localStorage
|
||||
*/
|
||||
class ActiveTabMemoizer {
|
||||
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.nav-tabs' } = {}) {
|
||||
this.currentTabKey = currentTabKey;
|
||||
this.tabSelector = tabSelector;
|
||||
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
|
||||
/**
|
||||
* Memorize the last selected tab after reloading a page.
|
||||
* Does that setting the current selected tab in the localStorage
|
||||
*/
|
||||
class ActiveTabMemoizer {
|
||||
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.nav-tabs' } = {}) {
|
||||
this.currentTabKey = currentTabKey;
|
||||
this.tabSelector = tabSelector;
|
||||
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
|
||||
|
||||
this.bootstrap();
|
||||
}
|
||||
this.bootstrap();
|
||||
}
|
||||
|
||||
bootstrap() {
|
||||
const tabs = document.querySelectorAll(this.tabSelector);
|
||||
if (tabs.length > 0) {
|
||||
tabs[0].addEventListener('click', (e) => {
|
||||
if (e.target && e.target.nodeName === 'A') {
|
||||
const anchorName = e.target.getAttribute('href');
|
||||
this.saveData(anchorName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.showTab();
|
||||
}
|
||||
|
||||
showTab() {
|
||||
const anchorName = this.readData();
|
||||
if (anchorName) {
|
||||
const tab = document.querySelector(`${this.tabSelector} a[href="${anchorName}"]`);
|
||||
if (tab) {
|
||||
tab.click();
|
||||
bootstrap() {
|
||||
const tabs = document.querySelectorAll(this.tabSelector);
|
||||
if (tabs.length > 0) {
|
||||
tabs[0].addEventListener('click', (e) => {
|
||||
if (e.target && e.target.nodeName === 'A') {
|
||||
const anchorName = e.target.getAttribute('href');
|
||||
this.saveData(anchorName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.showTab();
|
||||
}
|
||||
|
||||
showTab() {
|
||||
const anchorName = this.readData();
|
||||
if (anchorName) {
|
||||
const tab = document.querySelector(`${this.tabSelector} a[href="${anchorName}"]`);
|
||||
if (tab) {
|
||||
tab.click();
|
||||
}
|
||||
}
|
||||
|
||||
saveData(val) {
|
||||
if (!this.isLocalStorageAvailable) return undefined;
|
||||
|
||||
return window.localStorage.setItem(this.currentTabKey, val);
|
||||
}
|
||||
|
||||
readData() {
|
||||
if (!this.isLocalStorageAvailable) return null;
|
||||
|
||||
return window.localStorage.getItem(this.currentTabKey);
|
||||
}
|
||||
}
|
||||
|
||||
global.ActiveTabMemoizer = ActiveTabMemoizer;
|
||||
})(window);
|
||||
saveData(val) {
|
||||
if (!this.isLocalStorageAvailable) return undefined;
|
||||
|
||||
return window.localStorage.setItem(this.currentTabKey, val);
|
||||
}
|
||||
|
||||
readData() {
|
||||
if (!this.isLocalStorageAvailable) return null;
|
||||
|
||||
return window.localStorage.getItem(this.currentTabKey);
|
||||
}
|
||||
}
|
||||
|
||||
window.ActiveTabMemoizer = ActiveTabMemoizer;
|
||||
|
|
|
@ -2,99 +2,97 @@
|
|||
|
||||
import FilesCommentButton from './files_comment_button';
|
||||
|
||||
(function() {
|
||||
window.SingleFileDiff = (function() {
|
||||
var COLLAPSED_HTML, ERROR_HTML, LOADING_HTML, WRAPPER;
|
||||
window.SingleFileDiff = (function() {
|
||||
var COLLAPSED_HTML, ERROR_HTML, LOADING_HTML, WRAPPER;
|
||||
|
||||
WRAPPER = '<div class="diff-content"></div>';
|
||||
WRAPPER = '<div class="diff-content"></div>';
|
||||
|
||||
LOADING_HTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||
LOADING_HTML = '<i class="fa fa-spinner fa-spin"></i>';
|
||||
|
||||
ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
|
||||
ERROR_HTML = '<div class="nothing-here-block"><i class="fa fa-warning"></i> Could not load diff</div>';
|
||||
|
||||
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
|
||||
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
|
||||
|
||||
function SingleFileDiff(file) {
|
||||
this.file = file;
|
||||
this.toggleDiff = this.toggleDiff.bind(this);
|
||||
this.content = $('.diff-content', this.file);
|
||||
this.$toggleIcon = $('.diff-toggle-caret', this.file);
|
||||
this.diffForPath = this.content.find('[data-diff-for-path]').data('diff-for-path');
|
||||
this.isOpen = !this.diffForPath;
|
||||
if (this.diffForPath) {
|
||||
this.collapsedContent = this.content;
|
||||
this.loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide();
|
||||
this.content = null;
|
||||
this.collapsedContent.after(this.loadingContent);
|
||||
this.$toggleIcon.addClass('fa-caret-right');
|
||||
} else {
|
||||
this.collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide();
|
||||
this.content.after(this.collapsedContent);
|
||||
this.$toggleIcon.addClass('fa-caret-down');
|
||||
}
|
||||
|
||||
$('.js-file-title, .click-to-expand', this.file).on('click', (function (e) {
|
||||
this.toggleDiff($(e.target));
|
||||
}).bind(this));
|
||||
function SingleFileDiff(file) {
|
||||
this.file = file;
|
||||
this.toggleDiff = this.toggleDiff.bind(this);
|
||||
this.content = $('.diff-content', this.file);
|
||||
this.$toggleIcon = $('.diff-toggle-caret', this.file);
|
||||
this.diffForPath = this.content.find('[data-diff-for-path]').data('diff-for-path');
|
||||
this.isOpen = !this.diffForPath;
|
||||
if (this.diffForPath) {
|
||||
this.collapsedContent = this.content;
|
||||
this.loadingContent = $(WRAPPER).addClass('loading').html(LOADING_HTML).hide();
|
||||
this.content = null;
|
||||
this.collapsedContent.after(this.loadingContent);
|
||||
this.$toggleIcon.addClass('fa-caret-right');
|
||||
} else {
|
||||
this.collapsedContent = $(WRAPPER).html(COLLAPSED_HTML).hide();
|
||||
this.content.after(this.collapsedContent);
|
||||
this.$toggleIcon.addClass('fa-caret-down');
|
||||
}
|
||||
|
||||
SingleFileDiff.prototype.toggleDiff = function($target, cb) {
|
||||
if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
|
||||
this.isOpen = !this.isOpen;
|
||||
if (!this.isOpen && !this.hasError) {
|
||||
this.content.hide();
|
||||
this.$toggleIcon.addClass('fa-caret-right').removeClass('fa-caret-down');
|
||||
this.collapsedContent.show();
|
||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||
gl.diffNotesCompileComponents();
|
||||
}
|
||||
} else if (this.content) {
|
||||
this.collapsedContent.hide();
|
||||
this.content.show();
|
||||
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||
gl.diffNotesCompileComponents();
|
||||
}
|
||||
} else {
|
||||
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
||||
return this.getContentHTML(cb);
|
||||
}
|
||||
};
|
||||
$('.js-file-title, .click-to-expand', this.file).on('click', (function (e) {
|
||||
this.toggleDiff($(e.target));
|
||||
}).bind(this));
|
||||
}
|
||||
|
||||
SingleFileDiff.prototype.getContentHTML = function(cb) {
|
||||
SingleFileDiff.prototype.toggleDiff = function($target, cb) {
|
||||
if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
|
||||
this.isOpen = !this.isOpen;
|
||||
if (!this.isOpen && !this.hasError) {
|
||||
this.content.hide();
|
||||
this.$toggleIcon.addClass('fa-caret-right').removeClass('fa-caret-down');
|
||||
this.collapsedContent.show();
|
||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||
gl.diffNotesCompileComponents();
|
||||
}
|
||||
} else if (this.content) {
|
||||
this.collapsedContent.hide();
|
||||
this.loadingContent.show();
|
||||
$.get(this.diffForPath, (function(_this) {
|
||||
return function(data) {
|
||||
_this.loadingContent.hide();
|
||||
if (data.html) {
|
||||
_this.content = $(data.html);
|
||||
_this.content.syntaxHighlight();
|
||||
} else {
|
||||
_this.hasError = true;
|
||||
_this.content = $(ERROR_HTML);
|
||||
}
|
||||
_this.collapsedContent.after(_this.content);
|
||||
|
||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||
gl.diffNotesCompileComponents();
|
||||
}
|
||||
|
||||
FilesCommentButton.init($(_this.file));
|
||||
|
||||
if (cb) cb();
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
return SingleFileDiff;
|
||||
})();
|
||||
|
||||
$.fn.singleFileDiff = function() {
|
||||
return this.each(function() {
|
||||
if (!$.data(this, 'singleFileDiff')) {
|
||||
return $.data(this, 'singleFileDiff', new window.SingleFileDiff(this));
|
||||
this.content.show();
|
||||
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||
gl.diffNotesCompileComponents();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
|
||||
return this.getContentHTML(cb);
|
||||
}
|
||||
};
|
||||
}).call(window);
|
||||
|
||||
SingleFileDiff.prototype.getContentHTML = function(cb) {
|
||||
this.collapsedContent.hide();
|
||||
this.loadingContent.show();
|
||||
$.get(this.diffForPath, (function(_this) {
|
||||
return function(data) {
|
||||
_this.loadingContent.hide();
|
||||
if (data.html) {
|
||||
_this.content = $(data.html);
|
||||
_this.content.syntaxHighlight();
|
||||
} else {
|
||||
_this.hasError = true;
|
||||
_this.content = $(ERROR_HTML);
|
||||
}
|
||||
_this.collapsedContent.after(_this.content);
|
||||
|
||||
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
|
||||
gl.diffNotesCompileComponents();
|
||||
}
|
||||
|
||||
FilesCommentButton.init($(_this.file));
|
||||
|
||||
if (cb) cb();
|
||||
};
|
||||
})(this));
|
||||
};
|
||||
|
||||
return SingleFileDiff;
|
||||
})();
|
||||
|
||||
$.fn.singleFileDiff = function() {
|
||||
return this.each(function() {
|
||||
if (!$.data(this, 'singleFileDiff')) {
|
||||
return $.data(this, 'singleFileDiff', new window.SingleFileDiff(this));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,158 +1,157 @@
|
|||
/*
|
||||
* Instances of SmartInterval extend the functionality of `setInterval`, make it configurable
|
||||
* and controllable by a public API.
|
||||
*
|
||||
* */
|
||||
/**
|
||||
* Instances of SmartInterval extend the functionality of `setInterval`, make it configurable
|
||||
* and controllable by a public API.
|
||||
*/
|
||||
|
||||
(() => {
|
||||
class SmartInterval {
|
||||
/**
|
||||
* @param { function } opts.callback Function to be called on each iteration (required)
|
||||
* @param { milliseconds } opts.startingInterval `currentInterval` is set to this initially
|
||||
* @param { milliseconds } opts.maxInterval `currentInterval` will be incremented to this
|
||||
* @param { milliseconds } opts.hiddenInterval `currentInterval` is set to this
|
||||
* when the page is hidden
|
||||
* @param { integer } opts.incrementByFactorOf `currentInterval` is incremented by this factor
|
||||
* @param { boolean } opts.lazyStart Configure if timer is initialized on
|
||||
* instantiation or lazily
|
||||
* @param { boolean } opts.immediateExecution Configure if callback should
|
||||
* be executed before the first interval.
|
||||
*/
|
||||
constructor(opts = {}) {
|
||||
this.cfg = {
|
||||
callback: opts.callback,
|
||||
startingInterval: opts.startingInterval,
|
||||
maxInterval: opts.maxInterval,
|
||||
hiddenInterval: opts.hiddenInterval,
|
||||
incrementByFactorOf: opts.incrementByFactorOf,
|
||||
lazyStart: opts.lazyStart,
|
||||
immediateExecution: opts.immediateExecution,
|
||||
};
|
||||
class SmartInterval {
|
||||
/**
|
||||
* @param { function } opts.callback Function to be called on each iteration (required)
|
||||
* @param { milliseconds } opts.startingInterval `currentInterval` is set to this initially
|
||||
* @param { milliseconds } opts.maxInterval `currentInterval` will be incremented to this
|
||||
* @param { milliseconds } opts.hiddenInterval `currentInterval` is set to this
|
||||
* when the page is hidden
|
||||
* @param { integer } opts.incrementByFactorOf `currentInterval` is incremented by this factor
|
||||
* @param { boolean } opts.lazyStart Configure if timer is initialized on
|
||||
* instantiation or lazily
|
||||
* @param { boolean } opts.immediateExecution Configure if callback should
|
||||
* be executed before the first interval.
|
||||
*/
|
||||
constructor(opts = {}) {
|
||||
this.cfg = {
|
||||
callback: opts.callback,
|
||||
startingInterval: opts.startingInterval,
|
||||
maxInterval: opts.maxInterval,
|
||||
hiddenInterval: opts.hiddenInterval,
|
||||
incrementByFactorOf: opts.incrementByFactorOf,
|
||||
lazyStart: opts.lazyStart,
|
||||
immediateExecution: opts.immediateExecution,
|
||||
};
|
||||
|
||||
this.state = {
|
||||
intervalId: null,
|
||||
currentInterval: this.cfg.startingInterval,
|
||||
pageVisibility: 'visible',
|
||||
};
|
||||
this.state = {
|
||||
intervalId: null,
|
||||
currentInterval: this.cfg.startingInterval,
|
||||
pageVisibility: 'visible',
|
||||
};
|
||||
|
||||
this.initInterval();
|
||||
this.initInterval();
|
||||
}
|
||||
|
||||
/* public */
|
||||
|
||||
start() {
|
||||
const cfg = this.cfg;
|
||||
const state = this.state;
|
||||
|
||||
if (cfg.immediateExecution) {
|
||||
cfg.immediateExecution = false;
|
||||
cfg.callback();
|
||||
}
|
||||
/* public */
|
||||
|
||||
start() {
|
||||
const cfg = this.cfg;
|
||||
const state = this.state;
|
||||
state.intervalId = window.setInterval(() => {
|
||||
cfg.callback();
|
||||
|
||||
if (cfg.immediateExecution) {
|
||||
cfg.immediateExecution = false;
|
||||
cfg.callback();
|
||||
if (this.getCurrentInterval() === cfg.maxInterval) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.intervalId = window.setInterval(() => {
|
||||
cfg.callback();
|
||||
this.incrementInterval();
|
||||
this.resume();
|
||||
}, this.getCurrentInterval());
|
||||
}
|
||||
|
||||
if (this.getCurrentInterval() === cfg.maxInterval) {
|
||||
return;
|
||||
}
|
||||
// cancel the existing timer, setting the currentInterval back to startingInterval
|
||||
cancel() {
|
||||
this.setCurrentInterval(this.cfg.startingInterval);
|
||||
this.stopTimer();
|
||||
}
|
||||
|
||||
this.incrementInterval();
|
||||
this.resume();
|
||||
}, this.getCurrentInterval());
|
||||
}
|
||||
|
||||
// cancel the existing timer, setting the currentInterval back to startingInterval
|
||||
cancel() {
|
||||
this.setCurrentInterval(this.cfg.startingInterval);
|
||||
this.stopTimer();
|
||||
}
|
||||
|
||||
onVisibilityHidden() {
|
||||
if (this.cfg.hiddenInterval) {
|
||||
this.setCurrentInterval(this.cfg.hiddenInterval);
|
||||
this.resume();
|
||||
} else {
|
||||
this.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
// start a timer, using the existing interval
|
||||
resume() {
|
||||
this.stopTimer(); // stop exsiting timer, in case timer was not previously stopped
|
||||
this.start();
|
||||
}
|
||||
|
||||
onVisibilityVisible() {
|
||||
onVisibilityHidden() {
|
||||
if (this.cfg.hiddenInterval) {
|
||||
this.setCurrentInterval(this.cfg.hiddenInterval);
|
||||
this.resume();
|
||||
} else {
|
||||
this.cancel();
|
||||
this.start();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.cancel();
|
||||
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
||||
$(document).off('visibilitychange').off('beforeunload');
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
initInterval() {
|
||||
const cfg = this.cfg;
|
||||
|
||||
if (!cfg.lazyStart) {
|
||||
this.start();
|
||||
}
|
||||
|
||||
this.initVisibilityChangeHandling();
|
||||
this.initPageUnloadHandling();
|
||||
}
|
||||
|
||||
initVisibilityChangeHandling() {
|
||||
// cancel interval when tab no longer shown (prevents cached pages from polling)
|
||||
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
|
||||
}
|
||||
|
||||
initPageUnloadHandling() {
|
||||
// TODO: Consider refactoring in light of turbolinks removal.
|
||||
// prevent interval continuing after page change, when kept in cache by Turbolinks
|
||||
$(document).on('beforeunload', () => this.cancel());
|
||||
}
|
||||
|
||||
handleVisibilityChange(e) {
|
||||
this.state.pageVisibility = e.target.visibilityState;
|
||||
const intervalAction = this.isPageVisible() ?
|
||||
this.onVisibilityVisible :
|
||||
this.onVisibilityHidden;
|
||||
|
||||
intervalAction.apply(this);
|
||||
}
|
||||
|
||||
getCurrentInterval() {
|
||||
return this.state.currentInterval;
|
||||
}
|
||||
|
||||
setCurrentInterval(newInterval) {
|
||||
this.state.currentInterval = newInterval;
|
||||
}
|
||||
|
||||
incrementInterval() {
|
||||
const cfg = this.cfg;
|
||||
const currentInterval = this.getCurrentInterval();
|
||||
if (cfg.hiddenInterval && !this.isPageVisible()) return;
|
||||
let nextInterval = currentInterval * cfg.incrementByFactorOf;
|
||||
|
||||
if (nextInterval > cfg.maxInterval) {
|
||||
nextInterval = cfg.maxInterval;
|
||||
}
|
||||
|
||||
this.setCurrentInterval(nextInterval);
|
||||
}
|
||||
|
||||
isPageVisible() { return this.state.pageVisibility === 'visible'; }
|
||||
|
||||
stopTimer() {
|
||||
const state = this.state;
|
||||
|
||||
state.intervalId = window.clearInterval(state.intervalId);
|
||||
}
|
||||
}
|
||||
gl.SmartInterval = SmartInterval;
|
||||
})(window.gl || (window.gl = {}));
|
||||
|
||||
// start a timer, using the existing interval
|
||||
resume() {
|
||||
this.stopTimer(); // stop exsiting timer, in case timer was not previously stopped
|
||||
this.start();
|
||||
}
|
||||
|
||||
onVisibilityVisible() {
|
||||
this.cancel();
|
||||
this.start();
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.cancel();
|
||||
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
||||
$(document).off('visibilitychange').off('beforeunload');
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
initInterval() {
|
||||
const cfg = this.cfg;
|
||||
|
||||
if (!cfg.lazyStart) {
|
||||
this.start();
|
||||
}
|
||||
|
||||
this.initVisibilityChangeHandling();
|
||||
this.initPageUnloadHandling();
|
||||
}
|
||||
|
||||
initVisibilityChangeHandling() {
|
||||
// cancel interval when tab no longer shown (prevents cached pages from polling)
|
||||
document.addEventListener('visibilitychange', this.handleVisibilityChange.bind(this));
|
||||
}
|
||||
|
||||
initPageUnloadHandling() {
|
||||
// TODO: Consider refactoring in light of turbolinks removal.
|
||||
// prevent interval continuing after page change, when kept in cache by Turbolinks
|
||||
$(document).on('beforeunload', () => this.cancel());
|
||||
}
|
||||
|
||||
handleVisibilityChange(e) {
|
||||
this.state.pageVisibility = e.target.visibilityState;
|
||||
const intervalAction = this.isPageVisible() ?
|
||||
this.onVisibilityVisible :
|
||||
this.onVisibilityHidden;
|
||||
|
||||
intervalAction.apply(this);
|
||||
}
|
||||
|
||||
getCurrentInterval() {
|
||||
return this.state.currentInterval;
|
||||
}
|
||||
|
||||
setCurrentInterval(newInterval) {
|
||||
this.state.currentInterval = newInterval;
|
||||
}
|
||||
|
||||
incrementInterval() {
|
||||
const cfg = this.cfg;
|
||||
const currentInterval = this.getCurrentInterval();
|
||||
if (cfg.hiddenInterval && !this.isPageVisible()) return;
|
||||
let nextInterval = currentInterval * cfg.incrementByFactorOf;
|
||||
|
||||
if (nextInterval > cfg.maxInterval) {
|
||||
nextInterval = cfg.maxInterval;
|
||||
}
|
||||
|
||||
this.setCurrentInterval(nextInterval);
|
||||
}
|
||||
|
||||
isPageVisible() { return this.state.pageVisibility === 'visible'; }
|
||||
|
||||
stopTimer() {
|
||||
const state = this.state;
|
||||
|
||||
state.intervalId = window.clearInterval(state.intervalId);
|
||||
}
|
||||
}
|
||||
|
||||
window.gl.SmartInterval = SmartInterval;
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
/* eslint-disable arrow-parens, no-param-reassign, space-before-function-paren, func-names, no-var, max-len */
|
||||
|
||||
(global => {
|
||||
global.gl = global.gl || {};
|
||||
window.gl.SnippetsList = function() {
|
||||
var $holder = $('.snippets-list-holder');
|
||||
|
||||
gl.SnippetsList = function() {
|
||||
var $holder = $('.snippets-list-holder');
|
||||
|
||||
$holder.find('.pagination').on('ajax:success', (e, data) => {
|
||||
$holder.replaceWith(data.html);
|
||||
});
|
||||
};
|
||||
})(window);
|
||||
$holder.find('.pagination').on('ajax:success', (e, data) => {
|
||||
$holder.replaceWith(data.html);
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,30 +1,28 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, max-len */
|
||||
/* global Flash */
|
||||
|
||||
(function() {
|
||||
this.Star = (function() {
|
||||
function Star() {
|
||||
$('.project-home-panel .toggle-star').on('ajax:success', function(e, data, status, xhr) {
|
||||
var $starIcon, $starSpan, $this, toggleStar;
|
||||
$this = $(this);
|
||||
$starSpan = $this.find('span');
|
||||
$starIcon = $this.find('i');
|
||||
toggleStar = function(isStarred) {
|
||||
$this.parent().find('.star-count').text(data.star_count);
|
||||
if (isStarred) {
|
||||
$starSpan.removeClass('starred').text('Star');
|
||||
$starIcon.removeClass('fa-star').addClass('fa-star-o');
|
||||
} else {
|
||||
$starSpan.addClass('starred').text('Unstar');
|
||||
$starIcon.removeClass('fa-star-o').addClass('fa-star');
|
||||
}
|
||||
};
|
||||
toggleStar($starSpan.hasClass('starred'));
|
||||
}).on('ajax:error', function(e, xhr, status, error) {
|
||||
new Flash('Star toggle failed. Try again later.', 'alert');
|
||||
});
|
||||
}
|
||||
window.Star = (function() {
|
||||
function Star() {
|
||||
$('.project-home-panel .toggle-star').on('ajax:success', function(e, data, status, xhr) {
|
||||
var $starIcon, $starSpan, $this, toggleStar;
|
||||
$this = $(this);
|
||||
$starSpan = $this.find('span');
|
||||
$starIcon = $this.find('i');
|
||||
toggleStar = function(isStarred) {
|
||||
$this.parent().find('.star-count').text(data.star_count);
|
||||
if (isStarred) {
|
||||
$starSpan.removeClass('starred').text('Star');
|
||||
$starIcon.removeClass('fa-star').addClass('fa-star-o');
|
||||
} else {
|
||||
$starSpan.addClass('starred').text('Unstar');
|
||||
$starIcon.removeClass('fa-star-o').addClass('fa-star');
|
||||
}
|
||||
};
|
||||
toggleStar($starSpan.hasClass('starred'));
|
||||
}).on('ajax:error', function(e, xhr, status, error) {
|
||||
new Flash('Star toggle failed. Try again later.', 'alert');
|
||||
});
|
||||
}
|
||||
|
||||
return Star;
|
||||
})();
|
||||
}).call(window);
|
||||
return Star;
|
||||
})();
|
||||
|
|
|
@ -1,47 +1,45 @@
|
|||
(() => {
|
||||
class Subscription {
|
||||
constructor(containerElm) {
|
||||
this.containerElm = containerElm;
|
||||
class Subscription {
|
||||
constructor(containerElm) {
|
||||
this.containerElm = containerElm;
|
||||
|
||||
const subscribeButton = containerElm.querySelector('.js-subscribe-button');
|
||||
if (subscribeButton) {
|
||||
// remove class so we don't bind twice
|
||||
subscribeButton.classList.remove('js-subscribe-button');
|
||||
subscribeButton.addEventListener('click', this.toggleSubscription.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
toggleSubscription(event) {
|
||||
const button = event.currentTarget;
|
||||
const buttonSpan = button.querySelector('span');
|
||||
if (!buttonSpan || button.classList.contains('disabled')) {
|
||||
return;
|
||||
}
|
||||
button.classList.add('disabled');
|
||||
|
||||
const isSubscribed = buttonSpan.innerHTML.trim().toLowerCase() !== 'subscribe';
|
||||
const toggleActionUrl = this.containerElm.dataset.url;
|
||||
|
||||
$.post(toggleActionUrl, () => {
|
||||
button.classList.remove('disabled');
|
||||
|
||||
// hack to allow this to work with the issue boards Vue object
|
||||
if (document.querySelector('html').classList.contains('issue-boards-page')) {
|
||||
gl.issueBoards.boardStoreIssueSet(
|
||||
'subscribed',
|
||||
!gl.issueBoards.BoardsStore.detail.issue.subscribed,
|
||||
);
|
||||
} else {
|
||||
buttonSpan.innerHTML = isSubscribed ? 'Subscribe' : 'Unsubscribe';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static bindAll(selector) {
|
||||
[].forEach.call(document.querySelectorAll(selector), elm => new Subscription(elm));
|
||||
const subscribeButton = containerElm.querySelector('.js-subscribe-button');
|
||||
if (subscribeButton) {
|
||||
// remove class so we don't bind twice
|
||||
subscribeButton.classList.remove('js-subscribe-button');
|
||||
subscribeButton.addEventListener('click', this.toggleSubscription.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.Subscription = Subscription;
|
||||
})();
|
||||
toggleSubscription(event) {
|
||||
const button = event.currentTarget;
|
||||
const buttonSpan = button.querySelector('span');
|
||||
if (!buttonSpan || button.classList.contains('disabled')) {
|
||||
return;
|
||||
}
|
||||
button.classList.add('disabled');
|
||||
|
||||
const isSubscribed = buttonSpan.innerHTML.trim().toLowerCase() !== 'subscribe';
|
||||
const toggleActionUrl = this.containerElm.dataset.url;
|
||||
|
||||
$.post(toggleActionUrl, () => {
|
||||
button.classList.remove('disabled');
|
||||
|
||||
// hack to allow this to work with the issue boards Vue object
|
||||
if (document.querySelector('html').classList.contains('issue-boards-page')) {
|
||||
gl.issueBoards.boardStoreIssueSet(
|
||||
'subscribed',
|
||||
!gl.issueBoards.BoardsStore.detail.issue.subscribed,
|
||||
);
|
||||
} else {
|
||||
buttonSpan.innerHTML = isSubscribed ? 'Subscribe' : 'Unsubscribe';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static bindAll(selector) {
|
||||
[].forEach.call(document.querySelectorAll(selector), elm => new Subscription(elm));
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.Subscription = Subscription;
|
||||
|
|
|
@ -1,34 +1,33 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, object-shorthand, no-unused-vars, no-shadow, one-var, one-var-declaration-per-line, comma-dangle, max-len */
|
||||
(function() {
|
||||
this.SubscriptionSelect = (function() {
|
||||
function SubscriptionSelect() {
|
||||
$('.js-subscription-event').each(function(i, el) {
|
||||
var fieldName;
|
||||
fieldName = $(el).data("field-name");
|
||||
return $(el).glDropdown({
|
||||
selectable: true,
|
||||
fieldName: fieldName,
|
||||
toggleLabel: (function(_this) {
|
||||
return function(selected, el, instance) {
|
||||
var $item, label;
|
||||
label = 'Subscription';
|
||||
$item = instance.dropdown.find('.is-active');
|
||||
if ($item.length) {
|
||||
label = $item.text();
|
||||
}
|
||||
return label;
|
||||
};
|
||||
})(this),
|
||||
clicked: function(options) {
|
||||
return options.e.preventDefault();
|
||||
},
|
||||
id: function(obj, el) {
|
||||
return $(el).data("id");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return SubscriptionSelect;
|
||||
})();
|
||||
}).call(window);
|
||||
window.SubscriptionSelect = (function() {
|
||||
function SubscriptionSelect() {
|
||||
$('.js-subscription-event').each(function(i, el) {
|
||||
var fieldName;
|
||||
fieldName = $(el).data("field-name");
|
||||
return $(el).glDropdown({
|
||||
selectable: true,
|
||||
fieldName: fieldName,
|
||||
toggleLabel: (function(_this) {
|
||||
return function(selected, el, instance) {
|
||||
var $item, label;
|
||||
label = 'Subscription';
|
||||
$item = instance.dropdown.find('.is-active');
|
||||
if ($item.length) {
|
||||
label = $item.text();
|
||||
}
|
||||
return label;
|
||||
};
|
||||
})(this),
|
||||
clicked: function(options) {
|
||||
return options.e.preventDefault();
|
||||
},
|
||||
id: function(obj, el) {
|
||||
return $(el).data("id");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return SubscriptionSelect;
|
||||
})();
|
||||
|
|
|
@ -9,19 +9,18 @@
|
|||
//
|
||||
// <div class="js-syntax-highlight"></div>
|
||||
//
|
||||
(function() {
|
||||
$.fn.syntaxHighlight = function() {
|
||||
var $children;
|
||||
|
||||
if ($(this).hasClass('js-syntax-highlight')) {
|
||||
// Given the element itself, apply highlighting
|
||||
return $(this).addClass(gon.user_color_scheme);
|
||||
} else {
|
||||
// Given a parent element, recurse to any of its applicable children
|
||||
$children = $(this).find('.js-syntax-highlight');
|
||||
if ($children.length) {
|
||||
return $children.syntaxHighlight();
|
||||
}
|
||||
$.fn.syntaxHighlight = function() {
|
||||
var $children;
|
||||
|
||||
if ($(this).hasClass('js-syntax-highlight')) {
|
||||
// Given the element itself, apply highlighting
|
||||
return $(this).addClass(gon.user_color_scheme);
|
||||
} else {
|
||||
// Given a parent element, recurse to any of its applicable children
|
||||
$children = $(this).find('.js-syntax-highlight');
|
||||
if ($children.length) {
|
||||
return $children.syntaxHighlight();
|
||||
}
|
||||
};
|
||||
}).call(window);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,68 +1,66 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, quotes, consistent-return, no-var, one-var, one-var-declaration-per-line, no-else-return, prefer-arrow-callback, max-len */
|
||||
|
||||
(function() {
|
||||
this.TreeView = (function() {
|
||||
function TreeView() {
|
||||
this.initKeyNav();
|
||||
// Code browser tree slider
|
||||
// Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
|
||||
$(".tree-content-holder .tree-item").on('click', function(e) {
|
||||
var $clickedEl, path;
|
||||
$clickedEl = $(e.target);
|
||||
path = $('.tree-item-file-name a', this).attr('href');
|
||||
if (!$clickedEl.is('a') && !$clickedEl.is('.str-truncated')) {
|
||||
if (e.metaKey || e.which === 2) {
|
||||
e.preventDefault();
|
||||
return window.open(path, '_blank');
|
||||
} else {
|
||||
return gl.utils.visitUrl(path);
|
||||
}
|
||||
window.TreeView = (function() {
|
||||
function TreeView() {
|
||||
this.initKeyNav();
|
||||
// Code browser tree slider
|
||||
// Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
|
||||
$(".tree-content-holder .tree-item").on('click', function(e) {
|
||||
var $clickedEl, path;
|
||||
$clickedEl = $(e.target);
|
||||
path = $('.tree-item-file-name a', this).attr('href');
|
||||
if (!$clickedEl.is('a') && !$clickedEl.is('.str-truncated')) {
|
||||
if (e.metaKey || e.which === 2) {
|
||||
e.preventDefault();
|
||||
return window.open(path, '_blank');
|
||||
} else {
|
||||
return gl.utils.visitUrl(path);
|
||||
}
|
||||
});
|
||||
// Show the "Loading commit data" for only the first element
|
||||
$('span.log_loading:first').removeClass('hide');
|
||||
}
|
||||
}
|
||||
});
|
||||
// Show the "Loading commit data" for only the first element
|
||||
$('span.log_loading:first').removeClass('hide');
|
||||
}
|
||||
|
||||
TreeView.prototype.initKeyNav = function() {
|
||||
var li, liSelected;
|
||||
li = $("tr.tree-item");
|
||||
liSelected = null;
|
||||
return $('body').keydown(function(e) {
|
||||
var next, path;
|
||||
if ($("input:focus").length > 0 && (e.which === 38 || e.which === 40)) {
|
||||
return false;
|
||||
TreeView.prototype.initKeyNav = function() {
|
||||
var li, liSelected;
|
||||
li = $("tr.tree-item");
|
||||
liSelected = null;
|
||||
return $('body').keydown(function(e) {
|
||||
var next, path;
|
||||
if ($("input:focus").length > 0 && (e.which === 38 || e.which === 40)) {
|
||||
return false;
|
||||
}
|
||||
if (e.which === 40) {
|
||||
if (liSelected) {
|
||||
next = liSelected.next();
|
||||
if (next.length > 0) {
|
||||
liSelected.removeClass("selected");
|
||||
liSelected = next.addClass("selected");
|
||||
}
|
||||
} else {
|
||||
liSelected = li.eq(0).addClass("selected");
|
||||
}
|
||||
if (e.which === 40) {
|
||||
if (liSelected) {
|
||||
next = liSelected.next();
|
||||
if (next.length > 0) {
|
||||
liSelected.removeClass("selected");
|
||||
liSelected = next.addClass("selected");
|
||||
}
|
||||
} else {
|
||||
liSelected = li.eq(0).addClass("selected");
|
||||
}
|
||||
return $(liSelected).focus();
|
||||
} else if (e.which === 38) {
|
||||
if (liSelected) {
|
||||
next = liSelected.prev();
|
||||
if (next.length > 0) {
|
||||
liSelected.removeClass("selected");
|
||||
liSelected = next.addClass("selected");
|
||||
}
|
||||
} else {
|
||||
liSelected = li.last().addClass("selected");
|
||||
}
|
||||
return $(liSelected).focus();
|
||||
} else if (e.which === 13) {
|
||||
path = $('.tree-item.selected .tree-item-file-name a').attr('href');
|
||||
if (path) {
|
||||
return gl.utils.visitUrl(path);
|
||||
return $(liSelected).focus();
|
||||
} else if (e.which === 38) {
|
||||
if (liSelected) {
|
||||
next = liSelected.prev();
|
||||
if (next.length > 0) {
|
||||
liSelected.removeClass("selected");
|
||||
liSelected = next.addClass("selected");
|
||||
}
|
||||
} else {
|
||||
liSelected = li.last().addClass("selected");
|
||||
}
|
||||
});
|
||||
};
|
||||
return $(liSelected).focus();
|
||||
} else if (e.which === 13) {
|
||||
path = $('.tree-item.selected .tree-item-file-name a').attr('href');
|
||||
if (path) {
|
||||
return gl.utils.visitUrl(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return TreeView;
|
||||
})();
|
||||
}).call(window);
|
||||
return TreeView;
|
||||
})();
|
||||
|
|
|
@ -2,34 +2,35 @@
|
|||
|
||||
import Cookies from 'js-cookie';
|
||||
|
||||
((global) => {
|
||||
global.User = class {
|
||||
constructor({ action }) {
|
||||
this.action = action;
|
||||
this.placeProfileAvatarsToTop();
|
||||
this.initTabs();
|
||||
this.hideProjectLimitMessage();
|
||||
}
|
||||
class User {
|
||||
constructor({ action }) {
|
||||
this.action = action;
|
||||
this.placeProfileAvatarsToTop();
|
||||
this.initTabs();
|
||||
this.hideProjectLimitMessage();
|
||||
}
|
||||
|
||||
placeProfileAvatarsToTop() {
|
||||
$('.profile-groups-avatars').tooltip({
|
||||
placement: 'top'
|
||||
});
|
||||
}
|
||||
placeProfileAvatarsToTop() {
|
||||
$('.profile-groups-avatars').tooltip({
|
||||
placement: 'top'
|
||||
});
|
||||
}
|
||||
|
||||
initTabs() {
|
||||
return new global.UserTabs({
|
||||
parentEl: '.user-profile',
|
||||
action: this.action
|
||||
});
|
||||
}
|
||||
initTabs() {
|
||||
return new window.gl.UserTabs({
|
||||
parentEl: '.user-profile',
|
||||
action: this.action
|
||||
});
|
||||
}
|
||||
|
||||
hideProjectLimitMessage() {
|
||||
$('.hide-project-limit-message').on('click', e => {
|
||||
e.preventDefault();
|
||||
Cookies.set('hide_project_limit_message', 'false');
|
||||
$(this).parents('.project-limit-message').remove();
|
||||
});
|
||||
}
|
||||
};
|
||||
})(window.gl || (window.gl = {}));
|
||||
hideProjectLimitMessage() {
|
||||
$('.hide-project-limit-message').on('click', e => {
|
||||
e.preventDefault();
|
||||
Cookies.set('hide_project_limit_message', 'false');
|
||||
$(this).parents('.project-limit-message').remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.User = User;
|
||||
|
|
|
@ -59,117 +59,118 @@ content on the Users#show page.
|
|||
</div>
|
||||
</div>
|
||||
*/
|
||||
((global) => {
|
||||
class UserTabs {
|
||||
constructor ({ defaultAction, action, parentEl }) {
|
||||
this.loaded = {};
|
||||
this.defaultAction = defaultAction || 'activity';
|
||||
this.action = action || this.defaultAction;
|
||||
this.$parentEl = $(parentEl) || $(document);
|
||||
this._location = window.location;
|
||||
this.$parentEl.find('.nav-links a')
|
||||
.each((i, navLink) => {
|
||||
this.loaded[$(navLink).attr('data-action')] = false;
|
||||
});
|
||||
this.actions = Object.keys(this.loaded);
|
||||
this.bindEvents();
|
||||
|
||||
if (this.action === 'show') {
|
||||
this.action = this.defaultAction;
|
||||
}
|
||||
|
||||
this.activateTab(this.action);
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.changeProjectsPageWrapper = this.changeProjectsPage.bind(this);
|
||||
|
||||
this.$parentEl.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
|
||||
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event));
|
||||
|
||||
this.$parentEl.on('click', '.gl-pagination a', this.changeProjectsPageWrapper);
|
||||
}
|
||||
|
||||
changeProjectsPage(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$('.tab-pane.active').empty();
|
||||
const endpoint = $(e.target).attr('href');
|
||||
this.loadTab(this.getCurrentAction(), endpoint);
|
||||
}
|
||||
|
||||
tabShown(event) {
|
||||
const $target = $(event.target);
|
||||
const action = $target.data('action');
|
||||
const source = $target.attr('href');
|
||||
const endpoint = $target.data('endpoint');
|
||||
this.setTab(action, endpoint);
|
||||
return this.setCurrentAction(source);
|
||||
}
|
||||
|
||||
activateTab(action) {
|
||||
return this.$parentEl.find(`.nav-links .js-${action}-tab a`)
|
||||
.tab('show');
|
||||
}
|
||||
|
||||
setTab(action, endpoint) {
|
||||
if (this.loaded[action]) {
|
||||
return;
|
||||
}
|
||||
if (action === 'activity') {
|
||||
this.loadActivities();
|
||||
}
|
||||
|
||||
const loadableActions = ['groups', 'contributed', 'projects', 'snippets'];
|
||||
if (loadableActions.indexOf(action) > -1) {
|
||||
return this.loadTab(action, endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
loadTab(action, endpoint) {
|
||||
return $.ajax({
|
||||
beforeSend: () => this.toggleLoading(true),
|
||||
complete: () => this.toggleLoading(false),
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
url: endpoint,
|
||||
success: (data) => {
|
||||
const tabSelector = `div#${action}`;
|
||||
this.$parentEl.find(tabSelector).html(data.html);
|
||||
this.loaded[action] = true;
|
||||
return gl.utils.localTimeAgo($('.js-timeago', tabSelector));
|
||||
}
|
||||
class UserTabs {
|
||||
constructor ({ defaultAction, action, parentEl }) {
|
||||
this.loaded = {};
|
||||
this.defaultAction = defaultAction || 'activity';
|
||||
this.action = action || this.defaultAction;
|
||||
this.$parentEl = $(parentEl) || $(document);
|
||||
this._location = window.location;
|
||||
this.$parentEl.find('.nav-links a')
|
||||
.each((i, navLink) => {
|
||||
this.loaded[$(navLink).attr('data-action')] = false;
|
||||
});
|
||||
this.actions = Object.keys(this.loaded);
|
||||
this.bindEvents();
|
||||
|
||||
if (this.action === 'show') {
|
||||
this.action = this.defaultAction;
|
||||
}
|
||||
|
||||
loadActivities() {
|
||||
if (this.loaded['activity']) {
|
||||
return;
|
||||
}
|
||||
const $calendarWrap = this.$parentEl.find('.user-calendar');
|
||||
$calendarWrap.load($calendarWrap.data('href'));
|
||||
new gl.Activities();
|
||||
return this.loaded['activity'] = true;
|
||||
this.activateTab(this.action);
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
this.changeProjectsPageWrapper = this.changeProjectsPage.bind(this);
|
||||
|
||||
this.$parentEl.off('shown.bs.tab', '.nav-links a[data-toggle="tab"]')
|
||||
.on('shown.bs.tab', '.nav-links a[data-toggle="tab"]', event => this.tabShown(event));
|
||||
|
||||
this.$parentEl.on('click', '.gl-pagination a', this.changeProjectsPageWrapper);
|
||||
}
|
||||
|
||||
changeProjectsPage(e) {
|
||||
e.preventDefault();
|
||||
|
||||
$('.tab-pane.active').empty();
|
||||
const endpoint = $(e.target).attr('href');
|
||||
this.loadTab(this.getCurrentAction(), endpoint);
|
||||
}
|
||||
|
||||
tabShown(event) {
|
||||
const $target = $(event.target);
|
||||
const action = $target.data('action');
|
||||
const source = $target.attr('href');
|
||||
const endpoint = $target.data('endpoint');
|
||||
this.setTab(action, endpoint);
|
||||
return this.setCurrentAction(source);
|
||||
}
|
||||
|
||||
activateTab(action) {
|
||||
return this.$parentEl.find(`.nav-links .js-${action}-tab a`)
|
||||
.tab('show');
|
||||
}
|
||||
|
||||
setTab(action, endpoint) {
|
||||
if (this.loaded[action]) {
|
||||
return;
|
||||
}
|
||||
if (action === 'activity') {
|
||||
this.loadActivities();
|
||||
}
|
||||
|
||||
toggleLoading(status) {
|
||||
return this.$parentEl.find('.loading-status .loading')
|
||||
.toggle(status);
|
||||
}
|
||||
|
||||
setCurrentAction(source) {
|
||||
let new_state = source;
|
||||
new_state = new_state.replace(/\/+$/, '');
|
||||
new_state += this._location.search + this._location.hash;
|
||||
history.replaceState({
|
||||
url: new_state
|
||||
}, document.title, new_state);
|
||||
return new_state;
|
||||
}
|
||||
|
||||
getCurrentAction() {
|
||||
return this.$parentEl.find('.nav-links .active a').data('action');
|
||||
const loadableActions = ['groups', 'contributed', 'projects', 'snippets'];
|
||||
if (loadableActions.indexOf(action) > -1) {
|
||||
return this.loadTab(action, endpoint);
|
||||
}
|
||||
}
|
||||
global.UserTabs = UserTabs;
|
||||
})(window.gl || (window.gl = {}));
|
||||
|
||||
loadTab(action, endpoint) {
|
||||
return $.ajax({
|
||||
beforeSend: () => this.toggleLoading(true),
|
||||
complete: () => this.toggleLoading(false),
|
||||
dataType: 'json',
|
||||
type: 'GET',
|
||||
url: endpoint,
|
||||
success: (data) => {
|
||||
const tabSelector = `div#${action}`;
|
||||
this.$parentEl.find(tabSelector).html(data.html);
|
||||
this.loaded[action] = true;
|
||||
return gl.utils.localTimeAgo($('.js-timeago', tabSelector));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadActivities() {
|
||||
if (this.loaded['activity']) {
|
||||
return;
|
||||
}
|
||||
const $calendarWrap = this.$parentEl.find('.user-calendar');
|
||||
$calendarWrap.load($calendarWrap.data('href'));
|
||||
new gl.Activities();
|
||||
return this.loaded['activity'] = true;
|
||||
}
|
||||
|
||||
toggleLoading(status) {
|
||||
return this.$parentEl.find('.loading-status .loading')
|
||||
.toggle(status);
|
||||
}
|
||||
|
||||
setCurrentAction(source) {
|
||||
let new_state = source;
|
||||
new_state = new_state.replace(/\/+$/, '');
|
||||
new_state += this._location.search + this._location.hash;
|
||||
history.replaceState({
|
||||
url: new_state
|
||||
}, document.title, new_state);
|
||||
return new_state;
|
||||
}
|
||||
|
||||
getCurrentAction() {
|
||||
return this.$parentEl.find('.nav-links .active a').data('action');
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.UserTabs = UserTabs;
|
||||
|
|
|
@ -1,135 +1,133 @@
|
|||
/* eslint-disable comma-dangle, consistent-return, class-methods-use-this, arrow-parens, no-param-reassign, max-len */
|
||||
|
||||
((global) => {
|
||||
const debounceTimeoutDuration = 1000;
|
||||
const invalidInputClass = 'gl-field-error-outline';
|
||||
const successInputClass = 'gl-field-success-outline';
|
||||
const unavailableMessageSelector = '.username .validation-error';
|
||||
const successMessageSelector = '.username .validation-success';
|
||||
const pendingMessageSelector = '.username .validation-pending';
|
||||
const invalidMessageSelector = '.username .gl-field-error';
|
||||
const debounceTimeoutDuration = 1000;
|
||||
const invalidInputClass = 'gl-field-error-outline';
|
||||
const successInputClass = 'gl-field-success-outline';
|
||||
const unavailableMessageSelector = '.username .validation-error';
|
||||
const successMessageSelector = '.username .validation-success';
|
||||
const pendingMessageSelector = '.username .validation-pending';
|
||||
const invalidMessageSelector = '.username .gl-field-error';
|
||||
|
||||
class UsernameValidator {
|
||||
constructor() {
|
||||
this.inputElement = $('#new_user_username');
|
||||
this.inputDomElement = this.inputElement.get(0);
|
||||
this.state = {
|
||||
available: false,
|
||||
valid: false,
|
||||
pending: false,
|
||||
empty: true
|
||||
};
|
||||
class UsernameValidator {
|
||||
constructor() {
|
||||
this.inputElement = $('#new_user_username');
|
||||
this.inputDomElement = this.inputElement.get(0);
|
||||
this.state = {
|
||||
available: false,
|
||||
valid: false,
|
||||
pending: false,
|
||||
empty: true
|
||||
};
|
||||
|
||||
const debounceTimeout = _.debounce((username) => {
|
||||
this.validateUsername(username);
|
||||
}, debounceTimeoutDuration);
|
||||
const debounceTimeout = _.debounce((username) => {
|
||||
this.validateUsername(username);
|
||||
}, debounceTimeoutDuration);
|
||||
|
||||
this.inputElement.on('keyup.username_check', () => {
|
||||
const username = this.inputElement.val();
|
||||
this.inputElement.on('keyup.username_check', () => {
|
||||
const username = this.inputElement.val();
|
||||
|
||||
this.state.valid = this.inputDomElement.validity.valid;
|
||||
this.state.empty = !username.length;
|
||||
this.state.valid = this.inputDomElement.validity.valid;
|
||||
this.state.empty = !username.length;
|
||||
|
||||
if (this.state.valid) {
|
||||
return debounceTimeout(username);
|
||||
}
|
||||
|
||||
this.renderState();
|
||||
});
|
||||
|
||||
// Override generic field validation
|
||||
this.inputElement.on('invalid', this.interceptInvalid.bind(this));
|
||||
}
|
||||
|
||||
renderState() {
|
||||
// Clear all state
|
||||
this.clearFieldValidationState();
|
||||
|
||||
if (this.state.valid && this.state.available) {
|
||||
return this.setSuccessState();
|
||||
}
|
||||
|
||||
if (this.state.empty) {
|
||||
return this.clearFieldValidationState();
|
||||
}
|
||||
|
||||
if (this.state.pending) {
|
||||
return this.setPendingState();
|
||||
}
|
||||
|
||||
if (!this.state.available) {
|
||||
return this.setUnavailableState();
|
||||
}
|
||||
|
||||
if (!this.state.valid) {
|
||||
return this.setInvalidState();
|
||||
}
|
||||
}
|
||||
|
||||
interceptInvalid(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
validateUsername(username) {
|
||||
if (this.state.valid) {
|
||||
this.state.pending = true;
|
||||
this.state.available = false;
|
||||
this.renderState();
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
url: `${gon.relative_url_root}/users/${username}/exists`,
|
||||
dataType: 'json',
|
||||
success: (res) => this.setAvailabilityState(res.exists)
|
||||
});
|
||||
return debounceTimeout(username);
|
||||
}
|
||||
}
|
||||
|
||||
setAvailabilityState(usernameTaken) {
|
||||
if (usernameTaken) {
|
||||
this.state.valid = false;
|
||||
this.state.available = false;
|
||||
} else {
|
||||
this.state.available = true;
|
||||
}
|
||||
this.state.pending = false;
|
||||
this.renderState();
|
||||
});
|
||||
|
||||
// Override generic field validation
|
||||
this.inputElement.on('invalid', this.interceptInvalid.bind(this));
|
||||
}
|
||||
|
||||
renderState() {
|
||||
// Clear all state
|
||||
this.clearFieldValidationState();
|
||||
|
||||
if (this.state.valid && this.state.available) {
|
||||
return this.setSuccessState();
|
||||
}
|
||||
|
||||
clearFieldValidationState() {
|
||||
this.inputElement.siblings('p').hide();
|
||||
|
||||
this.inputElement.removeClass(invalidInputClass)
|
||||
.removeClass(successInputClass);
|
||||
if (this.state.empty) {
|
||||
return this.clearFieldValidationState();
|
||||
}
|
||||
|
||||
setUnavailableState() {
|
||||
const $usernameUnavailableMessage = this.inputElement.siblings(unavailableMessageSelector);
|
||||
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
||||
$usernameUnavailableMessage.show();
|
||||
if (this.state.pending) {
|
||||
return this.setPendingState();
|
||||
}
|
||||
|
||||
setSuccessState() {
|
||||
const $usernameSuccessMessage = this.inputElement.siblings(successMessageSelector);
|
||||
this.inputElement.addClass(successInputClass).removeClass(invalidInputClass);
|
||||
$usernameSuccessMessage.show();
|
||||
if (!this.state.available) {
|
||||
return this.setUnavailableState();
|
||||
}
|
||||
|
||||
setPendingState() {
|
||||
const $usernamePendingMessage = $(pendingMessageSelector);
|
||||
if (this.state.pending) {
|
||||
$usernamePendingMessage.show();
|
||||
} else {
|
||||
$usernamePendingMessage.hide();
|
||||
}
|
||||
}
|
||||
|
||||
setInvalidState() {
|
||||
const $inputErrorMessage = $(invalidMessageSelector);
|
||||
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
||||
$inputErrorMessage.show();
|
||||
if (!this.state.valid) {
|
||||
return this.setInvalidState();
|
||||
}
|
||||
}
|
||||
|
||||
global.UsernameValidator = UsernameValidator;
|
||||
})(window);
|
||||
interceptInvalid(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
validateUsername(username) {
|
||||
if (this.state.valid) {
|
||||
this.state.pending = true;
|
||||
this.state.available = false;
|
||||
this.renderState();
|
||||
return $.ajax({
|
||||
type: 'GET',
|
||||
url: `${gon.relative_url_root}/users/${username}/exists`,
|
||||
dataType: 'json',
|
||||
success: (res) => this.setAvailabilityState(res.exists)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setAvailabilityState(usernameTaken) {
|
||||
if (usernameTaken) {
|
||||
this.state.valid = false;
|
||||
this.state.available = false;
|
||||
} else {
|
||||
this.state.available = true;
|
||||
}
|
||||
this.state.pending = false;
|
||||
this.renderState();
|
||||
}
|
||||
|
||||
clearFieldValidationState() {
|
||||
this.inputElement.siblings('p').hide();
|
||||
|
||||
this.inputElement.removeClass(invalidInputClass)
|
||||
.removeClass(successInputClass);
|
||||
}
|
||||
|
||||
setUnavailableState() {
|
||||
const $usernameUnavailableMessage = this.inputElement.siblings(unavailableMessageSelector);
|
||||
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
||||
$usernameUnavailableMessage.show();
|
||||
}
|
||||
|
||||
setSuccessState() {
|
||||
const $usernameSuccessMessage = this.inputElement.siblings(successMessageSelector);
|
||||
this.inputElement.addClass(successInputClass).removeClass(invalidInputClass);
|
||||
$usernameSuccessMessage.show();
|
||||
}
|
||||
|
||||
setPendingState() {
|
||||
const $usernamePendingMessage = $(pendingMessageSelector);
|
||||
if (this.state.pending) {
|
||||
$usernamePendingMessage.show();
|
||||
} else {
|
||||
$usernamePendingMessage.hide();
|
||||
}
|
||||
}
|
||||
|
||||
setInvalidState() {
|
||||
const $inputErrorMessage = $(invalidMessageSelector);
|
||||
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
|
||||
$inputErrorMessage.show();
|
||||
}
|
||||
}
|
||||
|
||||
window.UsernameValidator = UsernameValidator;
|
||||
|
|
|
@ -206,8 +206,6 @@ function UsersSelect(currentUser, els) {
|
|||
return $dropdown.glDropdown({
|
||||
showMenuAbove: showMenuAbove,
|
||||
data: function(term, callback) {
|
||||
var isAuthorFilter;
|
||||
isAuthorFilter = $('.js-author-search');
|
||||
return _this.users(term, options, function(users) {
|
||||
// GitLabDropdownFilter returns this.instance
|
||||
// GitLabDropdownRemote returns this.options.instance
|
||||
|
|
|
@ -1,27 +1,24 @@
|
|||
(() => {
|
||||
const gl = window.gl || (window.gl = {});
|
||||
class VisibilitySelect {
|
||||
constructor(container) {
|
||||
if (!container) throw new Error('VisibilitySelect requires a container element as argument 1');
|
||||
this.container = container;
|
||||
this.helpBlock = this.container.querySelector('.help-block');
|
||||
this.select = this.container.querySelector('select');
|
||||
}
|
||||
|
||||
class VisibilitySelect {
|
||||
constructor(container) {
|
||||
if (!container) throw new Error('VisibilitySelect requires a container element as argument 1');
|
||||
this.container = container;
|
||||
this.helpBlock = this.container.querySelector('.help-block');
|
||||
this.select = this.container.querySelector('select');
|
||||
}
|
||||
|
||||
init() {
|
||||
if (this.select) {
|
||||
this.updateHelpText();
|
||||
this.select.addEventListener('change', this.updateHelpText.bind(this));
|
||||
} else {
|
||||
this.helpBlock.textContent = this.container.querySelector('.js-locked').dataset.helpBlock;
|
||||
}
|
||||
}
|
||||
|
||||
updateHelpText() {
|
||||
this.helpBlock.textContent = this.select.querySelector('option:checked').dataset.description;
|
||||
init() {
|
||||
if (this.select) {
|
||||
this.updateHelpText();
|
||||
this.select.addEventListener('change', this.updateHelpText.bind(this));
|
||||
} else {
|
||||
this.helpBlock.textContent = this.container.querySelector('.js-locked').dataset.helpBlock;
|
||||
}
|
||||
}
|
||||
|
||||
gl.VisibilitySelect = VisibilitySelect;
|
||||
})();
|
||||
updateHelpText() {
|
||||
this.helpBlock.textContent = this.select.querySelector('option:checked').dataset.description;
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.VisibilitySelect = VisibilitySelect;
|
||||
|
|
|
@ -17,9 +17,6 @@ export default {
|
|||
|
||||
return hasCI && !ciStatus;
|
||||
},
|
||||
hasPipeline() {
|
||||
return Object.keys(this.mr.pipeline || {}).length > 0;
|
||||
},
|
||||
svg() {
|
||||
return statusIconEntityMap.icon_status_failed;
|
||||
},
|
||||
|
@ -33,11 +30,7 @@ export default {
|
|||
template: `
|
||||
<div class="mr-widget-heading">
|
||||
<div class="ci-widget">
|
||||
<template v-if="!hasPipeline">
|
||||
<i class="fa fa-spinner fa-spin append-right-10" aria-hidden="true"></i>
|
||||
Waiting for pipeline...
|
||||
</template>
|
||||
<template v-else-if="hasCIError">
|
||||
<template v-if="hasCIError">
|
||||
<div class="ci-status-icon ci-status-icon-failed ci-error js-ci-error">
|
||||
<span class="js-icon-link icon-link">
|
||||
<span
|
||||
|
|
|
@ -4,66 +4,65 @@
|
|||
import 'vendor/jquery.nicescroll';
|
||||
import './breakpoints';
|
||||
|
||||
((global) => {
|
||||
class Wikis {
|
||||
constructor() {
|
||||
this.bp = Breakpoints.get();
|
||||
this.sidebarEl = document.querySelector('.js-wiki-sidebar');
|
||||
this.sidebarExpanded = false;
|
||||
$(this.sidebarEl).niceScroll();
|
||||
class Wikis {
|
||||
constructor() {
|
||||
this.bp = Breakpoints.get();
|
||||
this.sidebarEl = document.querySelector('.js-wiki-sidebar');
|
||||
this.sidebarExpanded = false;
|
||||
$(this.sidebarEl).niceScroll();
|
||||
|
||||
const sidebarToggles = document.querySelectorAll('.js-sidebar-wiki-toggle');
|
||||
for (let i = 0; i < sidebarToggles.length; i += 1) {
|
||||
sidebarToggles[i].addEventListener('click', e => this.handleToggleSidebar(e));
|
||||
}
|
||||
|
||||
this.newWikiForm = document.querySelector('form.new-wiki-page');
|
||||
if (this.newWikiForm) {
|
||||
this.newWikiForm.addEventListener('submit', e => this.handleNewWikiSubmit(e));
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => this.renderSidebar());
|
||||
this.renderSidebar();
|
||||
const sidebarToggles = document.querySelectorAll('.js-sidebar-wiki-toggle');
|
||||
for (let i = 0; i < sidebarToggles.length; i += 1) {
|
||||
sidebarToggles[i].addEventListener('click', e => this.handleToggleSidebar(e));
|
||||
}
|
||||
|
||||
handleNewWikiSubmit(e) {
|
||||
if (!this.newWikiForm) return;
|
||||
|
||||
const slugInput = this.newWikiForm.querySelector('#new_wiki_path');
|
||||
const slug = gl.text.slugify(slugInput.value);
|
||||
|
||||
if (slug.length > 0) {
|
||||
const wikisPath = slugInput.getAttribute('data-wikis-path');
|
||||
window.location.href = `${wikisPath}/${slug}`;
|
||||
e.preventDefault();
|
||||
}
|
||||
this.newWikiForm = document.querySelector('form.new-wiki-page');
|
||||
if (this.newWikiForm) {
|
||||
this.newWikiForm.addEventListener('submit', e => this.handleNewWikiSubmit(e));
|
||||
}
|
||||
|
||||
handleToggleSidebar(e) {
|
||||
window.addEventListener('resize', () => this.renderSidebar());
|
||||
this.renderSidebar();
|
||||
}
|
||||
|
||||
handleNewWikiSubmit(e) {
|
||||
if (!this.newWikiForm) return;
|
||||
|
||||
const slugInput = this.newWikiForm.querySelector('#new_wiki_path');
|
||||
const slug = gl.text.slugify(slugInput.value);
|
||||
|
||||
if (slug.length > 0) {
|
||||
const wikisPath = slugInput.getAttribute('data-wikis-path');
|
||||
window.location.href = `${wikisPath}/${slug}`;
|
||||
e.preventDefault();
|
||||
this.sidebarExpanded = !this.sidebarExpanded;
|
||||
this.renderSidebar();
|
||||
}
|
||||
|
||||
sidebarCanCollapse() {
|
||||
const bootstrapBreakpoint = this.bp.getBreakpointSize();
|
||||
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
|
||||
}
|
||||
|
||||
renderSidebar() {
|
||||
if (!this.sidebarEl) return;
|
||||
const { classList } = this.sidebarEl;
|
||||
if (this.sidebarExpanded || !this.sidebarCanCollapse()) {
|
||||
if (!classList.contains('right-sidebar-expanded')) {
|
||||
classList.remove('right-sidebar-collapsed');
|
||||
classList.add('right-sidebar-expanded');
|
||||
}
|
||||
} else if (classList.contains('right-sidebar-expanded')) {
|
||||
classList.add('right-sidebar-collapsed');
|
||||
classList.remove('right-sidebar-expanded');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
global.Wikis = Wikis;
|
||||
})(window.gl || (window.gl = {}));
|
||||
handleToggleSidebar(e) {
|
||||
e.preventDefault();
|
||||
this.sidebarExpanded = !this.sidebarExpanded;
|
||||
this.renderSidebar();
|
||||
}
|
||||
|
||||
sidebarCanCollapse() {
|
||||
const bootstrapBreakpoint = this.bp.getBreakpointSize();
|
||||
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
|
||||
}
|
||||
|
||||
renderSidebar() {
|
||||
if (!this.sidebarEl) return;
|
||||
const { classList } = this.sidebarEl;
|
||||
if (this.sidebarExpanded || !this.sidebarCanCollapse()) {
|
||||
if (!classList.contains('right-sidebar-expanded')) {
|
||||
classList.remove('right-sidebar-collapsed');
|
||||
classList.add('right-sidebar-expanded');
|
||||
}
|
||||
} else if (classList.contains('right-sidebar-expanded')) {
|
||||
classList.add('right-sidebar-collapsed');
|
||||
classList.remove('right-sidebar-expanded');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.Wikis = Wikis;
|
||||
|
|
|
@ -34,65 +34,64 @@ window.Dropzone = Dropzone;
|
|||
// **Cancelable** No
|
||||
// **Target** a.js-zen-leave
|
||||
//
|
||||
(function() {
|
||||
this.ZenMode = (function() {
|
||||
function ZenMode() {
|
||||
this.active_backdrop = null;
|
||||
this.active_textarea = null;
|
||||
$(document).on('click', '.js-zen-enter', function(e) {
|
||||
e.preventDefault();
|
||||
return $(e.currentTarget).trigger('zen_mode:enter');
|
||||
});
|
||||
$(document).on('click', '.js-zen-leave', function(e) {
|
||||
e.preventDefault();
|
||||
return $(e.currentTarget).trigger('zen_mode:leave');
|
||||
});
|
||||
$(document).on('zen_mode:enter', (function(_this) {
|
||||
return function(e) {
|
||||
return _this.enter($(e.target).closest('.md-area').find('.zen-backdrop'));
|
||||
};
|
||||
})(this));
|
||||
$(document).on('zen_mode:leave', (function(_this) {
|
||||
return function(e) {
|
||||
return _this.exit();
|
||||
};
|
||||
})(this));
|
||||
$(document).on('keydown', function(e) {
|
||||
// Esc
|
||||
if (e.keyCode === 27) {
|
||||
e.preventDefault();
|
||||
return $(document).trigger('zen_mode:leave');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ZenMode.prototype.enter = function(backdrop) {
|
||||
Mousetrap.pause();
|
||||
this.active_backdrop = $(backdrop);
|
||||
this.active_backdrop.addClass('fullscreen');
|
||||
this.active_textarea = this.active_backdrop.find('textarea');
|
||||
// Prevent a user-resized textarea from persisting to fullscreen
|
||||
this.active_textarea.removeAttr('style');
|
||||
return this.active_textarea.focus();
|
||||
};
|
||||
|
||||
ZenMode.prototype.exit = function() {
|
||||
if (this.active_textarea) {
|
||||
Mousetrap.unpause();
|
||||
this.active_textarea.closest('.zen-backdrop').removeClass('fullscreen');
|
||||
this.scrollTo(this.active_textarea);
|
||||
this.active_textarea = null;
|
||||
this.active_backdrop = null;
|
||||
return Dropzone.forElement('.div-dropzone').enable();
|
||||
window.ZenMode = (function() {
|
||||
function ZenMode() {
|
||||
this.active_backdrop = null;
|
||||
this.active_textarea = null;
|
||||
$(document).on('click', '.js-zen-enter', function(e) {
|
||||
e.preventDefault();
|
||||
return $(e.currentTarget).trigger('zen_mode:enter');
|
||||
});
|
||||
$(document).on('click', '.js-zen-leave', function(e) {
|
||||
e.preventDefault();
|
||||
return $(e.currentTarget).trigger('zen_mode:leave');
|
||||
});
|
||||
$(document).on('zen_mode:enter', (function(_this) {
|
||||
return function(e) {
|
||||
return _this.enter($(e.target).closest('.md-area').find('.zen-backdrop'));
|
||||
};
|
||||
})(this));
|
||||
$(document).on('zen_mode:leave', (function(_this) {
|
||||
return function(e) {
|
||||
return _this.exit();
|
||||
};
|
||||
})(this));
|
||||
$(document).on('keydown', function(e) {
|
||||
// Esc
|
||||
if (e.keyCode === 27) {
|
||||
e.preventDefault();
|
||||
return $(document).trigger('zen_mode:leave');
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
ZenMode.prototype.scrollTo = function(zen_area) {
|
||||
return $.scrollTo(zen_area, 0, {
|
||||
offset: -150
|
||||
});
|
||||
};
|
||||
ZenMode.prototype.enter = function(backdrop) {
|
||||
Mousetrap.pause();
|
||||
this.active_backdrop = $(backdrop);
|
||||
this.active_backdrop.addClass('fullscreen');
|
||||
this.active_textarea = this.active_backdrop.find('textarea');
|
||||
// Prevent a user-resized textarea from persisting to fullscreen
|
||||
this.active_textarea.removeAttr('style');
|
||||
return this.active_textarea.focus();
|
||||
};
|
||||
|
||||
return ZenMode;
|
||||
})();
|
||||
}).call(window);
|
||||
ZenMode.prototype.exit = function() {
|
||||
if (this.active_textarea) {
|
||||
Mousetrap.unpause();
|
||||
this.active_textarea.closest('.zen-backdrop').removeClass('fullscreen');
|
||||
this.scrollTo(this.active_textarea);
|
||||
this.active_textarea = null;
|
||||
this.active_backdrop = null;
|
||||
return Dropzone.forElement('.div-dropzone').enable();
|
||||
}
|
||||
};
|
||||
|
||||
ZenMode.prototype.scrollTo = function(zen_area) {
|
||||
return $.scrollTo(zen_area, 0, {
|
||||
offset: -150
|
||||
});
|
||||
};
|
||||
|
||||
return ZenMode;
|
||||
})();
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
max-width: $limited-layout-width-sm;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-top: 64px;
|
||||
padding-bottom: 64px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@
|
|||
@mixin maintain-sidebar-dimensions {
|
||||
display: block;
|
||||
width: $gutter-width;
|
||||
padding: 10px 20px;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.issues-bulk-update.right-sidebar {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
color: $gl-text-color;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: $border-radius-default;
|
||||
margin-bottom: $gl-padding;
|
||||
|
||||
.well-segment {
|
||||
padding: $gl-padding;
|
||||
|
@ -21,6 +22,11 @@
|
|||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
&.admin-well h4 {
|
||||
border-bottom: 1px solid $border-color;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
|
@ -53,6 +59,14 @@
|
|||
padding: 15px;
|
||||
}
|
||||
|
||||
.dark-well {
|
||||
background-color: $gray-normal;
|
||||
|
||||
.btn {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.well-centered {
|
||||
h1 {
|
||||
font-weight: normal;
|
||||
|
|
|
@ -37,65 +37,77 @@
|
|||
}
|
||||
|
||||
.build-page {
|
||||
.sticky {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
.build-trace-container {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.build-trace-container {
|
||||
position: absolute;
|
||||
top: 225px;
|
||||
left: 15px;
|
||||
bottom: 10px;
|
||||
.build-trace {
|
||||
background: $black;
|
||||
color: $gray-darkest;
|
||||
font-family: $monospace_font;
|
||||
white-space: pre;
|
||||
overflow-x: auto;
|
||||
font-size: 12px;
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
|
||||
&.sidebar-expanded {
|
||||
right: 305px;
|
||||
.bash {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
background: $gray-light;
|
||||
border: 1px solid $border-color;
|
||||
color: $gl-text-color;
|
||||
position: sticky;
|
||||
position: -webkit-sticky;
|
||||
top: 50px;
|
||||
|
||||
&.affix {
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
&.sidebar-collapsed {
|
||||
// with sidebar
|
||||
&.affix.sidebar-expanded {
|
||||
right: 306px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
// without sidebar
|
||||
&.affix.sidebar-collapsed {
|
||||
right: 16px;
|
||||
left: 16px;
|
||||
}
|
||||
|
||||
code {
|
||||
background: $black;
|
||||
color: $gray-darkest;
|
||||
&.affix-top {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.top-bar {
|
||||
top: 0;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
background: $gray-light;
|
||||
border: 1px solid $border-color;
|
||||
color: $gl-text-color;
|
||||
.truncated-info {
|
||||
margin: 0 auto;
|
||||
align-self: center;
|
||||
|
||||
.truncated-info {
|
||||
margin: 0 auto;
|
||||
align-self: center;
|
||||
.truncated-info-size {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.truncated-info-size {
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.raw-link {
|
||||
color: $gl-text-color;
|
||||
margin-left: 5px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.raw-link {
|
||||
color: $gl-text-color;
|
||||
margin-left: 5px;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.controllers {
|
||||
display: flex;
|
||||
align-self: center;
|
||||
font-size: 15px;
|
||||
margin-bottom: 4px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
height: 15px;
|
||||
|
@ -103,17 +115,9 @@
|
|||
fill: $gl-text-color;
|
||||
}
|
||||
|
||||
.controllers-buttons,
|
||||
.btn-scroll {
|
||||
color: $gl-text-color;
|
||||
height: 15px;
|
||||
vertical-align: middle;
|
||||
padding: 0;
|
||||
width: 12px;
|
||||
}
|
||||
|
||||
.controllers-buttons {
|
||||
margin: 1px 10px;
|
||||
color: $gl-text-color;
|
||||
margin: 0 10px;
|
||||
}
|
||||
|
||||
.btn-scroll.animate {
|
||||
|
@ -143,15 +147,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.bash {
|
||||
top: 35px;
|
||||
left: 10px;
|
||||
bottom: 0;
|
||||
padding: 10px 20px 20px 5px;
|
||||
white-space: pre-wrap;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.environment-information {
|
||||
border: 1px solid $border-color;
|
||||
padding: 8px $gl-padding 12px;
|
||||
|
|
|
@ -187,8 +187,7 @@
|
|||
}
|
||||
|
||||
.text-metric {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.selected-metric-line {
|
||||
|
@ -232,10 +231,6 @@
|
|||
width: 100%;
|
||||
padding: 0;
|
||||
padding-bottom: 100%;
|
||||
|
||||
.text-metric-bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.prometheus-svg-container > svg {
|
||||
|
@ -250,11 +245,15 @@
|
|||
stroke-width: 0;
|
||||
}
|
||||
|
||||
.text-metric-bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.label-axis-text,
|
||||
.text-metric-usage {
|
||||
fill: $black;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.legend-axis-text {
|
||||
|
@ -262,7 +261,20 @@
|
|||
}
|
||||
|
||||
.tick > text {
|
||||
font-size: 14px;
|
||||
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) {
|
||||
|
@ -277,3 +289,9 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.prometheus-row {
|
||||
h5 {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -200,7 +200,6 @@
|
|||
right: 0;
|
||||
transition: width .3s;
|
||||
background: $gray-light;
|
||||
padding: 0 20px;
|
||||
z-index: 200;
|
||||
overflow: hidden;
|
||||
|
||||
|
@ -224,6 +223,10 @@
|
|||
}
|
||||
}
|
||||
|
||||
.issuable-sidebar {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.issuable-sidebar-header {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
|
|
@ -483,11 +483,12 @@ a.deploy-project-label {
|
|||
.project-stats {
|
||||
font-size: 0;
|
||||
text-align: center;
|
||||
max-width: 100%;
|
||||
border-bottom: 1px solid $border-color;
|
||||
|
||||
.nav {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
border-bottom: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.nav > li {
|
||||
|
|
|
@ -33,3 +33,20 @@
|
|||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.admin-runner-btn-group-cell {
|
||||
min-width: 150px;
|
||||
|
||||
.btn-sm {
|
||||
padding: 4px 9px;
|
||||
}
|
||||
|
||||
.btn-default {
|
||||
color: $gl-text-color-secondary;
|
||||
}
|
||||
|
||||
.fa-pause,
|
||||
.fa-play {
|
||||
font-size: 11px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
params[:application_setting][:disabled_oauth_sign_in_sources] =
|
||||
AuthHelper.button_based_providers.map(&:to_s) -
|
||||
Array(enabled_oauth_sign_in_sources)
|
||||
|
||||
params[:application_setting][:restricted_visibility_levels]&.delete("")
|
||||
params.delete(:domain_blacklist_raw) if params[:domain_blacklist_file]
|
||||
|
||||
params.require(:application_setting).permit(
|
||||
|
|
|
@ -40,14 +40,14 @@ class Admin::ProjectsController < Admin::ApplicationController
|
|||
::Projects::TransferService.new(@project, current_user, params.dup).execute(namespace)
|
||||
|
||||
@project.reload
|
||||
redirect_to admin_namespace_project_path(@project.namespace, @project)
|
||||
redirect_to admin_project_path(@project)
|
||||
end
|
||||
|
||||
def repository_check
|
||||
RepositoryCheck::SingleRepositoryWorker.perform_async(@project.id)
|
||||
|
||||
redirect_to(
|
||||
admin_namespace_project_path(@project.namespace, @project),
|
||||
admin_project_path(@project),
|
||||
notice: 'Repository check was triggered.'
|
||||
)
|
||||
end
|
||||
|
|
|
@ -110,6 +110,8 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def log_exception(exception)
|
||||
Raven.capture_exception(exception) if sentry_enabled?
|
||||
|
||||
application_trace = ActionDispatch::ExceptionWrapper.new(env, exception).application_trace
|
||||
application_trace.map!{ |t| " #{t}\n" }
|
||||
logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
|
||||
|
|
|
@ -78,8 +78,7 @@ module CreatesCommit
|
|||
end
|
||||
|
||||
def new_merge_request_path
|
||||
namespace_project_new_merge_request_path(
|
||||
@project_to_commit_into.namespace,
|
||||
project_new_merge_request_path(
|
||||
@project_to_commit_into,
|
||||
merge_request: {
|
||||
source_project_id: @project_to_commit_into.id,
|
||||
|
@ -91,7 +90,7 @@ module CreatesCommit
|
|||
end
|
||||
|
||||
def existing_merge_request_path
|
||||
namespace_project_merge_request_path(@project.namespace, @project, @merge_request)
|
||||
project_merge_request_path(@project, @merge_request)
|
||||
end
|
||||
|
||||
def merge_request_exists?
|
||||
|
|
|
@ -45,7 +45,7 @@ module MilestoneActions
|
|||
|
||||
def milestone_redirect_path
|
||||
if @project
|
||||
namespace_project_milestone_path(@project.namespace, @project, @milestone)
|
||||
project_milestone_path(@project, @milestone)
|
||||
elsif @group
|
||||
group_milestone_path(@group, @milestone.safe_title, title: @milestone.title)
|
||||
else
|
||||
|
|
|
@ -2,6 +2,6 @@ module RepositorySettingsRedirect
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
def redirect_to_repository_settings(project)
|
||||
redirect_to namespace_project_settings_repository_path(project.namespace, project)
|
||||
redirect_to project_settings_repository_path(project)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,9 +9,9 @@ module SpammableActions
|
|||
|
||||
def mark_as_spam
|
||||
if SpamService.new(spammable).mark_as_spam!
|
||||
redirect_to spammable, notice: "#{spammable.spammable_entity_type.titlecase} was submitted to Akismet successfully."
|
||||
redirect_to spammable_path, notice: "#{spammable.spammable_entity_type.titlecase} was submitted to Akismet successfully."
|
||||
else
|
||||
redirect_to spammable, alert: 'Error with Akismet. Please check the logs for more info.'
|
||||
redirect_to spammable_path, alert: 'Error with Akismet. Please check the logs for more info.'
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -25,7 +25,7 @@ module SpammableActions
|
|||
|
||||
def recaptcha_check_with_fallback(&fallback)
|
||||
if spammable.valid?
|
||||
redirect_to spammable
|
||||
redirect_to spammable_path
|
||||
elsif render_recaptcha?
|
||||
ensure_spam_config_loaded!
|
||||
|
||||
|
@ -56,6 +56,10 @@ module SpammableActions
|
|||
raise NotImplementedError, "#{self.class} does not implement #{__method__}"
|
||||
end
|
||||
|
||||
def spammable_path
|
||||
raise NotImplementedError, "#{self.class} does not implement #{__method__}"
|
||||
end
|
||||
|
||||
def authorize_submit_spammable!
|
||||
access_denied! unless current_user.admin?
|
||||
end
|
||||
|
|
|
@ -11,6 +11,9 @@ class Groups::MilestonesController < Groups::ApplicationController
|
|||
@milestone_states = GlobalMilestone.states_count(@projects)
|
||||
@milestones = Kaminari.paginate_array(milestones).page(params[:page])
|
||||
end
|
||||
format.json do
|
||||
render json: milestones.map { |m| m.for_display.slice(:title, :name) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ class InvitesController < ApplicationController
|
|||
when Project
|
||||
project = member.source
|
||||
label = "project #{project.name_with_namespace}"
|
||||
path = namespace_project_path(project.namespace, project)
|
||||
path = project_path(project)
|
||||
when Group
|
||||
group = member.source
|
||||
label = "group #{group.name}"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||
include AuthenticatesWithTwoFactor
|
||||
include Devise::Controllers::Rememberable
|
||||
|
||||
protect_from_forgery except: [:kerberos, :saml, :cas3]
|
||||
|
||||
|
@ -115,8 +116,10 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||
if @user.persisted? && @user.valid?
|
||||
log_audit_event(@user, with: oauth['provider'])
|
||||
if @user.two_factor_enabled?
|
||||
params[:remember_me] = '1' if remember_me?
|
||||
prompt_for_two_factor(@user)
|
||||
else
|
||||
remember_me(@user) if remember_me?
|
||||
sign_in_and_redirect(@user)
|
||||
end
|
||||
else
|
||||
|
@ -147,4 +150,9 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
|||
AuditEventService.new(user, user, options)
|
||||
.for_authentication.security_event
|
||||
end
|
||||
|
||||
def remember_me?
|
||||
request_params = request.env['omniauth.params']
|
||||
(request_params['remember_me'] == '1') if request_params.present?
|
||||
end
|
||||
end
|
||||
|
|
|
@ -76,13 +76,13 @@ class Projects::ApplicationController < ApplicationController
|
|||
def require_non_empty_project
|
||||
# Be sure to return status code 303 to avoid a double DELETE:
|
||||
# http://api.rubyonrails.org/classes/ActionController/Redirecting.html
|
||||
redirect_to namespace_project_path(@project.namespace, @project), status: 303 if @project.empty_repo?
|
||||
redirect_to project_path(@project), status: 303 if @project.empty_repo?
|
||||
end
|
||||
|
||||
def require_branch_head
|
||||
unless @repository.branch_exists?(@ref)
|
||||
redirect_to(
|
||||
namespace_project_tree_path(@project.namespace, @project, @ref),
|
||||
project_tree_path(@project, @ref),
|
||||
notice: "This action is not allowed unless you are on a branch"
|
||||
)
|
||||
end
|
||||
|
|
|
@ -46,7 +46,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
|
|||
|
||||
def keep
|
||||
build.keep_artifacts!
|
||||
redirect_to namespace_project_job_path(project.namespace, project, build)
|
||||
redirect_to project_job_path(project, build)
|
||||
end
|
||||
|
||||
def latest_succeeded
|
||||
|
|
|
@ -27,9 +27,9 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
|
||||
def create
|
||||
create_commit(Files::CreateService, success_notice: "The file has been successfully created.",
|
||||
success_path: -> { namespace_project_blob_path(@project.namespace, @project, File.join(@branch_name, @file_path)) },
|
||||
success_path: -> { project_blob_path(@project, File.join(@branch_name, @file_path)) },
|
||||
failure_view: :new,
|
||||
failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref))
|
||||
failure_path: project_new_blob_path(@project, @ref))
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -63,7 +63,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
@path = params[:file_path] if params[:file_path].present?
|
||||
create_commit(Files::UpdateService, success_path: -> { after_edit_path },
|
||||
failure_view: :edit,
|
||||
failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
|
||||
failure_path: project_blob_path(@project, @id))
|
||||
|
||||
rescue Files::UpdateService::FileChangedError
|
||||
@conflict = true
|
||||
|
@ -83,9 +83,9 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
|
||||
def destroy
|
||||
create_commit(Files::DeleteService, success_notice: "The file has been successfully deleted.",
|
||||
success_path: -> { namespace_project_tree_path(@project.namespace, @project, @branch_name) },
|
||||
success_path: -> { project_tree_path(@project, @branch_name) },
|
||||
failure_view: :show,
|
||||
failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
|
||||
failure_path: project_blob_path(@project, @id))
|
||||
end
|
||||
|
||||
def diff
|
||||
|
@ -118,7 +118,7 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
else
|
||||
if tree = @repository.tree(@commit.id, @path)
|
||||
if tree.entries.any?
|
||||
return redirect_to namespace_project_tree_path(@project.namespace, @project, File.join(@ref, @path))
|
||||
return redirect_to project_tree_path(@project, File.join(@ref, @path))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -143,10 +143,10 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
def after_edit_path
|
||||
from_merge_request = MergeRequestsFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:from_merge_request_iid])
|
||||
if from_merge_request && @branch_name == @ref
|
||||
diffs_namespace_project_merge_request_path(from_merge_request.target_project.namespace, from_merge_request.target_project, from_merge_request) +
|
||||
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
|
||||
"##{hexdigest(@path)}"
|
||||
else
|
||||
namespace_project_blob_path(@project.namespace, @project, File.join(@branch_name, @path))
|
||||
project_blob_path(@project, File.join(@branch_name, @path))
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
redirect_to url_to_autodeploy_setup(project, branch_name),
|
||||
notice: view_context.autodeploy_flash_notice(branch_name)
|
||||
else
|
||||
redirect_to namespace_project_tree_path(@project.namespace, @project, branch_name)
|
||||
redirect_to project_tree_path(@project, branch_name)
|
||||
end
|
||||
else
|
||||
@error = result[:message]
|
||||
|
@ -62,7 +62,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
|
||||
format.json do
|
||||
if result[:status] == :success
|
||||
render json: { name: branch_name, url: namespace_project_tree_url(@project.namespace, @project, branch_name) }
|
||||
render json: { name: branch_name, url: project_tree_url(@project, branch_name) }
|
||||
else
|
||||
render json: result[:messsage], status: :unprocessable_entity
|
||||
end
|
||||
|
@ -79,7 +79,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
flash_type = result[:status] == :error ? :alert : :notice
|
||||
flash[flash_type] = result[:message]
|
||||
|
||||
redirect_to namespace_project_branches_path(@project.namespace, @project), status: 303
|
||||
redirect_to project_branches_path(@project), status: 303
|
||||
end
|
||||
|
||||
format.js { render nothing: true, status: result[:return_code] }
|
||||
|
@ -90,7 +90,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
def destroy_all_merged
|
||||
DeleteMergedBranchesService.new(@project, current_user).async_execute
|
||||
|
||||
redirect_to namespace_project_branches_path(@project.namespace, @project),
|
||||
redirect_to project_branches_path(@project),
|
||||
notice: 'Merged branches are being deleted. This can take some time depending on the number of branches. Please refresh the page to see changes.'
|
||||
end
|
||||
|
||||
|
@ -106,8 +106,7 @@ class Projects::BranchesController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def url_to_autodeploy_setup(project, branch_name)
|
||||
namespace_project_new_blob_path(
|
||||
project.namespace,
|
||||
project_new_blob_path(
|
||||
project,
|
||||
branch_name,
|
||||
file_name: '.gitlab-ci.yml',
|
||||
|
|
|
@ -7,23 +7,23 @@ class Projects::BuildArtifactsController < Projects::ApplicationController
|
|||
before_action :validate_artifacts!
|
||||
|
||||
def download
|
||||
redirect_to download_namespace_project_job_artifacts_path(project.namespace, project, job)
|
||||
redirect_to download_project_job_artifacts_path(project, job)
|
||||
end
|
||||
|
||||
def browse
|
||||
redirect_to browse_namespace_project_job_artifacts_path(project.namespace, project, job, path: params[:path])
|
||||
redirect_to browse_project_job_artifacts_path(project, job, path: params[:path])
|
||||
end
|
||||
|
||||
def file
|
||||
redirect_to file_namespace_project_job_artifacts_path(project.namespace, project, job, path: params[:path])
|
||||
redirect_to file_project_job_artifacts_path(project, job, path: params[:path])
|
||||
end
|
||||
|
||||
def raw
|
||||
redirect_to raw_namespace_project_job_artifacts_path(project.namespace, project, job, path: params[:path])
|
||||
redirect_to raw_project_job_artifacts_path(project, job, path: params[:path])
|
||||
end
|
||||
|
||||
def latest_succeeded
|
||||
redirect_to latest_succeeded_namespace_project_artifacts_path(project.namespace, project, job, ref_name_and_path: params[:ref_name_and_path], job: params[:job])
|
||||
redirect_to latest_succeeded_project_artifacts_path(project, job, ref_name_and_path: params[:ref_name_and_path], job: params[:job])
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -2,15 +2,15 @@ class Projects::BuildsController < Projects::ApplicationController
|
|||
before_action :authorize_read_build!
|
||||
|
||||
def index
|
||||
redirect_to namespace_project_jobs_path(project.namespace, project)
|
||||
redirect_to project_jobs_path(project)
|
||||
end
|
||||
|
||||
def show
|
||||
redirect_to namespace_project_job_path(project.namespace, project, job)
|
||||
redirect_to project_job_path(project, job)
|
||||
end
|
||||
|
||||
def raw
|
||||
redirect_to raw_namespace_project_job_path(project.namespace, project, job)
|
||||
redirect_to raw_project_job_path(project, job)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -80,16 +80,16 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def successful_change_path
|
||||
referenced_merge_request_url || namespace_project_commits_url(@project.namespace, @project, @branch_name)
|
||||
referenced_merge_request_url || project_commits_url(@project, @branch_name)
|
||||
end
|
||||
|
||||
def failed_change_path
|
||||
referenced_merge_request_url || namespace_project_commit_url(@project.namespace, @project, params[:id])
|
||||
referenced_merge_request_url || project_commit_url(@project, params[:id])
|
||||
end
|
||||
|
||||
def referenced_merge_request_url
|
||||
if merge_request = @commit.merged_merge_request(current_user)
|
||||
namespace_project_merge_request_url(merge_request.target_project.namespace, merge_request.target_project, merge_request)
|
||||
project_merge_request_url(merge_request.target_project, merge_request)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -31,9 +31,9 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
from: params[:from].presence,
|
||||
to: params[:to].presence
|
||||
}
|
||||
redirect_to namespace_project_compare_index_path(@project.namespace, @project, from_to_vars)
|
||||
redirect_to project_compare_index_path(@project, from_to_vars)
|
||||
else
|
||||
redirect_to namespace_project_compare_path(@project.namespace, @project,
|
||||
redirect_to project_compare_path(@project,
|
||||
params[:from], params[:to])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,8 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
|||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
Gitlab::PollingInterval.set_header(response, interval: 3_000)
|
||||
|
||||
render json: {
|
||||
environments: EnvironmentSerializer
|
||||
.new(project: @project, current_user: @current_user)
|
||||
|
@ -63,7 +65,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
|||
@environment = project.environments.create(environment_params)
|
||||
|
||||
if @environment.persisted?
|
||||
redirect_to namespace_project_environment_path(project.namespace, project, @environment)
|
||||
redirect_to project_environment_path(project, @environment)
|
||||
else
|
||||
render :new
|
||||
end
|
||||
|
@ -71,7 +73,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
|||
|
||||
def update
|
||||
if @environment.update(environment_params)
|
||||
redirect_to namespace_project_environment_path(project.namespace, project, @environment)
|
||||
redirect_to project_environment_path(project, @environment)
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
|
@ -86,7 +88,7 @@ class Projects::EnvironmentsController < Projects::ApplicationController
|
|||
if stop_action
|
||||
polymorphic_url([project.namespace.becomes(Namespace), project, stop_action])
|
||||
else
|
||||
namespace_project_environment_url(project.namespace, project, @environment)
|
||||
project_environment_url(project, @environment)
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
|
|
|
@ -44,12 +44,12 @@ class Projects::ForksController < Projects::ApplicationController
|
|||
|
||||
if @forked_project.saved? && @forked_project.forked?
|
||||
if @forked_project.import_in_progress?
|
||||
redirect_to namespace_project_import_path(@forked_project.namespace, @forked_project, continue: continue_params)
|
||||
redirect_to project_import_path(@forked_project, continue: continue_params)
|
||||
else
|
||||
if continue_params
|
||||
redirect_to continue_params[:to], notice: continue_params[:notice]
|
||||
else
|
||||
redirect_to namespace_project_path(@forked_project.namespace, @forked_project), notice: "The project '#{@forked_project.name}' was successfully forked."
|
||||
redirect_to project_path(@forked_project), notice: "The project '#{@forked_project.name}' was successfully forked."
|
||||
end
|
||||
end
|
||||
else
|
||||
|
|
|
@ -29,7 +29,7 @@ class Projects::GraphsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def ci
|
||||
redirect_to charts_namespace_project_pipelines_path(@project.namespace, @project)
|
||||
redirect_to charts_project_pipelines_path(@project)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -22,7 +22,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
|
|||
flash[:alert] = 'Please select a group.'
|
||||
end
|
||||
|
||||
redirect_to namespace_project_settings_members_path(project.namespace, project)
|
||||
redirect_to project_settings_members_path(project)
|
||||
end
|
||||
|
||||
def update
|
||||
|
@ -36,7 +36,7 @@ class Projects::GroupLinksController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to namespace_project_settings_members_path(project.namespace, project), status: 302
|
||||
redirect_to project_settings_members_path(project), status: 302
|
||||
end
|
||||
format.js { head :ok }
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ class Projects::HookLogsController < Projects::ApplicationController
|
|||
|
||||
set_hook_execution_notice(status, message)
|
||||
|
||||
redirect_to edit_namespace_project_hook_path(@project.namespace, @project, @hook)
|
||||
redirect_to edit_project_hook_path(@project, @hook)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -17,7 +17,7 @@ class Projects::HooksController < Projects::ApplicationController
|
|||
@hooks = @project.hooks.select(&:persisted?)
|
||||
flash[:alert] = @hook.errors.full_messages.join.html_safe
|
||||
end
|
||||
redirect_to namespace_project_settings_integrations_path(@project.namespace, @project)
|
||||
redirect_to project_settings_integrations_path(@project)
|
||||
end
|
||||
|
||||
def edit
|
||||
|
@ -26,7 +26,7 @@ class Projects::HooksController < Projects::ApplicationController
|
|||
def update
|
||||
if hook.update_attributes(hook_params)
|
||||
flash[:notice] = 'Hook was successfully updated.'
|
||||
redirect_to namespace_project_settings_integrations_path(@project.namespace, @project)
|
||||
redirect_to project_settings_integrations_path(@project)
|
||||
else
|
||||
render 'edit'
|
||||
end
|
||||
|
@ -47,7 +47,7 @@ class Projects::HooksController < Projects::ApplicationController
|
|||
def destroy
|
||||
hook.destroy
|
||||
|
||||
redirect_to namespace_project_settings_integrations_path(@project.namespace, @project), status: 302
|
||||
redirect_to project_settings_integrations_path(@project), status: 302
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -17,7 +17,7 @@ class Projects::ImportsController < Projects::ApplicationController
|
|||
@project.reload.import_schedule
|
||||
end
|
||||
|
||||
redirect_to namespace_project_import_path(@project.namespace, @project)
|
||||
redirect_to project_import_path(@project)
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -25,10 +25,10 @@ class Projects::ImportsController < Projects::ApplicationController
|
|||
if continue_params
|
||||
redirect_to continue_params[:to], notice: continue_params[:notice]
|
||||
else
|
||||
redirect_to namespace_project_path(@project.namespace, @project), notice: finished_notice
|
||||
redirect_to project_path(@project), notice: finished_notice
|
||||
end
|
||||
elsif @project.import_failed?
|
||||
redirect_to new_namespace_project_import_path(@project.namespace, @project)
|
||||
redirect_to new_project_import_path(@project)
|
||||
else
|
||||
if continue_params && continue_params[:notice_now]
|
||||
flash.now[:notice] = continue_params[:notice_now]
|
||||
|
@ -50,19 +50,19 @@ class Projects::ImportsController < Projects::ApplicationController
|
|||
|
||||
def require_no_repo
|
||||
if @project.repository_exists?
|
||||
redirect_to namespace_project_path(@project.namespace, @project)
|
||||
redirect_to project_path(@project)
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_if_progress
|
||||
if @project.import_in_progress?
|
||||
redirect_to namespace_project_import_path(@project.namespace, @project)
|
||||
redirect_to project_import_path(@project)
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_if_no_import
|
||||
if @project.repository_exists? && @project.no_import?
|
||||
redirect_to namespace_project_path(@project.namespace, @project)
|
||||
redirect_to project_path(@project)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -227,7 +227,7 @@ 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!
|
||||
@noteable = @issue ||= @project.issues.find_by!(iid: params[:id])
|
||||
|
||||
return render_404 unless can?(current_user, :read_issue, @issue)
|
||||
|
||||
|
@ -238,6 +238,10 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
alias_method :awardable, :issue
|
||||
alias_method :spammable, :issue
|
||||
|
||||
def spammable_path
|
||||
project_issue_path(@project, @issue)
|
||||
end
|
||||
|
||||
def authorize_update_issue!
|
||||
return render_404 unless can?(current_user, :update_issue, @issue)
|
||||
end
|
||||
|
|
|
@ -38,7 +38,7 @@ class Projects::JobsController < Projects::ApplicationController
|
|||
build.cancel if can?(current_user, :update_build, build)
|
||||
end
|
||||
|
||||
redirect_to namespace_project_jobs_path(project.namespace, project)
|
||||
redirect_to project_jobs_path(project)
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -108,7 +108,7 @@ class Projects::JobsController < Projects::ApplicationController
|
|||
|
||||
def erase
|
||||
if @build.erase(erased_by: current_user)
|
||||
redirect_to namespace_project_job_path(project.namespace, project, @build),
|
||||
redirect_to project_job_path(project, @build),
|
||||
notice: "Build has been successfully erased!"
|
||||
else
|
||||
respond_422
|
||||
|
@ -137,6 +137,6 @@ class Projects::JobsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def build_path(build)
|
||||
namespace_project_job_path(build.project.namespace, build.project, build)
|
||||
project_job_path(build.project, build)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -33,7 +33,7 @@ class Projects::LabelsController < Projects::ApplicationController
|
|||
|
||||
if @label.valid?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to namespace_project_labels_path(@project.namespace, @project) }
|
||||
format.html { redirect_to project_labels_path(@project) }
|
||||
format.json { render json: @label }
|
||||
end
|
||||
else
|
||||
|
@ -51,7 +51,7 @@ class Projects::LabelsController < Projects::ApplicationController
|
|||
@label = Labels::UpdateService.new(label_params).execute(@label)
|
||||
|
||||
if @label.valid?
|
||||
redirect_to namespace_project_labels_path(@project.namespace, @project)
|
||||
redirect_to project_labels_path(@project)
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
|
@ -61,12 +61,11 @@ class Projects::LabelsController < Projects::ApplicationController
|
|||
Gitlab::IssuesLabels.generate(@project)
|
||||
|
||||
if params[:redirect] == 'issues'
|
||||
redirect_to namespace_project_issues_path(@project.namespace, @project)
|
||||
redirect_to project_issues_path(@project)
|
||||
elsif params[:redirect] == 'merge_requests'
|
||||
redirect_to namespace_project_merge_requests_path(@project.namespace,
|
||||
@project)
|
||||
redirect_to project_merge_requests_path(@project)
|
||||
else
|
||||
redirect_to namespace_project_labels_path(@project.namespace, @project)
|
||||
redirect_to project_labels_path(@project)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -74,7 +73,7 @@ class Projects::LabelsController < Projects::ApplicationController
|
|||
@label.destroy
|
||||
@labels = find_labels
|
||||
|
||||
redirect_to namespace_project_labels_path(@project.namespace, @project),
|
||||
redirect_to project_labels_path(@project),
|
||||
status: 302,
|
||||
notice: 'Label was removed'
|
||||
end
|
||||
|
@ -114,7 +113,7 @@ class Projects::LabelsController < Projects::ApplicationController
|
|||
return render_404 unless promote_service.execute(@label)
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to(namespace_project_labels_path(@project.namespace, @project),
|
||||
redirect_to(project_labels_path(@project),
|
||||
notice: 'Label was promoted to a Group Label')
|
||||
end
|
||||
format.js
|
||||
|
@ -125,7 +124,7 @@ class Projects::LabelsController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to(namespace_project_labels_path(@project.namespace, @project),
|
||||
redirect_to(project_labels_path(@project),
|
||||
notice: 'Failed to promote label due to internal error. Please contact administrators.')
|
||||
end
|
||||
format.js
|
||||
|
|
|
@ -16,12 +16,10 @@ class Projects::MattermostsController < Projects::ApplicationController
|
|||
|
||||
if result
|
||||
flash[:notice] = 'This service is now configured'
|
||||
redirect_to edit_namespace_project_service_path(
|
||||
@project.namespace, @project, service)
|
||||
redirect_to edit_project_service_path(@project, service)
|
||||
else
|
||||
flash[:alert] = message || 'Failed to configure service'
|
||||
redirect_to new_namespace_project_mattermost_path(
|
||||
@project.namespace, @project)
|
||||
redirect_to new_project_mattermost_path(@project)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ class Projects::MergeRequests::ConflictsController < Projects::MergeRequests::Ap
|
|||
|
||||
flash[:notice] = 'All merge conflicts were resolved. The merge request can now be merged.'
|
||||
|
||||
render json: { redirect_to: namespace_project_merge_request_url(@project.namespace, @project, @merge_request, resolved_conflicts: true) }
|
||||
render json: { redirect_to: project_merge_request_url(@project, @merge_request, resolved_conflicts: true) }
|
||||
rescue Gitlab::Conflict::ResolutionError => e
|
||||
render status: :bad_request, json: { message: e.message }
|
||||
end
|
||||
|
|
|
@ -211,21 +211,18 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
|
||||
stop_url =
|
||||
if environment.stop_action? && can?(current_user, :create_deployment, environment)
|
||||
stop_namespace_project_environment_path(project.namespace, project, environment)
|
||||
stop_project_environment_path(project, environment)
|
||||
end
|
||||
|
||||
metrics_url =
|
||||
if can?(current_user, :read_environment, environment) && environment.has_metrics?
|
||||
metrics_namespace_project_environment_deployment_path(environment.project.namespace,
|
||||
environment.project,
|
||||
environment,
|
||||
deployment)
|
||||
metrics_project_environment_deployment_path(environment.project, environment, deployment)
|
||||
end
|
||||
|
||||
{
|
||||
id: environment.id,
|
||||
name: environment.name,
|
||||
url: namespace_project_environment_path(project.namespace, project, environment),
|
||||
url: project_environment_path(project, environment),
|
||||
metrics_url: metrics_url,
|
||||
stop_url: stop_url,
|
||||
external_url: environment.external_url,
|
||||
|
|
|
@ -51,8 +51,7 @@ class Projects::MilestonesController < Projects::ApplicationController
|
|||
@milestone = Milestones::CreateService.new(project, current_user, milestone_params).execute
|
||||
|
||||
if @milestone.save
|
||||
redirect_to namespace_project_milestone_path(@project.namespace,
|
||||
@project, @milestone)
|
||||
redirect_to project_milestone_path(@project, @milestone)
|
||||
else
|
||||
render "new"
|
||||
end
|
||||
|
@ -65,8 +64,7 @@ class Projects::MilestonesController < Projects::ApplicationController
|
|||
format.js
|
||||
format.html do
|
||||
if @milestone.valid?
|
||||
redirect_to namespace_project_milestone_path(@project.namespace,
|
||||
@project, @milestone)
|
||||
redirect_to project_milestone_path(@project, @milestone)
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
|
|
|
@ -8,8 +8,8 @@ class Projects::NetworkController < Projects::ApplicationController
|
|||
before_action :assign_commit
|
||||
|
||||
def show
|
||||
@url = namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json))
|
||||
@commit_url = namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s")
|
||||
@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
|
||||
|
|
|
@ -15,7 +15,7 @@ class Projects::PagesController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to namespace_project_pages_path(@project.namespace, @project),
|
||||
redirect_to project_pages_path(@project),
|
||||
status: 302,
|
||||
notice: 'Pages were removed'
|
||||
end
|
||||
|
|
|
@ -16,7 +16,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController
|
|||
@domain = @project.pages_domains.create(pages_domain_params)
|
||||
|
||||
if @domain.valid?
|
||||
redirect_to namespace_project_pages_path(@project.namespace, @project)
|
||||
redirect_to project_pages_path(@project)
|
||||
else
|
||||
render 'new'
|
||||
end
|
||||
|
@ -27,7 +27,7 @@ class Projects::PagesDomainsController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to namespace_project_pages_path(@project.namespace, @project),
|
||||
redirect_to project_pages_path(@project),
|
||||
status: 302,
|
||||
notice: 'Domain was removed'
|
||||
end
|
||||
|
|
|
@ -34,7 +34,7 @@ class Projects::PipelineSchedulesController < Projects::ApplicationController
|
|||
|
||||
def update
|
||||
if schedule.update(schedule_params)
|
||||
redirect_to namespace_project_pipeline_schedules_path(@project.namespace.becomes(Namespace), @project)
|
||||
redirect_to project_pipeline_schedules_path(@project)
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
.execute(:web, ignore_skip_ci: true, save_on_errors: false)
|
||||
|
||||
if @pipeline.persisted?
|
||||
redirect_to namespace_project_pipeline_path(project.namespace, project, @pipeline)
|
||||
redirect_to project_pipeline_path(project, @pipeline)
|
||||
else
|
||||
render 'new'
|
||||
end
|
||||
|
@ -111,7 +111,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
|
||||
redirect_back_or_default default: project_pipelines_path(project)
|
||||
end
|
||||
|
||||
format.json { head :no_content }
|
||||
|
@ -123,7 +123,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
|
||||
redirect_back_or_default default: project_pipelines_path(project)
|
||||
end
|
||||
|
||||
format.json { head :no_content }
|
||||
|
|
|
@ -2,13 +2,13 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
|
|||
before_action :authorize_admin_pipeline!
|
||||
|
||||
def show
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project, params: params)
|
||||
redirect_to project_settings_ci_cd_path(@project, params: params)
|
||||
end
|
||||
|
||||
def update
|
||||
if @project.update_attributes(update_params)
|
||||
flash[:notice] = "Pipelines settings for '#{@project.name}' were successfully updated."
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
|
||||
redirect_to project_settings_ci_cd_path(@project)
|
||||
else
|
||||
render 'show'
|
||||
end
|
||||
|
@ -23,7 +23,7 @@ class Projects::PipelinesSettingsController < Projects::ApplicationController
|
|||
def update_params
|
||||
params.require(:project).permit(
|
||||
:runners_token, :builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
|
||||
:public_builds, :auto_cancel_pending_pipelines
|
||||
:public_builds, :auto_cancel_pending_pipelines, :ci_config_path
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -7,7 +7,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
|
||||
def index
|
||||
sort = params[:sort].presence || sort_value_name
|
||||
redirect_to namespace_project_settings_members_path(@project.namespace, @project, sort: sort)
|
||||
redirect_to project_settings_members_path(@project, sort: sort)
|
||||
end
|
||||
|
||||
def update
|
||||
|
@ -19,7 +19,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def resend_invite
|
||||
redirect_path = namespace_project_settings_members_path(@project.namespace, @project)
|
||||
redirect_path = project_settings_members_path(@project)
|
||||
|
||||
@project_member = @project.project_members.find(params[:id])
|
||||
|
||||
|
@ -42,7 +42,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
|||
return render_404
|
||||
end
|
||||
|
||||
redirect_to(namespace_project_settings_members_path(project.namespace, project),
|
||||
redirect_to(project_settings_members_path(project),
|
||||
notice: notice)
|
||||
end
|
||||
|
||||
|
|
|
@ -13,21 +13,21 @@ class Projects::RefsController < Projects::ApplicationController
|
|||
new_path =
|
||||
case params[:destination]
|
||||
when "tree"
|
||||
namespace_project_tree_path(@project.namespace, @project, @id)
|
||||
project_tree_path(@project, @id)
|
||||
when "blob"
|
||||
namespace_project_blob_path(@project.namespace, @project, @id)
|
||||
project_blob_path(@project, @id)
|
||||
when "graph"
|
||||
namespace_project_network_path(@project.namespace, @project, @id, @options)
|
||||
project_network_path(@project, @id, @options)
|
||||
when "graphs"
|
||||
namespace_project_graph_path(@project.namespace, @project, @id)
|
||||
project_graph_path(@project, @id)
|
||||
when "find_file"
|
||||
namespace_project_find_file_path(@project.namespace, @project, @id)
|
||||
project_find_file_path(@project, @id)
|
||||
when "graphs_commits"
|
||||
commits_namespace_project_graph_path(@project.namespace, @project, @id)
|
||||
commits_project_graph_path(@project, @id)
|
||||
when "badges"
|
||||
namespace_project_pipelines_settings_path(@project.namespace, @project, ref: @id)
|
||||
project_pipelines_settings_path(@project, ref: @id)
|
||||
else
|
||||
namespace_project_commits_path(@project.namespace, @project, @id)
|
||||
project_commits_path(@project, @id)
|
||||
end
|
||||
|
||||
redirect_to new_path
|
||||
|
@ -62,7 +62,7 @@ class Projects::RefsController < Projects::ApplicationController
|
|||
|
||||
offset = (@offset + @limit)
|
||||
if contents.size > offset
|
||||
@more_log_url = logs_file_namespace_project_ref_path(@project.namespace, @project, @ref, @path || '', offset: offset)
|
||||
@more_log_url = logs_file_project_ref_path(@project, @ref, @path || '', offset: offset)
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
|
|
|
@ -10,11 +10,11 @@ module Projects
|
|||
|
||||
def destroy
|
||||
if image.destroy
|
||||
redirect_to project_container_registry_path(@project),
|
||||
redirect_to project_container_registry_index_path(@project),
|
||||
status: 302,
|
||||
notice: 'Image repository has been removed successfully!'
|
||||
else
|
||||
redirect_to project_container_registry_path(@project),
|
||||
redirect_to project_container_registry_index_path(@project),
|
||||
status: 302,
|
||||
alert: 'Failed to remove image repository!'
|
||||
end
|
||||
|
|
|
@ -5,11 +5,11 @@ module Projects
|
|||
|
||||
def destroy
|
||||
if tag.delete
|
||||
redirect_to project_container_registry_path(@project),
|
||||
redirect_to project_container_registry_index_path(@project),
|
||||
status: 302,
|
||||
notice: 'Registry tag has been removed successfully!'
|
||||
else
|
||||
redirect_to project_container_registry_path(@project),
|
||||
redirect_to project_container_registry_index_path(@project),
|
||||
status: 302,
|
||||
alert: 'Failed to remove registry tag!'
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ class Projects::ReleasesController < Projects::ApplicationController
|
|||
release.destroy
|
||||
end
|
||||
|
||||
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
|
||||
redirect_to project_tag_path(@project, @tag.name)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -5,7 +5,7 @@ class Projects::RunnersController < Projects::ApplicationController
|
|||
layout 'project_settings'
|
||||
|
||||
def index
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
|
||||
redirect_to project_settings_ci_cd_path(@project)
|
||||
end
|
||||
|
||||
def edit
|
||||
|
@ -49,7 +49,7 @@ class Projects::RunnersController < Projects::ApplicationController
|
|||
def toggle_shared_runners
|
||||
project.toggle!(:shared_runners_enabled)
|
||||
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
|
||||
redirect_to project_settings_ci_cd_path(@project)
|
||||
end
|
||||
|
||||
protected
|
||||
|
|
|
@ -15,7 +15,7 @@ class Projects::ServicesController < Projects::ApplicationController
|
|||
|
||||
def update
|
||||
if @service.save(context: :manual_change)
|
||||
redirect_to(namespace_project_settings_integrations_path(@project.namespace, @project), notice: success_message)
|
||||
redirect_to(project_settings_integrations_path(@project), notice: success_message)
|
||||
else
|
||||
render 'edit'
|
||||
end
|
||||
|
|
|
@ -30,7 +30,7 @@ class Projects::SnippetsController < Projects::ApplicationController
|
|||
).execute
|
||||
@snippets = @snippets.page(params[:page])
|
||||
if @snippets.out_of_range? && @snippets.total_pages != 0
|
||||
redirect_to namespace_project_snippets_path(page: @snippets.total_pages)
|
||||
redirect_to project_snippets_path(@project, page: @snippets.total_pages)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -79,7 +79,7 @@ class Projects::SnippetsController < Projects::ApplicationController
|
|||
|
||||
@snippet.destroy
|
||||
|
||||
redirect_to namespace_project_snippets_path(@project.namespace, @project), status: 302
|
||||
redirect_to project_snippets_path(@project), status: 302
|
||||
end
|
||||
|
||||
protected
|
||||
|
@ -90,6 +90,10 @@ class Projects::SnippetsController < Projects::ApplicationController
|
|||
alias_method :awardable, :snippet
|
||||
alias_method :spammable, :snippet
|
||||
|
||||
def spammable_path
|
||||
project_snippet_path(@project, @snippet)
|
||||
end
|
||||
|
||||
def authorize_read_project_snippet!
|
||||
return render_404 unless can?(current_user, :read_project_snippet, @snippet)
|
||||
end
|
||||
|
|
|
@ -35,7 +35,7 @@ class Projects::TagsController < Projects::ApplicationController
|
|||
if result[:status] == :success
|
||||
@tag = result[:tag]
|
||||
|
||||
redirect_to namespace_project_tag_path(@project.namespace, @project, @tag.name)
|
||||
redirect_to project_tag_path(@project, @tag.name)
|
||||
else
|
||||
@error = result[:message]
|
||||
@message = params[:message]
|
||||
|
@ -50,7 +50,7 @@ class Projects::TagsController < Projects::ApplicationController
|
|||
respond_to do |format|
|
||||
if result[:status] == :success
|
||||
format.html do
|
||||
redirect_to namespace_project_tags_path(@project.namespace, @project), status: 303
|
||||
redirect_to project_tags_path(@project), status: 303
|
||||
end
|
||||
|
||||
format.js
|
||||
|
@ -58,7 +58,7 @@ class Projects::TagsController < Projects::ApplicationController
|
|||
@error = result[:message]
|
||||
|
||||
format.html do
|
||||
redirect_to namespace_project_tags_path(@project.namespace, @project),
|
||||
redirect_to project_tags_path(@project),
|
||||
alert: @error, status: 303
|
||||
end
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ class Projects::TreeController < Projects::ApplicationController
|
|||
if tree.entries.empty?
|
||||
if @repository.blob_at(@commit.id, @path)
|
||||
return redirect_to(
|
||||
namespace_project_blob_path(@project.namespace, @project,
|
||||
project_blob_path(@project,
|
||||
File.join(@ref, @path))
|
||||
)
|
||||
elsif @path.present?
|
||||
|
@ -37,8 +37,8 @@ class Projects::TreeController < Projects::ApplicationController
|
|||
return render_404 unless @commit_params.values.all?
|
||||
|
||||
create_commit(Files::CreateDirService, success_notice: "The directory has been successfully created.",
|
||||
success_path: namespace_project_tree_path(@project.namespace, @project, File.join(@branch_name, @dir_name)),
|
||||
failure_path: namespace_project_tree_path(@project.namespace, @project, @ref))
|
||||
success_path: project_tree_path(@project, File.join(@branch_name, @dir_name)),
|
||||
failure_path: project_tree_path(@project, @ref))
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -7,7 +7,7 @@ class Projects::TriggersController < Projects::ApplicationController
|
|||
layout 'project_settings'
|
||||
|
||||
def index
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
|
||||
redirect_to project_settings_ci_cd_path(@project)
|
||||
end
|
||||
|
||||
def create
|
||||
|
@ -19,7 +19,7 @@ class Projects::TriggersController < Projects::ApplicationController
|
|||
flash[:alert] = 'You could not create a new trigger.'
|
||||
end
|
||||
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
|
||||
redirect_to project_settings_ci_cd_path(@project)
|
||||
end
|
||||
|
||||
def take_ownership
|
||||
|
@ -29,7 +29,7 @@ class Projects::TriggersController < Projects::ApplicationController
|
|||
flash[:alert] = 'You could not take ownership of trigger.'
|
||||
end
|
||||
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
|
||||
redirect_to project_settings_ci_cd_path(@project)
|
||||
end
|
||||
|
||||
def edit
|
||||
|
@ -37,7 +37,7 @@ class Projects::TriggersController < Projects::ApplicationController
|
|||
|
||||
def update
|
||||
if trigger.update(trigger_params)
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project), notice: 'Trigger was successfully updated.'
|
||||
redirect_to project_settings_ci_cd_path(@project), notice: 'Trigger was successfully updated.'
|
||||
else
|
||||
render action: "edit"
|
||||
end
|
||||
|
@ -50,7 +50,7 @@ class Projects::TriggersController < Projects::ApplicationController
|
|||
flash[:alert] = "Could not remove the trigger."
|
||||
end
|
||||
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project), status: 302
|
||||
redirect_to project_settings_ci_cd_path(@project), status: 302
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -4,7 +4,7 @@ class Projects::VariablesController < Projects::ApplicationController
|
|||
layout 'project_settings'
|
||||
|
||||
def index
|
||||
redirect_to namespace_project_settings_ci_cd_path(@project.namespace, @project)
|
||||
redirect_to project_settings_ci_cd_path(@project)
|
||||
end
|
||||
|
||||
def show
|
||||
|
@ -14,19 +14,19 @@ class Projects::VariablesController < Projects::ApplicationController
|
|||
def update
|
||||
@variable = @project.variables.find(params[:id])
|
||||
|
||||
if @variable.update_attributes(project_params)
|
||||
redirect_to namespace_project_variables_path(project.namespace, project), notice: 'Variable was successfully updated.'
|
||||
if @variable.update_attributes(variable_params)
|
||||
redirect_to project_variables_path(project), notice: 'Variable was successfully updated.'
|
||||
else
|
||||
render action: "show"
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
@variable = Ci::Variable.new(project_params)
|
||||
@variable = @project.variables.new(variable_params)
|
||||
|
||||
if @variable.valid? && @project.variables << @variable
|
||||
if @variable.save
|
||||
flash[:notice] = 'Variables were successfully updated.'
|
||||
redirect_to namespace_project_settings_ci_cd_path(project.namespace, project)
|
||||
redirect_to project_settings_ci_cd_path(project)
|
||||
else
|
||||
render "show"
|
||||
end
|
||||
|
@ -36,15 +36,18 @@ class Projects::VariablesController < Projects::ApplicationController
|
|||
@key = @project.variables.find(params[:id])
|
||||
@key.destroy
|
||||
|
||||
redirect_to namespace_project_settings_ci_cd_path(project.namespace, project),
|
||||
redirect_to project_settings_ci_cd_path(project),
|
||||
status: 302,
|
||||
notice: 'Variable was successfully removed.'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def project_params
|
||||
params.require(:variable)
|
||||
.permit([:id, :key, :value, :protected, :_destroy])
|
||||
def variable_params
|
||||
params.require(:variable).permit(*variable_params_attributes)
|
||||
end
|
||||
|
||||
def variable_params_attributes
|
||||
%i[id key value protected _destroy]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,7 +49,7 @@ class Projects::WikisController < Projects::ApplicationController
|
|||
|
||||
if @page.valid?
|
||||
redirect_to(
|
||||
namespace_project_wiki_path(@project.namespace, @project, @page),
|
||||
project_wiki_path(@project, @page),
|
||||
notice: 'Wiki was successfully updated.'
|
||||
)
|
||||
else
|
||||
|
@ -62,7 +62,7 @@ class Projects::WikisController < Projects::ApplicationController
|
|||
|
||||
if @page.persisted?
|
||||
redirect_to(
|
||||
namespace_project_wiki_path(@project.namespace, @project, @page),
|
||||
project_wiki_path(@project, @page),
|
||||
notice: 'Wiki was successfully updated.'
|
||||
)
|
||||
else
|
||||
|
@ -75,7 +75,7 @@ class Projects::WikisController < Projects::ApplicationController
|
|||
|
||||
unless @page
|
||||
redirect_to(
|
||||
namespace_project_wiki_path(@project.namespace, @project, :home),
|
||||
project_wiki_path(@project, :home),
|
||||
notice: "Page not found"
|
||||
)
|
||||
end
|
||||
|
@ -85,7 +85,7 @@ class Projects::WikisController < Projects::ApplicationController
|
|||
@page = @project_wiki.find_page(params[:id])
|
||||
WikiPages::DestroyService.new(@project, current_user).execute(@page)
|
||||
|
||||
redirect_to namespace_project_wiki_path(@project.namespace, @project, :home),
|
||||
redirect_to project_wiki_path(@project, :home),
|
||||
status: 302,
|
||||
notice: "Page was successfully deleted"
|
||||
end
|
||||
|
|
|
@ -92,7 +92,7 @@ class ProjectsController < Projects::ApplicationController
|
|||
|
||||
def show
|
||||
if @project.import_in_progress?
|
||||
redirect_to namespace_project_import_path(@project.namespace, @project)
|
||||
redirect_to project_import_path(@project)
|
||||
return
|
||||
end
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ class SearchController < ApplicationController
|
|||
query = params[:search].strip.downcase
|
||||
found_by_commit_sha = Commit.valid_hash?(query) && only_commit.sha.start_with?(query)
|
||||
|
||||
redirect_to namespace_project_commit_path(@project.namespace, @project, only_commit) if found_by_commit_sha
|
||||
redirect_to project_commit_path(@project, only_commit) if found_by_commit_sha
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -107,6 +107,10 @@ class SnippetsController < ApplicationController
|
|||
alias_method :awardable, :snippet
|
||||
alias_method :spammable, :snippet
|
||||
|
||||
def spammable_path
|
||||
snippet_path(@snippet)
|
||||
end
|
||||
|
||||
def authorize_read_snippet!
|
||||
return if can?(current_user, :read_personal_snippet, @snippet)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue