Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-03-16 18:11:53 +00:00
parent dad48b4af2
commit 889bf7a0ee
200 changed files with 77429 additions and 27765 deletions

View File

@ -183,6 +183,7 @@ setup-test-env:
- tmp/tests/gitlab-workhorse/gitlab-workhorse
- tmp/tests/gitlab-workhorse/gitlab-resize-image
- tmp/tests/gitlab-workhorse/config.toml
- tmp/tests/gitlab-workhorse/WORKHORSE_TREE
- tmp/tests/repositories/
- tmp/tests/second_storage/
when: always

View File

@ -293,7 +293,7 @@ gem 'autoprefixer-rails', '10.2.0.0'
gem 'terser', '1.0.2'
gem 'addressable', '~> 2.7'
gem 'gemojione', '~> 3.3'
gem 'gemojione', '~> 4.3.3'
gem 'gon', '~> 6.2'
gem 'request_store', '~> 1.5'
gem 'base32', '~> 0.3.0'

View File

@ -412,7 +412,7 @@ GEM
ruby-progressbar (~> 1.4)
fuzzyurl (0.9.0)
gemoji (3.0.1)
gemojione (3.3.0)
gemojione (4.3.3)
json
get_process_mem (0.2.5)
ffi (~> 1.0)
@ -1414,7 +1414,7 @@ DEPENDENCIES
fog-rackspace (~> 0.1.1)
fugit (~> 1.2.1)
fuubar (~> 2.2.0)
gemojione (~> 3.3)
gemojione (~> 4.3.3)
gettext (~> 3.3)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.3)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 MiB

After

Width:  |  Height:  |  Size: 5.4 MiB

View File

@ -43,7 +43,7 @@ export default class EditBlob {
blobPath: fileNameEl.value,
blobContent: editorEl.innerText,
});
this.editor.use(new FileTemplateExtension());
this.editor.use(new FileTemplateExtension({ instance: this.editor }));
fileNameEl.addEventListener('change', () => {
this.editor.updateModelLanguage(fileNameEl.value);

View File

@ -1,11 +1,85 @@
import { ERROR_INSTANCE_REQUIRED_FOR_EXTENSION } from '../constants';
import { Range } from 'monaco-editor';
import { ERROR_INSTANCE_REQUIRED_FOR_EXTENSION, EDITOR_TYPE_CODE } from '../constants';
const hashRegexp = new RegExp('#?L', 'g');
const createAnchor = (href) => {
const fragment = new DocumentFragment();
const el = document.createElement('a');
el.classList.add('link-anchor');
el.href = href;
fragment.appendChild(el);
el.addEventListener('contextmenu', (e) => {
e.stopPropagation();
});
return fragment;
};
export class EditorLiteExtension {
constructor({ instance, ...options } = {}) {
if (instance) {
Object.assign(instance, options);
EditorLiteExtension.highlightLines(instance);
if (instance.getEditorType && instance.getEditorType() === EDITOR_TYPE_CODE) {
EditorLiteExtension.setupLineLinking(instance);
}
} else if (Object.entries(options).length) {
throw new Error(ERROR_INSTANCE_REQUIRED_FOR_EXTENSION);
}
}
static highlightLines(instance) {
const { hash } = window.location;
if (!hash) {
return;
}
const [start, end] = hash.replace(hashRegexp, '').split('-');
let startLine = start ? parseInt(start, 10) : null;
let endLine = end ? parseInt(end, 10) : startLine;
if (endLine < startLine) {
[startLine, endLine] = [endLine, startLine];
}
if (startLine) {
window.requestAnimationFrame(() => {
instance.revealLineInCenter(startLine);
Object.assign(instance, {
lineDecorations: instance.deltaDecorations(
[],
[
{
range: new Range(startLine, 1, endLine, 1),
options: { isWholeLine: true, className: 'active-line-text' },
},
],
),
});
});
}
}
static onMouseMoveHandler(e) {
const target = e.target.element;
if (target.classList.contains('line-numbers')) {
const lineNum = e.target.position.lineNumber;
const hrefAttr = `#L${lineNum}`;
let el = target.querySelector('a');
if (!el) {
el = createAnchor(hrefAttr);
target.appendChild(el);
}
}
}
static setupLineLinking(instance) {
instance.onMouseMove(EditorLiteExtension.onMouseMoveHandler);
instance.onMouseDown((e) => {
const isCorrectAnchor = e.target.element.classList.contains('link-anchor');
if (!isCorrectAnchor) {
return;
}
if (instance.lineDecorations) {
instance.deltaDecorations(instance.lineDecorations, []);
}
});
}
}

View File

@ -3,10 +3,10 @@ export const FREQUENTLY_USED_COOKIE_KEY = 'frequently_used_emojis';
export const CATEGORY_ICON_MAP = {
[FREQUENTLY_USED_KEY]: 'history',
activity: 'dumbbell',
people: 'smiley',
nature: 'nature',
food: 'food',
activity: 'dumbbell',
travel: 'car',
objects: 'object',
symbols: 'heart',

View File

@ -8,7 +8,7 @@ let emojiMap = null;
let validEmojiNames = null;
export const FALLBACK_EMOJI_KEY = 'grey_question';
export const EMOJI_VERSION = '1';
export const EMOJI_VERSION = '2';
const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();

View File

@ -1,6 +1,6 @@
import AccessorUtilities from '../../lib/utils/accessor';
const GL_EMOJI_VERSION = '0.2.0';
const GL_EMOJI_VERSION = '0.3.0';
const unicodeSupportTestMap = {
// man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/
@ -25,6 +25,8 @@ const unicodeSupportTestMap = {
// angel_tone5
'\u{1F47C}\u{1F3FF}',
],
// star_struck, http://emojipedia.org/unicode-9.0/
'10.0': '\u{1F929}',
// rofl, http://emojipedia.org/unicode-9.0/
'9.0': '\u{1F923}',
// metal, http://emojipedia.org/unicode-8.0/

View File

@ -61,7 +61,9 @@ export default {
<template>
<section id="grafana" class="settings no-animate js-grafana-integration">
<div class="settings-header">
<h4 class="js-section-header">
<h4
class="js-section-header settings-title js-settings-toggle js-settings-toggle-trigger-only"
>
{{ s__('GrafanaIntegration|Grafana authentication') }}
</h4>
<gl-button class="js-settings-toggle">{{ __('Expand') }}</gl-button>

View File

@ -7,6 +7,7 @@ export const defaultEditorOptions = {
enabled: false,
},
wordWrap: 'on',
glyphMargin: true,
};
export const defaultDiffOptions = {
@ -21,6 +22,7 @@ export const defaultDiffEditorOptions = {
readOnly: false,
renderLineHighlight: 'none',
hideCursorInOverviewRuler: true,
glyphMargin: true,
};
export const defaultModelOptions = {

View File

@ -44,13 +44,14 @@ export default {
</script>
<template>
<div class="dropdown">
<div class="js-pipeline-info">
<div class="js-pipeline-info" data-testid="pipeline-info">
<ci-icon :status="pipeline.details.status" class="vertical-align-middle" />
<span class="font-weight-bold">{{ s__('Job|Pipeline') }}</span>
<gl-link
:href="pipeline.path"
class="js-pipeline-path link-commit"
data-testid="pipeline-path"
data-qa-selector="pipeline_path"
>#{{ pipeline.id }}</gl-link
>
@ -58,13 +59,17 @@ export default {
{{ s__('Job|for') }}
<template v-if="isTriggeredByMergeRequest">
<gl-link :href="pipeline.merge_request.path" class="link-commit ref-name js-mr-link"
<gl-link
:href="pipeline.merge_request.path"
class="link-commit ref-name"
data-testid="mr-link"
>!{{ pipeline.merge_request.iid }}</gl-link
>
{{ s__('Job|with') }}
<gl-link
:href="pipeline.merge_request.source_branch_path"
class="link-commit ref-name js-source-branch-link"
class="link-commit ref-name"
data-testid="source-branch-link"
>{{ pipeline.merge_request.source_branch }}</gl-link
>
@ -72,7 +77,8 @@ export default {
{{ s__('Job|into') }}
<gl-link
:href="pipeline.merge_request.target_branch_path"
class="link-commit ref-name js-target-branch-link"
class="link-commit ref-name"
data-testid="target-branch-link"
>{{ pipeline.merge_request.target_branch }}</gl-link
>
</template>

View File

@ -2,9 +2,9 @@ import initFilePickers from '~/file_pickers';
import BindInOut from '../../../../behaviors/bind_in_out';
import Group from '../../../../group';
document.addEventListener('DOMContentLoaded', () => {
(() => {
BindInOut.initAll();
initFilePickers();
return new Group();
});
})();

View File

@ -1,3 +1,3 @@
import Labels from '../../../../labels';
document.addEventListener('DOMContentLoaded', () => new Labels());
new Labels(); // eslint-disable-line no-new

View File

@ -1,3 +1,3 @@
import Labels from '../../../../labels';
document.addEventListener('DOMContentLoaded', () => new Labels());
new Labels(); // eslint-disable-line no-new

View File

@ -4,7 +4,6 @@ import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
import { FILTERED_SEARCH } from '~/pages/constants';
import initFilteredSearch from '~/pages/search/init_filtered_search';
import { initInstallRunner } from '~/pages/shared/mount_runner_instructions';
import initSearchSettings from '~/search_settings';
import initSettingsPanels from '~/settings_panels';
// Initialize expandable settings panels
@ -21,5 +20,3 @@ initSharedRunnersForm();
initVariableList();
initInstallRunner();
initSearchSettings();

View File

@ -0,0 +1,3 @@
import initSearchSettings from '~/search_settings';
initSearchSettings();

View File

@ -1,6 +1,3 @@
import bundle from '~/packages_and_registries/settings/group/bundle';
import initSearchSettings from '~/search_settings';
bundle();
document.addEventListener('DOMContentLoaded', initSearchSettings);

View File

@ -1,10 +1,7 @@
import DueDateSelectors from '~/due_date_select';
import initSearchSettings from '~/search_settings';
import initSettingsPanels from '~/settings_panels';
// Initialize expandable settings panels
initSettingsPanels();
new DueDateSelectors(); // eslint-disable-line no-new
initSearchSettings();

View File

@ -7,81 +7,78 @@ import { __ } from '~/locale';
import EmojiMenu from './emoji_menu';
const defaultStatusEmoji = 'speech_balloon';
const toggleEmojiMenuButtonSelector = '.js-toggle-emoji-menu';
const toggleEmojiMenuButton = document.querySelector(toggleEmojiMenuButtonSelector);
const statusEmojiField = document.getElementById('js-status-emoji-field');
const statusMessageField = document.getElementById('js-status-message-field');
document.addEventListener('DOMContentLoaded', () => {
const toggleEmojiMenuButtonSelector = '.js-toggle-emoji-menu';
const toggleEmojiMenuButton = document.querySelector(toggleEmojiMenuButtonSelector);
const statusEmojiField = document.getElementById('js-status-emoji-field');
const statusMessageField = document.getElementById('js-status-message-field');
const toggleNoEmojiPlaceholder = (isVisible) => {
const placeholderElement = document.getElementById('js-no-emoji-placeholder');
placeholderElement.classList.toggle('hidden', !isVisible);
};
const toggleNoEmojiPlaceholder = (isVisible) => {
const placeholderElement = document.getElementById('js-no-emoji-placeholder');
placeholderElement.classList.toggle('hidden', !isVisible);
};
const findStatusEmoji = () => toggleEmojiMenuButton.querySelector('gl-emoji');
const removeStatusEmoji = () => {
const statusEmoji = findStatusEmoji();
if (statusEmoji) {
statusEmoji.remove();
}
};
const findStatusEmoji = () => toggleEmojiMenuButton.querySelector('gl-emoji');
const removeStatusEmoji = () => {
const statusEmoji = findStatusEmoji();
if (statusEmoji) {
statusEmoji.remove();
}
};
const selectEmojiCallback = (emoji, emojiTag) => {
statusEmojiField.value = emoji;
toggleNoEmojiPlaceholder(false);
removeStatusEmoji();
toggleEmojiMenuButton.innerHTML += emojiTag;
};
const selectEmojiCallback = (emoji, emojiTag) => {
statusEmojiField.value = emoji;
toggleNoEmojiPlaceholder(false);
removeStatusEmoji();
toggleEmojiMenuButton.innerHTML += emojiTag;
};
const clearEmojiButton = document.getElementById('js-clear-user-status-button');
clearEmojiButton.addEventListener('click', () => {
statusEmojiField.value = '';
statusMessageField.value = '';
removeStatusEmoji();
toggleNoEmojiPlaceholder(true);
});
const emojiAutocomplete = new GfmAutoComplete();
emojiAutocomplete.setup($(statusMessageField), { emojis: true });
const userNameInput = document.getElementById('user_name');
userNameInput.addEventListener('input', () => {
const EMOJI_REGEX = emojiRegex();
if (EMOJI_REGEX.test(userNameInput.value)) {
// set field to invalid so it gets detected by GlFieldErrors
userNameInput.setCustomValidity(__('Invalid field'));
} else {
userNameInput.setCustomValidity('');
}
});
Emoji.initEmojiMap()
.then(() => {
const emojiMenu = new EmojiMenu(
Emoji,
toggleEmojiMenuButtonSelector,
'js-status-emoji-menu',
selectEmojiCallback,
);
emojiMenu.bindEvents();
const defaultEmojiTag = Emoji.glEmojiTag(defaultStatusEmoji);
statusMessageField.addEventListener('input', () => {
const hasStatusMessage = statusMessageField.value.trim() !== '';
const statusEmoji = findStatusEmoji();
if (hasStatusMessage && statusEmoji) {
return;
}
if (hasStatusMessage) {
toggleNoEmojiPlaceholder(false);
toggleEmojiMenuButton.innerHTML += defaultEmojiTag;
} else if (statusEmoji.dataset.name === defaultStatusEmoji) {
toggleNoEmojiPlaceholder(true);
removeStatusEmoji();
}
});
})
.catch(() => createFlash(__('Failed to load emoji list.')));
const clearEmojiButton = document.getElementById('js-clear-user-status-button');
clearEmojiButton.addEventListener('click', () => {
statusEmojiField.value = '';
statusMessageField.value = '';
removeStatusEmoji();
toggleNoEmojiPlaceholder(true);
});
const emojiAutocomplete = new GfmAutoComplete();
emojiAutocomplete.setup($(statusMessageField), { emojis: true });
const userNameInput = document.getElementById('user_name');
userNameInput.addEventListener('input', () => {
const EMOJI_REGEX = emojiRegex();
if (EMOJI_REGEX.test(userNameInput.value)) {
// set field to invalid so it gets detected by GlFieldErrors
userNameInput.setCustomValidity(__('Invalid field'));
} else {
userNameInput.setCustomValidity('');
}
});
Emoji.initEmojiMap()
.then(() => {
const emojiMenu = new EmojiMenu(
Emoji,
toggleEmojiMenuButtonSelector,
'js-status-emoji-menu',
selectEmojiCallback,
);
emojiMenu.bindEvents();
const defaultEmojiTag = Emoji.glEmojiTag(defaultStatusEmoji);
statusMessageField.addEventListener('input', () => {
const hasStatusMessage = statusMessageField.value.trim() !== '';
const statusEmoji = findStatusEmoji();
if (hasStatusMessage && statusEmoji) {
return;
}
if (hasStatusMessage) {
toggleNoEmojiPlaceholder(false);
toggleEmojiMenuButton.innerHTML += defaultEmojiTag;
} else if (statusEmoji.dataset.name === defaultStatusEmoji) {
toggleNoEmojiPlaceholder(true);
removeStatusEmoji();
}
});
})
.catch(() => createFlash(__('Failed to load emoji list.')));

View File

@ -0,0 +1,3 @@
import initSearchSettings from '~/search_settings';
initSearchSettings();

View File

@ -0,0 +1,3 @@
import initSearchSettings from '~/search_settings';
initSearchSettings();

View File

@ -6,7 +6,6 @@ import initDeployFreeze from '~/deploy_freeze';
import { initInstallRunner } from '~/pages/shared/mount_runner_instructions';
import initSharedRunnersToggle from '~/projects/settings/mount_shared_runners_toggle';
import registrySettingsApp from '~/registry/settings/registry_settings_bundle';
import initSearchSettings from '~/search_settings';
import initSettingsPanels from '~/settings_panels';
document.addEventListener('DOMContentLoaded', () => {
@ -43,6 +42,4 @@ document.addEventListener('DOMContentLoaded', () => {
}
initInstallRunner();
initSearchSettings();
});

View File

@ -0,0 +1,3 @@
import initSearchSettings from '~/search_settings';
initSearchSettings();

View File

@ -3,7 +3,6 @@ import mountErrorTrackingForm from '~/error_tracking_settings';
import mountGrafanaIntegration from '~/grafana_integration';
import initIncidentsSettings from '~/incidents_settings';
import mountOperationSettings from '~/operation_settings';
import initSearchSettings from '~/search_settings';
import initSettingsPanels from '~/settings_panels';
initIncidentsSettings();
@ -14,7 +13,3 @@ if (!IS_EE) {
initSettingsPanels();
}
mountAlertsSettings(document.querySelector('.js-alerts-settings'));
document.addEventListener('DOMContentLoaded', () => {
initSearchSettings();
});

View File

@ -1,5 +1,4 @@
import MirrorRepos from '~/mirrors/mirror_repos';
import initSearchSettings from '~/search_settings';
import initForm from '../form';
document.addEventListener('DOMContentLoaded', () => {
@ -7,6 +6,4 @@ document.addEventListener('DOMContentLoaded', () => {
const mirrorReposContainer = document.querySelector('.js-mirror-settings');
if (mirrorReposContainer) new MirrorRepos(mirrorReposContainer).init();
initSearchSettings();
});

View File

@ -27,7 +27,7 @@ export default {
registerCiSchema() {
const editorInstance = this.$refs.editor.getEditor();
editorInstance.use(new CiSchemaExtension());
editorInstance.use(new CiSchemaExtension({ instance: editorInstance }));
editorInstance.registerCiSchema({
projectPath: this.projectPath,
projectNamespace: this.projectNamespace,

View File

@ -65,7 +65,9 @@ export default {
css-class="sidebar-collapsed-icon dont-change-state"
tooltip-placement="left"
/>
<div class="gl-display-flex gl-align-items-center gl-justify-between gl-mb-2 hide-collapsed">
<div
class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-mb-2 hide-collapsed"
>
<span class="gl-overflow-hidden gl-text-overflow-ellipsis gl-white-space-nowrap">
{{ $options.i18n.text }}: {{ reference }}
<gl-loading-icon v-if="isLoading" inline :label="$options.i18n.text" />

File diff suppressed because it is too large Load Diff

View File

@ -24,3 +24,53 @@
[id^='editor-lite-'] {
height: 500px;
}
.monaco-editor.gl-editor-lite {
.margin-view-overlays {
.line-numbers {
@include gl-display-flex;
@include gl-justify-content-end;
@include gl-relative;
&::before {
@include gl-visibility-hidden;
@include gl-align-self-center;
@include gl-bg-gray-400;
@include gl-mr-2;
@include gl-w-4;
@include gl-h-4;
mask-image: asset_url('icons-stacked.svg#link');
mask-repeat: no-repeat;
mask-size: cover;
mask-position: center;
content: '';
}
&:hover {
@include gl-text-decoration-underline;
cursor: pointer !important;
}
&:hover::before {
@include gl-visibility-visible;
}
&:focus::before {
@include gl-visibility-visible;
outline: auto;
}
.link-anchor {
@include gl-display-block;
@include gl-absolute;
@include gl-w-full;
@include gl-h-full;
}
}
}
}
.active-line-text {
@include gl-bg-orange-600;
@include gl-opacity-3;
}

View File

@ -11,7 +11,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
# https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/30233
before_action :set_application_setting, except: :integrations
before_action :whitelist_query_limiting, only: [:usage_data]
before_action :disable_query_limiting, only: [:usage_data]
before_action only: [:ci_cd] do
push_frontend_feature_flag(:ci_instance_variables_ui, default_enabled: true)
@ -194,8 +194,8 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
@plans = Plan.all
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/63107')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/63107')
end
def application_setting_params

View File

@ -4,7 +4,7 @@ class Admin::ServicesController < Admin::ApplicationController
include ServiceParams
before_action :service, only: [:edit, :update]
before_action :whitelist_query_limiting, only: [:index]
before_action :disable_query_limiting, only: [:index]
feature_category :integrations
@ -39,7 +39,7 @@ class Admin::ServicesController < Admin::ApplicationController
end
# rubocop: enable CodeReuse/ActiveRecord
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/220357')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/220357')
end
end

View File

@ -13,7 +13,7 @@ module Boards
requires_cross_project_access if: -> { board&.group_board? }
before_action :whitelist_query_limiting, only: [:bulk_move]
before_action :disable_query_limiting, only: [:bulk_move]
before_action :authorize_read_issue, only: [:index]
before_action :authorize_create_issue, only: [:create]
before_action :authorize_update_issue, only: [:update]
@ -147,8 +147,8 @@ module Boards
serializer.represent(resource, opts)
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/issues/35174')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/issues/35174')
end
def validate_id_list

View File

@ -4,7 +4,8 @@ class GraphqlController < ApplicationController
# Unauthenticated users have access to the API for public data
skip_before_action :authenticate_user!
WHITELIST_HEADER = 'HTTP_X_GITLAB_QUERY_WHITELIST_ISSUE'
# Header can be passed by tests to disable SQL query limits.
DISABLE_SQL_QUERY_LIMIT_HEADER = 'HTTP_X_GITLAB_DISABLE_SQL_QUERY_LIMIT'
# If a user is using their session to access GraphQL, we need to have session
# storage, since the admin-mode check is session wide.
@ -23,7 +24,7 @@ class GraphqlController < ApplicationController
before_action(only: [:execute]) { authenticate_sessionless_user!(:api) }
before_action :set_user_last_activity
before_action :track_vs_code_usage
before_action :whitelist_query!
before_action :disable_query_limiting
# Since we deactivate authentication from the main ApplicationController and
# defer it to :authorize_access_api!, we need to override the bypass session
@ -62,12 +63,14 @@ class GraphqlController < ApplicationController
private
# Tests may mark some queries as exempt from query limits
def whitelist_query!
whitelist_issue = request.headers[WHITELIST_HEADER]
return unless whitelist_issue
# Tests may mark some GraphQL queries as exempt from SQL query limits
def disable_query_limiting
return unless Gitlab::QueryLimiting.enabled_for_env?
Gitlab::QueryLimiting.whitelist(whitelist_issue)
disable_issue = request.headers[DISABLE_SQL_QUERY_LIMIT_HEADER]
return unless disable_issue
Gitlab::QueryLimiting.disable!(disable_issue)
end
def set_user_last_activity

View File

@ -0,0 +1,75 @@
# frozen_string_literal: true
module Groups
module Settings
class ApplicationsController < Groups::ApplicationController
include OauthApplications
prepend_before_action :authorize_admin_group!
before_action :set_application, only: [:show, :edit, :update, :destroy]
before_action :load_scopes, only: [:index, :create, :edit, :update]
feature_category :authentication_and_authorization
def index
set_index_vars
end
def show
end
def edit
end
def create
@application = Applications::CreateService.new(current_user, application_params).execute(request)
if @application.persisted?
flash[:notice] = I18n.t(:notice, scope: [:doorkeeper, :flash, :applications, :create])
redirect_to group_settings_application_url(@group, @application)
else
set_index_vars
render :index
end
end
def update
if @application.update(application_params)
redirect_to group_settings_application_path(@group, @application), notice: _('Application was successfully updated.')
else
render :edit
end
end
def destroy
@application.destroy
redirect_to group_settings_applications_url(@group), status: :found, notice: _('Application was successfully destroyed.')
end
private
def set_index_vars
# TODO: Remove limit(100) and implement pagination
# https://gitlab.com/gitlab-org/gitlab/-/issues/324187
@applications = @group.oauth_applications.limit(100)
# Don't overwrite a value possibly set by `create`
@application ||= Doorkeeper::Application.new
end
def set_application
@application = @group.oauth_applications.find(params[:id])
end
def application_params
params
.require(:doorkeeper_application)
.permit(:name, :redirect_uri, :trusted, :scopes, :confidential)
.tap do |params|
params[:owner] = @group
end
end
end
end
end

View File

@ -5,6 +5,7 @@ module Groups
class CiCdController < Groups::ApplicationController
include RunnerSetupScripts
layout 'group_settings'
skip_cross_project_access_check :show
before_action :authorize_admin_group!
before_action :authorize_update_max_artifacts_size!, only: [:update]

View File

@ -9,6 +9,8 @@ module Groups
feature_category :integrations
layout 'group_settings'
def index
@integrations = Service.find_or_initialize_all_non_project_specific(Service.for_group(group)).sort_by(&:title)
end

View File

@ -3,6 +3,7 @@
module Groups
module Settings
class PackagesAndRegistriesController < Groups::ApplicationController
layout 'group_settings'
before_action :authorize_admin_group!
before_action :verify_packages_enabled!

View File

@ -3,6 +3,7 @@
module Groups
module Settings
class RepositoryController < Groups::ApplicationController
layout 'group_settings'
skip_cross_project_access_check :show
before_action :authorize_create_deploy_token!
before_action :define_deploy_token_variables

View File

@ -3,7 +3,7 @@
class Import::GitlabProjectsController < Import::BaseController
include WorkhorseAuthorization
before_action :whitelist_query_limiting, only: [:create]
before_action :disable_query_limiting, only: [:create]
before_action :verify_gitlab_project_import_enabled
def new
@ -42,8 +42,8 @@ class Import::GitlabProjectsController < Import::BaseController
)
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42437')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42437')
end
def uploader_class

View File

@ -3,7 +3,7 @@
class Import::ManifestController < Import::BaseController
extend ::Gitlab::Utils::Override
before_action :whitelist_query_limiting, only: [:create]
before_action :disable_query_limiting, only: [:create]
before_action :verify_import_enabled
before_action :ensure_import_vars, only: [:create, :status]
@ -115,7 +115,7 @@ class Import::ManifestController < Import::BaseController
render_404 unless manifest_import_enabled?
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/48939')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/48939')
end
end

View File

@ -8,7 +8,7 @@ class Projects::CommitsController < Projects::ApplicationController
prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) }
around_action :allow_gitaly_ref_name_caching
before_action :whitelist_query_limiting, except: :commits_root
before_action :disable_query_limiting, except: :commits_root
before_action :require_non_empty_project
before_action :assign_ref_vars, except: :commits_root
before_action :authorize_download_code!
@ -83,7 +83,7 @@ class Projects::CommitsController < Projects::ApplicationController
@commits = set_commits_for_rendering(@commits)
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42330')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42330')
end
end

View File

@ -7,7 +7,7 @@ class Projects::ForksController < Projects::ApplicationController
include Gitlab::Utils::StrongMemoize
# Authorize
before_action :whitelist_query_limiting, only: [:create]
before_action :disable_query_limiting, only: [:create]
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :authenticate_user!, only: [:new, :create]
@ -110,8 +110,8 @@ class Projects::ForksController < Projects::ApplicationController
access_denied! unless fork_namespace && fork_service.valid_fork_target?
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42335')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42335')
end
def load_namespaces_with_associations

View File

@ -18,7 +18,7 @@ class Projects::IssuesController < Projects::ApplicationController
prepend_before_action :authenticate_user!, only: [:new, :export_csv]
prepend_before_action :store_uri, only: [:new, :show, :designs]
before_action :whitelist_query_limiting, only: [:create, :create_merge_request, :move, :bulk_update]
before_action :disable_query_limiting, only: [:create, :create_merge_request, :move, :bulk_update]
before_action :check_issues_available!
before_action :issue, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) }
after_action :log_issue_show, unless: ->(c) { ISSUES_EXCEPT_ACTIONS.include?(c.action_name.to_sym) }
@ -353,13 +353,13 @@ class Projects::IssuesController < Projects::ApplicationController
IssuesFinder
end
def whitelist_query_limiting
def disable_query_limiting
# Also see the following issues:
#
# 1. https://gitlab.com/gitlab-org/gitlab-foss/issues/42423
# 2. https://gitlab.com/gitlab-org/gitlab-foss/issues/42424
# 3. https://gitlab.com/gitlab-org/gitlab-foss/issues/42426
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42422')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42422')
end
private

View File

@ -6,7 +6,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
include RendersCommits
skip_before_action :merge_request
before_action :whitelist_query_limiting, only: [:create]
before_action :disable_query_limiting, only: [:create]
before_action :authorize_create_merge_request_from!
before_action :apply_diff_view_cookie!, only: [:diffs, :diff_for_path]
before_action :build_merge_request, except: [:create]
@ -133,8 +133,8 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
end
# rubocop: enable CodeReuse/ActiveRecord
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42384')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42384')
end
def incr_count_webide_merge_request

View File

@ -14,7 +14,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
skip_before_action :merge_request, only: [:index, :bulk_update, :export_csv]
before_action :apply_diff_view_cookie!, only: [:show]
before_action :whitelist_query_limiting, only: [:assign_related_issues, :update]
before_action :disable_query_limiting, only: [:assign_related_issues, :update]
before_action :authorize_update_issuable!, only: [:close, :edit, :update, :remove_wip, :sort]
before_action :authorize_read_actual_head_pipeline!, only: [
:test_reports,
@ -468,9 +468,9 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
access_denied! unless @merge_request.can_be_merged_by?(current_user)
end
def whitelist_query_limiting
def disable_query_limiting
# Also see https://gitlab.com/gitlab-org/gitlab-foss/issues/42441
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42438')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42438')
end
def reports_response(report_comparison, pipeline = nil)

View File

@ -4,7 +4,7 @@ class Projects::NetworkController < Projects::ApplicationController
include ExtractsPath
include ApplicationHelper
before_action :whitelist_query_limiting
before_action :disable_query_limiting
before_action :require_non_empty_project
before_action :assign_ref_vars
before_action :authorize_download_code!
@ -42,7 +42,7 @@ class Projects::NetworkController < Projects::ApplicationController
@commit = @repo.commit(@options[:extended_sha1])
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42333')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42333')
end
end

View File

@ -6,7 +6,7 @@ class Projects::NotesController < Projects::ApplicationController
include NotesHelper
include ToggleAwardEmoji
before_action :whitelist_query_limiting, only: [:create, :update]
before_action :disable_query_limiting, only: [:create, :update]
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
@ -87,7 +87,7 @@ class Projects::NotesController < Projects::ApplicationController
access_denied! unless can?(current_user, :create_note, noteable)
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42383')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42383')
end
end

View File

@ -4,7 +4,7 @@ class Projects::PipelinesController < Projects::ApplicationController
include ::Gitlab::Utils::StrongMemoize
include Analytics::UniqueVisitsHelper
before_action :whitelist_query_limiting, only: [:create, :retry]
before_action :disable_query_limiting, only: [:create, :retry]
before_action :pipeline, except: [:index, :new, :create, :charts, :config_variables]
before_action :set_pipeline_path, only: [:show]
before_action :authorize_read_pipeline!
@ -92,7 +92,7 @@ class Projects::PipelinesController < Projects::ApplicationController
end
def show
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/26657')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/26657')
respond_to do |format|
format.html
@ -269,9 +269,9 @@ class Projects::PipelinesController < Projects::ApplicationController
&.present(current_user: current_user)
end
def whitelist_query_limiting
def disable_query_limiting
# Also see https://gitlab.com/gitlab-org/gitlab-foss/issues/42343
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42339')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42339')
end
def authorize_update_pipeline!

View File

@ -5,6 +5,7 @@ module Projects
class AccessTokensController < Projects::ApplicationController
include ProjectsHelper
layout 'project_settings'
before_action :check_feature_availability
feature_category :authentication_and_authorization

View File

@ -7,6 +7,7 @@ module Projects
NUMBER_OF_RUNNERS_PER_PAGE = 20
layout 'project_settings'
before_action :authorize_admin_pipeline!
before_action :define_variables
before_action do

View File

@ -3,6 +3,7 @@
module Projects
module Settings
class OperationsController < Projects::ApplicationController
layout 'project_settings'
before_action :authorize_admin_operations!
before_action :authorize_read_prometheus_alerts!, only: [:reset_alerting_token]

View File

@ -3,6 +3,7 @@
module Projects
module Settings
class RepositoryController < Projects::ApplicationController
layout 'project_settings'
before_action :authorize_admin_project!
before_action :define_variables, only: [:create_deploy_token]
before_action do

View File

@ -14,7 +14,7 @@ class ProjectsController < Projects::ApplicationController
around_action :allow_gitaly_ref_name_caching, only: [:index, :show]
before_action :whitelist_query_limiting, only: [:show, :create]
before_action :disable_query_limiting, only: [:show, :create]
before_action :authenticate_user!, except: [:index, :show, :activity, :refs, :resolve, :unfoldered_environment_names]
before_action :redirect_git_extension, only: [:show]
before_action :project, except: [:index, :new, :create, :resolve]
@ -510,8 +510,8 @@ class ProjectsController < Projects::ApplicationController
redirect_to(request.original_url.sub(%r{\.git/?\Z}, ''))
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/20826')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20826')
end
def present_project

View File

@ -9,7 +9,7 @@ class RegistrationsController < Devise::RegistrationsController
layout 'devise'
prepend_before_action :check_captcha, only: :create
before_action :whitelist_query_limiting, :ensure_destroy_prerequisites_met, only: [:destroy]
before_action :disable_query_limiting, :ensure_destroy_prerequisites_met, only: [:destroy]
before_action :load_recaptcha, only: :new
before_action :set_invite_params, only: :new
@ -162,8 +162,8 @@ class RegistrationsController < Devise::RegistrationsController
@devise_mapping ||= Devise.mappings[:user]
end
def whitelist_query_limiting
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42380')
def disable_query_limiting
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42380')
end
def load_recaptcha

View File

@ -17,6 +17,6 @@ class ApplicationsFinder
def by_id(applications)
return applications unless params[:id]
Doorkeeper::Application.find_by(id: params[:id]) # rubocop: disable CodeReuse/ActiveRecord
applications.find_by(id: params[:id]) # rubocop: disable CodeReuse/ActiveRecord
end
end

View File

@ -18,7 +18,7 @@ module Mutations
argument :api_url, GraphQL::STRING_TYPE,
required: true,
description: 'Endpoint at which prometheus can be queried.'
description: 'Endpoint at which Prometheus can be queried.'
def resolve(args)
project = authorized_find!(args[:project_path])

View File

@ -16,7 +16,7 @@ module Mutations
argument :api_url, GraphQL::STRING_TYPE,
required: false,
description: "Endpoint at which prometheus can be queried."
description: "Endpoint at which Prometheus can be queried."
def resolve(args)
integration = authorized_find!(id: args[:id])

View File

@ -53,7 +53,7 @@ module Mutations
end
def resolve(board:, **args)
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/247861')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/247861')
raise_resource_not_available_error! unless board
authorize_board!(board)

View File

@ -19,7 +19,7 @@ module Mutations
def resolve(project_path:, iid:, assignee_usernames:, operation_mode: Types::MutationOperationModeEnum.enum[:replace])
resource = authorized_find!(project_path: project_path, iid: iid)
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/issues/36098') if resource.is_a?(MergeRequest)
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/issues/36098') if resource.is_a?(MergeRequest)
update_service_class.new(
resource.project,

View File

@ -11,7 +11,7 @@ module Mutations
description: 'The project to move the issue to.'
def resolve(project_path:, iid:, target_project_path:)
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab/-/issues/267762')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/267762')
issue = authorized_find!(project_path: project_path, iid: iid)
source_project = issue.project

View File

@ -42,7 +42,8 @@ module Mutations
description: 'Squash commits on the source branch before merge.'
def resolve(project_path:, iid:, **args)
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/42317')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/42317')
merge_request = authorized_find!(project_path: project_path, iid: iid)
project = merge_request.target_project
merge_params = args.compact.with_indifferent_access

View File

@ -8,15 +8,16 @@ module Resolvers
argument :path, GraphQL::STRING_TYPE,
required: true,
description: "Path to a file which defines metrics dashboard " \
"eg: 'config/prometheus/common_metrics.yml'."
description: <<~MD
Path to a file which defines a metrics dashboard eg: `"config/prometheus/common_metrics.yml"`.
MD
alias_method :environment, :object
def resolve(**args)
def resolve(path:)
return unless environment
::PerformanceMonitoring::PrometheusDashboard.find_for(**args, **service_params)
::PerformanceMonitoring::PrometheusDashboard.find_for(path: path, **service_params)
end
private

View File

@ -7,7 +7,7 @@ module Resolvers
argument :ids, [GraphQL::ID_TYPE],
required: false,
description: 'Array of global milestone IDs, e.g., "gid://gitlab/Milestone/1".'
description: 'Array of global milestone IDs, e.g., `"gid://gitlab/Milestone/1"`.'
argument :state, Types::MilestoneStateEnum,
required: false,

View File

@ -22,6 +22,9 @@ module GroupsHelper
ldap_group_links#index
hooks#index
pipeline_quota#index
applications#index
applications#show
applications#edit
packages_and_registries#index
]
end

View File

@ -7,6 +7,7 @@ module Ci
include StripAttribute
include Schedulable
include Limitable
include EachBatch
self.limit_name = 'ci_pipeline_schedules'
self.limit_scope = :project
@ -28,6 +29,7 @@ module Ci
scope :active, -> { where(active: true) }
scope :inactive, -> { where(active: false) }
scope :preloaded, -> { preload(:owner, project: [:route]) }
scope :owned_by, ->(user) { where(owner: user) }
accepts_nested_attributes_for :variables, allow_destroy: true

View File

@ -70,6 +70,7 @@ class Group < Namespace
has_many :group_deploy_keys, through: :group_deploy_keys_groups
has_many :group_deploy_tokens
has_many :deploy_tokens, through: :group_deploy_tokens
has_many :oauth_applications, class_name: 'Doorkeeper::Application', as: :owner, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent
has_one :dependency_proxy_setting, class_name: 'DependencyProxy::GroupSetting'
has_many :dependency_proxy_blobs, class_name: 'DependencyProxy::Blob'

View File

@ -351,6 +351,7 @@ class User < ApplicationRecord
# For this reason the tradeoff is to disable this cop.
after_transition any => :blocked do |user|
Ci::CancelUserPipelinesService.new.execute(user)
Ci::DisableUserPipelineSchedulesService.new.execute(user)
end
# rubocop: enable CodeReuse/ServiceClass
end

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
module Ci
class DisableUserPipelineSchedulesService
def execute(user)
Ci::PipelineSchedule.active.owned_by(user).each_batch do |relation|
relation.update_all(active: false)
end
end
end
end

View File

@ -48,7 +48,7 @@ class PostReceiveService
end
def process_mr_push_options(push_options, changes)
Gitlab::QueryLimiting.whitelist('https://gitlab.com/gitlab-org/gitlab-foss/issues/61359')
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab-foss/issues/61359')
return unless repository
unless repository.repo_type.project?

View File

@ -1,4 +1,5 @@
- page_title _("Edit"), @application.name, _("Applications")
- @content_class = "limit-container-width" unless fluid_layout
%h3.page-title= _('Edit application')
= render 'form', application: @application
= render 'shared/doorkeeper/applications/form', url: doorkeeper_submit_path(@application)

View File

@ -1,85 +1,8 @@
- page_title _("Applications")
- @content_class = "limit-container-width" unless fluid_layout
.row.gl-mt-3
.col-lg-4.profile-settings-sidebar
%h4.gl-mt-0
= page_title
%p
- if user_oauth_applications?
= _("Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account.")
- else
= _("Manage applications that you've authorized to use your account.")
.col-lg-8
- if user_oauth_applications?
%h5.gl-mt-0
= _('Add new application')
= render 'form', application: @application
%hr
- else
.bs-callout.bs-callout-disabled
= _('Adding new applications is disabled in your GitLab instance. Please contact your GitLab administrator to get the permission')
- if user_oauth_applications?
.oauth-applications
%h5
= _("Your applications (%{size})") % { size: @applications.size }
- if @applications.any?
.table-responsive
%table.table
%thead
%tr
%th= _('Name')
%th= _('Callback URL')
%th= _('Clients')
%th.last-heading
%tbody
- @applications.each do |application|
%tr{ id: "application_#{application.id}" }
%td= link_to application.name, oauth_application_path(application)
%td
- application.redirect_uri.split.each do |uri|
%div= uri
%td= application.access_tokens.count
%td.gl-display-flex
= link_to edit_oauth_application_path(application), class: "gl-button btn btn-default gl-mr-2" do
%span.sr-only
= _('Edit')
= sprite_icon('pencil')
= render 'delete_form', application: application, small: true
- else
.settings-message.text-center
= _("You don't have any applications")
.oauth-authorized-applications.prepend-top-20.gl-mb-3
- if user_oauth_applications?
%h5
= _("Authorized applications (%{size})") % { size: @authorized_apps.size + @authorized_anonymous_tokens.size }
- if @authorized_tokens.any?
.table-responsive
%table.table.table-striped
%thead
%tr
%th= _('Name')
%th= _('Authorized At')
%th= _('Scope')
%th
%tbody
- @authorized_apps.each do |app|
- token = app.authorized_tokens.order('created_at desc').first # rubocop: disable CodeReuse/ActiveRecord
%tr{ id: "application_#{app.id}" }
%td= app.name
%td= token.created_at
%td= token.scopes
%td= render 'doorkeeper/authorized_applications/delete_form', application: app
- @authorized_anonymous_tokens.each do |token|
%tr
%td
= _('Anonymous')
.form-text.text-muted
%em= _("Authorization was granted by entering your username and password in the application.")
%td= token.created_at
%td= token.scopes
%td= render 'doorkeeper/authorized_applications/delete_form', token: token
- else
.settings-message.text-center
= _("You don't have any authorized applications")
= render 'shared/doorkeeper/applications/index',
oauth_applications_enabled: user_oauth_applications?,
oauth_authorized_applications_enabled: true,
form_url: doorkeeper_submit_path(@application),
application_url: ->(application) { oauth_application_path(application) },
edit_application_url: ->(application) { edit_oauth_application_path(application) }

View File

@ -6,42 +6,4 @@
%h3.page-title
= _("Application: %{name}") % { name: @application.name }
.table-holder.oauth-application-show
%table.table
%tr
%td
= _('Application ID')
%td
.clipboard-group
.input-group
%input.label.label-monospace.monospace{ id: "application_id", type: "text", autocomplete: 'off', value: @application.uid, readonly: true }
.input-group-append
= clipboard_button(target: '#application_id', title: _("Copy ID"), class: "gl-button btn btn-default")
%tr
%td
= _('Secret')
%td
.clipboard-group
.input-group
%input.label.label-monospace.monospace{ id: "secret", type: "text", autocomplete: 'off', value: @application.secret, readonly: true }
.input-group-append
= clipboard_button(target: '#secret', title: _("Copy secret"), class: "gl-button btn btn-default")
%tr
%td
= _('Callback URL')
%td
- @application.redirect_uri.split.each do |uri|
%div
%span.monospace= uri
%tr
%td
= _('Confidential')
%td
= @application.confidential? ? _('Yes') : _('No')
= render "shared/tokens/scopes_list", token: @application
.form-actions
= link_to _('Edit'), edit_oauth_application_path(@application), class: 'gl-button btn btn-confirm wide float-left'
= render 'delete_form', application: @application, submit_btn_css: 'gl-button btn btn-danger gl-ml-3'
= render 'shared/doorkeeper/applications/show', edit_path: edit_oauth_application_path(@application), delete_path: oauth_application_path(@application)

View File

@ -1,5 +1,3 @@
- enable_search_settings locals: { container_class: 'gl-my-5' }
= form_for @group, html: { multipart: true, class: 'gl-show-field-errors js-general-settings-form' }, authenticity_token: true do |f|
%input{ type: 'hidden', name: 'update_section', value: 'js-general-settings' }
= form_errors(@group)

View File

@ -0,0 +1,5 @@
- page_title _("Edit"), @application.name, _("Group applications")
- @content_class = "limit-container-width" unless fluid_layout
%h3.page-title= _('Edit group application')
= render 'shared/doorkeeper/applications/form', url: group_settings_application_path(@group, @application)

View File

@ -0,0 +1,8 @@
- page_title _("Group applications")
= render 'shared/doorkeeper/applications/index',
oauth_applications_enabled: user_oauth_applications?,
oauth_authorized_applications_enabled: false,
form_url: group_settings_applications_path(@group),
application_url: ->(application) { group_settings_application_path(@group, application) },
edit_application_url: ->(application) { edit_group_settings_application_path(@group, application) }

View File

@ -0,0 +1,9 @@
- add_to_breadcrumbs _("Group applications"), group_settings_applications_path(@group)
- breadcrumb_title @application.name
- page_title @application.name, _("Group applications")
- @content_class = "limit-container-width" unless fluid_layout
%h3.page-title
= _("Group application: %{name}") % { name: @application.name }
= render 'shared/doorkeeper/applications/show', edit_path: edit_group_settings_application_path(@group, @application), delete_path: group_settings_application_path(@group, @application)

View File

@ -4,8 +4,6 @@
- expanded = expanded_by_default?
- general_expanded = @group.errors.empty? ? expanded : true
- enable_search_settings locals: { container_class: 'gl-my-5' }
-# Given we only have one field in this form which is also admin-only,
-# we don't want to show an empty section to non-admin users,
- if can?(current_user, :update_max_artifacts_size, @group)

View File

@ -2,6 +2,4 @@
- page_title _('Packages & Registries')
- @content_class = 'limit-container-width' unless fluid_layout
- enable_search_settings locals: { container_class: 'gl-my-5' }
%section#js-packages-and-registries-settings{ data: { default_expanded: expanded_by_default?.to_s, group_path: @group.full_path } }

View File

@ -1,8 +1,6 @@
- breadcrumb_title _('Repository Settings')
- page_title _('Repository')
- enable_search_settings locals: { container_class: 'gl-my-5' }
- deploy_token_description = s_('DeployTokens|Group deploy tokens allow access to the packages, repositories, and registry images within the group.')
= render "shared/deploy_tokens/index", group_or_project: @group, description: deploy_token_description

View File

@ -1,4 +1,5 @@
- page_title _("Settings")
- nav "group"
- enable_search_settings locals: { container_class: 'gl-my-5' }
= render template: "layouts/group"

View File

@ -19,10 +19,13 @@
%span.gl-badge.gl-bg-green-500.gl-text-white.gl-rounded-pill.gl-font-weight-bold.gl-py-1
= _('Next')
- if current_user
= render "layouts/nav/dashboard"
- if Feature.enabled?(:combined_menu, current_user, default_enabled: :yaml)
= render "layouts/nav/combined_menu"
- else
= render "layouts/nav/explore"
- if current_user
= render "layouts/nav/dashboard"
- else
= render "layouts/nav/explore"
.navbar-collapse.collapse
%ul.nav.navbar-nav

View File

@ -0,0 +1,3 @@
%button{ type: 'button', data: { toggle: "dropdown" } }
= sprite_icon('ellipsis_v')
= _('Projects')

View File

@ -145,7 +145,7 @@
%span.nav-item-name.qa-group-settings-item
= _('Settings')
%ul.sidebar-sub-level-items.qa-group-sidebar-submenu{ data: { testid: 'group-settings-menu' } }
= nav_link(path: %w[groups#projects groups#edit badges#index ci_cd#show], html_options: { class: "fly-out-top-item" } ) do
= nav_link(path: %w[groups#projects groups#edit badges#index ci_cd#show groups/applications#index], html_options: { class: "fly-out-top-item" } ) do
= link_to edit_group_path(@group) do
%strong.fly-out-top-item-name
= _('Settings')
@ -175,6 +175,11 @@
%span
= _('CI/CD')
= nav_link(controller: :applications) do
= link_to group_settings_applications_path(@group), title: _('Applications') do
%span
= _('Applications')
= render 'groups/sidebar/packages_settings'
= render_if_exists "groups/ee/settings_nav"

View File

@ -1,4 +1,6 @@
- page_title _("Settings")
- nav "project"
- enable_search_settings locals: { container_class: 'gl-my-5' }
= render template: "layouts/project"

View File

@ -14,4 +14,4 @@
- if can_create_wiki
%p
= _("Add a homepage to your wiki that contains information about your project and GitLab will display it here instead of this message.")
= link_to _("Create your first page"), wiki_path(@project.wiki) + '?view=create', class: "btn gl-button btn-primary"
= link_to _("Create your first page"), wiki_path(@project.wiki) + '?view=create', class: "btn gl-button btn-confirm"

View File

@ -3,8 +3,6 @@
- @content_class = "limit-container-width" unless fluid_layout
- expanded = expanded_by_default?
- enable_search_settings
%section.settings.general-settings.no-animate.expanded#js-general-settings
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only= _('Naming, topics, avatar')

View File

@ -5,8 +5,6 @@
- expanded = expanded_by_default?
- general_expanded = @project.errors.empty? ? expanded : true
- enable_search_settings locals: { container_class: 'gl-my-5' }
%section.settings#js-general-pipeline-settings.no-animate{ class: ('expanded' if general_expanded), data: { qa_selector: 'general_pipelines_settings_content' } }
.settings-header
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only

View File

@ -5,7 +5,7 @@
%section.settings.no-animate#js-alert-management-settings{ class: ('expanded' if expanded) }
.settings-header
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Alerts')
%button.btn.js-settings-toggle{ type: 'button' }
= _('Expand')

View File

@ -4,7 +4,7 @@
%section.settings.no-animate.js-error-tracking-settings
.settings-header
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Error tracking')
%button.btn.js-settings-toggle{ type: 'button' }
= _('Expand')

View File

@ -1,6 +1,6 @@
%section.settings.no-animate.js-prometheus-settings
.settings-header
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _('Prometheus')
%button.btn.js-settings-toggle{ type: 'button' }
= _('Expand')

View File

@ -3,7 +3,7 @@
%section.settings.border-0.no-animate
.settings-header{ :class => "border-top" }
%h4
%h4.settings-title.js-settings-toggle.js-settings-toggle-trigger-only
= _("Jaeger tracing")
%button.btn.gl-button.js-settings-toggle{ type: 'button' }
= _('Expand')

View File

@ -2,8 +2,6 @@
- page_title _('Operations Settings')
- breadcrumb_title _('Operations Settings')
- enable_search_settings locals: { container_class: 'gl-my-5' }
= render 'projects/settings/operations/alert_management'
= render 'projects/settings/operations/incidents'
= render 'projects/settings/operations/error_tracking'

View File

@ -3,8 +3,6 @@
- @content_class = "limit-container-width" unless fluid_layout
- deploy_token_description = s_('DeployTokens|Deploy tokens allow access to packages, your repository, and registry images.')
- enable_search_settings locals: { container_class: 'gl-my-5' }
= render "projects/default_branch/show"
= render_if_exists "projects/push_rules/index"
= render "projects/mirrors/mirror_repos"

View File

@ -52,6 +52,6 @@
= render 'shared/zen', attr: :release_description, classes: 'note-textarea', placeholder: s_('TagsPage|Write your release notes or drag files here…'), current_text: @release_description, qa_selector: 'release_notes_field'
= render 'shared/notes/hints'
.form-actions
= button_tag s_('TagsPage|Create tag'), class: 'btn btn-success', data: { qa_selector: "create_tag_button" }
= link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'btn btn-cancel'
= button_tag s_('TagsPage|Create tag'), class: 'gl-button btn btn-confirm', data: { qa_selector: "create_tag_button" }
= link_to s_('TagsPage|Cancel'), project_tags_path(@project), class: 'gl-button btn btn-default btn-cancel'
%script#availableRefs{ type: "application/json" }= @project.repository.ref_names.to_json.html_safe

View File

@ -1,6 +1,6 @@
- submit_btn_css ||= 'gl-button btn btn-danger btn-sm'
= form_tag oauth_application_path(application) do
%input{ :name => "_method", :type => "hidden", :value => "delete" }/
= form_tag path do
%input{ :name => "_method", :type => "hidden", :value => "delete" }
- if defined? small
= button_tag type: "submit", class: "gl-button btn btn-default", data: { confirm: _("Are you sure?") } do
%span.sr-only

View File

@ -1,5 +1,5 @@
= form_for application, url: doorkeeper_submit_path(application), html: { role: 'form', class: 'doorkeeper-app-form' } do |f|
= form_errors(application)
= form_for @application, url: url, html: { role: 'form', class: 'doorkeeper-app-form' } do |f|
= form_errors(@application)
.form-group
= f.label :name, class: 'label-bold'
@ -20,7 +20,7 @@
.form-group
= f.label :scopes, class: 'label-bold'
= render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: application, scopes: @scopes
= render 'shared/tokens/scopes_form', prefix: 'doorkeeper_application', token: @application, scopes: @scopes
.gl-mt-3
= f.submit _('Save application'), class: "gl-button btn btn-confirm"

View File

@ -0,0 +1,88 @@
- @content_class = "limit-container-width" unless fluid_layout
.row.gl-mt-3
.col-lg-4.profile-settings-sidebar
%h4.gl-mt-0
= page_title
%p
- if oauth_applications_enabled
- if oauth_authorized_applications_enabled
= _("Manage applications that can use GitLab as an OAuth provider, and applications that you've authorized to use your account.")
- else
= _("Manage applications that can use GitLab as an OAuth provider.")
- else
= _("Manage applications that you've authorized to use your account.")
.col-lg-8
- if oauth_applications_enabled
%h5.gl-mt-0
= _('Add new application')
= render 'shared/doorkeeper/applications/form', url: form_url
%hr
- else
.bs-callout.bs-callout-disabled
= _('Adding new applications is disabled in your GitLab instance. Please contact your GitLab administrator to get the permission')
- if oauth_applications_enabled
.oauth-applications
%h5
= _("Your applications (%{size})") % { size: @applications.size }
- if @applications.any?
.table-responsive
%table.table
%thead
%tr
%th= _('Name')
%th= _('Callback URL')
%th= _('Clients')
%th.last-heading
%tbody
- @applications.each do |application|
%tr{ id: "application_#{application.id}" }
%td= link_to application.name, application_url.call(application)
%td
- application.redirect_uri.split.each do |uri|
%div= uri
%td= application.access_tokens.count
%td.gl-display-flex
= link_to edit_application_url.call(application), class: "gl-button btn btn-default gl-mr-2" do
%span.sr-only
= _('Edit')
= sprite_icon('pencil')
= render 'shared/doorkeeper/applications/delete_form', path: application_url.call(application), small: true
- else
.settings-message.text-center
= _("You don't have any applications")
- if oauth_authorized_applications_enabled
.oauth-authorized-applications.prepend-top-20.gl-mb-3
- if oauth_applications_enabled
%h5
= _("Authorized applications (%{size})") % { size: @authorized_apps.size + @authorized_anonymous_tokens.size }
- if @authorized_tokens.any?
.table-responsive
%table.table.table-striped
%thead
%tr
%th= _('Name')
%th= _('Authorized At')
%th= _('Scope')
%th
%tbody
- @authorized_apps.each do |app|
- token = app.authorized_tokens.order('created_at desc').first # rubocop: disable CodeReuse/ActiveRecord
%tr{ id: "application_#{app.id}" }
%td= app.name
%td= token.created_at
%td= token.scopes
%td= render 'doorkeeper/authorized_applications/delete_form', application: app
- @authorized_anonymous_tokens.each do |token|
%tr
%td
= _('Anonymous')
.form-text.text-muted
%em= _("Authorization was granted by entering your username and password in the application.")
%td= token.created_at
%td= token.scopes
%td= render 'doorkeeper/authorized_applications/delete_form', token: token
- else
.settings-message.text-center
= _("You don't have any authorized applications")

View File

@ -0,0 +1,39 @@
.table-holder.oauth-application-show
%table.table
%tr
%td
= _('Application ID')
%td
.clipboard-group
.input-group
%input.label.label-monospace.monospace{ id: "application_id", type: "text", autocomplete: 'off', value: @application.uid, readonly: true }
.input-group-append
= clipboard_button(target: '#application_id', title: _("Copy ID"), class: "gl-button btn btn-default")
%tr
%td
= _('Secret')
%td
.clipboard-group
.input-group
%input.label.label-monospace.monospace{ id: "secret", type: "text", autocomplete: 'off', value: @application.secret, readonly: true }
.input-group-append
= clipboard_button(target: '#secret', title: _("Copy secret"), class: "gl-button btn btn-default")
%tr
%td
= _('Callback URL')
%td
- @application.redirect_uri.split.each do |uri|
%div
%span.monospace= uri
%tr
%td
= _('Confidential')
%td
= @application.confidential? ? _('Yes') : _('No')
= render "shared/tokens/scopes_list", token: @application
.form-actions
= link_to _('Edit'), edit_path, class: 'gl-button btn btn-confirm wide float-left'
= render 'shared/doorkeeper/applications/delete_form', path: delete_path, submit_btn_css: 'gl-button btn btn-danger gl-ml-3'

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