Commit eef9c80f authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖
Browse files

Add latest changes from gitlab-org/gitlab@master

parent d6404862
......@@ -53,7 +53,7 @@ review-build-cng:
review-deploy:
extends:
- .review-workflow-base
- .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
- .review:rules:review-deploy
stage: review
dependencies: []
resource_group: "review/${CI_COMMIT_REF_NAME}"
......@@ -172,7 +172,7 @@ review-qa-all:
review-performance:
extends:
- .default-retry
- .review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise
- .review:rules:review-performance
image:
name: sitespeedio/sitespeed.io:6.3.1
entrypoint: [""]
......
......@@ -669,7 +669,23 @@
allow_failure: true
- <<: *if-dot-com-gitlab-org-schedule
.review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise:
.review:rules:review-deploy:
rules:
- <<: *if-not-ee
when: never
- <<: *if-dot-com-gitlab-org-merge-request
changes: *ci-review-patterns
- <<: *if-dot-com-gitlab-org-merge-request
changes: *frontend-patterns
allow_failure: true
- <<: *if-dot-com-gitlab-org-merge-request
changes: *code-qa-patterns
when: manual
allow_failure: true
- <<: *if-dot-com-gitlab-org-schedule
allow_failure: true
.review:rules:review-performance:
rules:
- if: '$DAST_RUN == "true"' # Skip this job when DAST is run
when: never
......
......@@ -260,7 +260,7 @@ gem 'ruby-fogbugz', '~> 0.2.1'
gem 'kubeclient', '~> 4.6.0'
# Sanitize user input
gem 'sanitize', '~> 4.6'
gem 'sanitize', '~> 5.2.1'
gem 'babosa', '~> 1.0.2'
# Sanitizes SVG input
......@@ -328,7 +328,7 @@ gem 'snowplow-tracker', '~> 0.6.1'
# Metrics
group :metrics do
gem 'method_source', '~> 0.8', require: false
gem 'method_source', '~> 1.0', require: false
# Prometheus
gem 'prometheus-client-mmap', '~> 0.11.0'
......@@ -351,7 +351,7 @@ end
group :development, :test do
gem 'bullet', '~> 6.1.0'
gem 'pry-byebug', '~> 3.5.1', platform: :mri
gem 'pry-byebug', '~> 3.9.0', platform: :mri
gem 'pry-rails', '~> 0.3.9'
gem 'awesome_print', require: false
......
......@@ -151,7 +151,7 @@ GEM
bundler-audit (0.6.1)
bundler (>= 1.2.0, < 3)
thor (~> 0.18)
byebug (9.1.0)
byebug (11.1.3)
capybara (3.33.0)
addressable
mini_mime (>= 0.1.3)
......@@ -177,7 +177,7 @@ GEM
cork
nap
open4 (~> 1.3)
coderay (1.1.2)
coderay (1.1.3)
colored2 (3.1.2)
commonmarker (0.20.1)
ruby-enum (~> 0.5)
......@@ -676,7 +676,7 @@ GEM
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
memory_profiler (0.9.14)
method_source (0.9.2)
method_source (1.0.0)
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2020.0512)
......@@ -713,10 +713,10 @@ GEM
netrc (0.11.0)
nio4r (2.5.2)
no_proxy_fix (0.1.2)
nokogiri (1.10.9)
nokogiri (1.10.10)
mini_portile2 (~> 2.4.0)
nokogumbo (1.5.0)
nokogiri
nokogumbo (2.0.2)
nokogiri (~> 1.8, >= 1.8.4)
notiffany (0.1.3)
nenv (~> 0.1)
shellany (~> 0.0)
......@@ -832,12 +832,12 @@ GEM
unparser
procto (0.0.3)
prometheus-client-mmap (0.11.0)
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
pry-byebug (3.5.1)
byebug (~> 9.1)
pry (~> 0.10)
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
pry-byebug (3.9.0)
byebug (~> 11.0)
pry (~> 0.13.0)
pry-rails (0.3.9)
pry (>= 0.10.4)
public_suffix (4.0.3)
......@@ -1028,10 +1028,10 @@ GEM
rubyzip (2.0.0)
rugged (0.28.4.1)
safe_yaml (1.0.4)
sanitize (4.6.6)
sanitize (5.2.1)
crass (~> 1.0.2)
nokogiri (>= 1.4.4)
nokogumbo (~> 1.4)
nokogiri (>= 1.8.0)
nokogumbo (~> 2.0)
sass (3.5.5)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
......@@ -1360,7 +1360,7 @@ DEPENDENCIES
mail (= 2.7.1)
marginalia (~> 1.9.0)
memory_profiler (~> 0.9)
method_source (~> 0.8)
method_source (~> 1.0)
mimemagic (~> 0.3.2)
mini_magick
minitest (~> 5.11.0)
......@@ -1397,7 +1397,7 @@ DEPENDENCIES
png_quantizator (~> 0.2.1)
premailer-rails (~> 1.10.3)
prometheus-client-mmap (~> 0.11.0)
pry-byebug (~> 3.5.1)
pry-byebug (~> 3.9.0)
pry-rails (~> 0.3.9)
rack (~> 2.0.9)
rack-attack (~> 6.3.0)
......@@ -1437,7 +1437,7 @@ DEPENDENCIES
ruby_parser (~> 3.8)
rubyzip (~> 2.0.0)
rugged (~> 0.28)
sanitize (~> 4.6)
sanitize (~> 5.2.1)
sassc-rails (~> 2.1.0)
scss_lint (~> 0.56.0)
seed-fu (~> 2.3.7)
......
import PayloadPreviewer from '~/pages/admin/application_settings/payload_previewer';
export default () => {
new PayloadPreviewer(
document.querySelector('.js-usage-ping-payload-trigger'),
document.querySelector('.js-usage-ping-payload'),
).init();
Array.from(document.querySelectorAll('.js-payload-preview-trigger')).forEach(trigger => {
new PayloadPreviewer(trigger).init();
});
};
......@@ -67,7 +67,7 @@ export default {
</script>
<template>
<gl-deprecated-dropdown :text="value">
<gl-search-box-by-type v-model.trim="searchTerm" class="m-2" />
<gl-search-box-by-type v-model.trim="searchTerm" class="gl-m-3" />
<gl-deprecated-dropdown-item
v-for="environment in filteredResults"
:key="environment"
......
......@@ -130,7 +130,7 @@ export default {
<gl-search-box-by-type
v-model.trim="searchQuery"
:placeholder="s__('ClusterIntegration|Search domains')"
class="m-2"
class="gl-m-3"
/>
<gl-deprecated-dropdown-item
v-for="domain in filteredDomains"
......
......@@ -23,6 +23,7 @@ import { addInProgressImportToStore } from '../utils/cache_update';
import {
debounceWait,
dropdownLabel,
userMappingsPageSize,
previousImportsMessage,
tableConfig,
userMappingMessage,
......@@ -74,12 +75,15 @@ export default {
},
data() {
return {
hasMoreUsers: false,
isFetching: false,
isLoadingMoreUsers: false,
isSubmitting: false,
searchTerm: '',
selectedProject: undefined,
selectState: null,
userMappings: [],
userMappingsStartAt: 0,
users: [],
};
},
......@@ -101,6 +105,9 @@ export default {
? `jira-import::${this.selectedProject}-${this.numberOfPreviousImports + 1}`
: 'jira-import::KEY-1';
},
isInitialLoadingState() {
return this.isLoadingMoreUsers && !this.hasMoreUsers;
},
},
watch: {
searchTerm: debounce(function debouncedUserSearch() {
......@@ -108,23 +115,7 @@ export default {
}, debounceWait),
},
mounted() {
this.$apollo
.mutate({
mutation: getJiraUserMappingMutation,
variables: {
input: {
projectPath: this.projectPath,
},
},
})
.then(({ data }) => {
if (data.jiraImportUsers.errors.length) {
this.$emit('error', data.jiraImportUsers.errors.join('. '));
} else {
this.userMappings = data.jiraImportUsers.jiraUsers;
}
})
.catch(() => this.$emit('error', __('There was an error retrieving the Jira users.')));
this.getJiraUserMapping();
this.searchUsers()
.then(data => {
......@@ -133,6 +124,36 @@ export default {
.catch(() => {});
},
methods: {
getJiraUserMapping() {
this.isLoadingMoreUsers = true;
this.$apollo
.mutate({
mutation: getJiraUserMappingMutation,
variables: {
input: {
projectPath: this.projectPath,
startAt: this.userMappingsStartAt,
},
},
})
.then(({ data }) => {
if (data.jiraImportUsers.errors.length) {
this.$emit('error', data.jiraImportUsers.errors.join('. '));
return;
}
this.userMappings = this.userMappings.concat(data.jiraImportUsers.jiraUsers);
this.hasMoreUsers = data.jiraImportUsers.jiraUsers.length === userMappingsPageSize;
this.userMappingsStartAt += userMappingsPageSize;
})
.catch(() => {
this.$emit('error', __('There was an error retrieving the Jira users.'));
})
.finally(() => {
this.isLoadingMoreUsers = false;
});
},
searchUsers() {
const params = {
active: true,
......@@ -187,7 +208,9 @@ export default {
this.selectedProject = undefined;
}
})
.catch(() => this.$emit('error', __('There was an error importing the Jira project.')))
.catch(() => {
this.$emit('error', __('There was an error importing the Jira project.'));
})
.finally(() => {
this.isSubmitting = false;
});
......@@ -278,11 +301,9 @@ export default {
"
@hide="resetDropdown"
>
<gl-search-box-by-type v-model.trim="searchTerm" class="m-2" />
<gl-search-box-by-type v-model.trim="searchTerm" class="gl-m-3" />
<div v-if="isFetching" class="gl-text-center">
<gl-loading-icon />
</div>
<gl-loading-icon v-if="isFetching" />
<gl-new-dropdown-item
v-for="user in users"
......@@ -300,6 +321,17 @@ export default {
</template>
</gl-table>
<gl-loading-icon v-if="isInitialLoadingState" />
<gl-button
v-if="hasMoreUsers"
:loading="isLoadingMoreUsers"
data-testid="load-more-users-button"
@click="getJiraUserMapping"
>
{{ __('Load more users') }}
</gl-button>
<div class="footer-block row-content-block d-flex justify-content-between">
<gl-button
type="submit"
......
......@@ -27,3 +27,6 @@ export const tableConfig = [
export const userMappingMessage = __(`Jira users have been imported from the configured Jira
instance. They can be mapped by selecting a GitLab user from the dropdown in the "GitLab username"
column. When the form appears, the dropdown defaults to the user conducting the import.`);
// pageSize must match the MAX_USERS value in app/services/jira_import/users_mapper_service.rb
export const userMappingsPageSize = 50;
......@@ -184,7 +184,7 @@ export default {
<gl-search-box-by-type
v-model.trim="searchQuery"
class="m-2"
class="gl-m-3"
:placeholder="this.$options.translations.searchMilestones"
@input="searchMilestones"
/>
......
......@@ -192,7 +192,7 @@ export default {
>
<div class="d-flex flex-column overflow-hidden">
<gl-new-dropdown-header>{{ __('Environment') }}</gl-new-dropdown-header>
<gl-search-box-by-type class="m-2" @input="debouncedEnvironmentsSearch" />
<gl-search-box-by-type class="gl-m-3" @input="debouncedEnvironmentsSearch" />
<gl-loading-icon v-if="environmentsLoading" :inline="true" />
<div v-else class="flex-fill overflow-auto">
......
......@@ -83,7 +83,7 @@ export default {
<gl-search-box-by-type
ref="monitorDashboardsDropdownSearch"
v-model="searchTerm"
class="m-2"
class="gl-m-3"
/>
<div class="flex-fill overflow-auto">
......
import setup from 'ee_else_ce/admin/application_settings/setup_metrics_and_profiling';
import setup from '~/admin/application_settings/setup_metrics_and_profiling';
document.addEventListener('DOMContentLoaded', setup);
......@@ -3,9 +3,9 @@ import { __ } from '../../../locale';
import { deprecatedCreateFlash as flash } from '../../../flash';
export default class PayloadPreviewer {
constructor(trigger, container) {
constructor(trigger) {
this.trigger = trigger;
this.container = container;
this.container = document.querySelector(trigger.dataset.payloadSelector);
this.isVisible = false;
this.isInserted = false;
}
......
......@@ -119,7 +119,7 @@ export default {
<gl-new-dropdown-divider />
<gl-search-box-by-type
v-model.trim="authorInput"
class="m-2"
class="gl-m-3"
:placeholder="__('Search')"
@input="searchAuthors"
/>
......
......@@ -63,7 +63,7 @@ export default {
return this.actions.length > 0;
},
hasValidBlobs() {
return this.actions.every(x => x.filePath && x.content);
return this.actions.every(x => x.content);
},
updatePrevented() {
return this.snippet.title === '' || !this.hasValidBlobs || this.isUpdating;
......
......@@ -11,7 +11,7 @@ import {
import axios from '../lib/utils/axios_utils';
import { s__, __, sprintf } from '../locale';
import ModalStore from '../boards/stores/modal_store';
import { parseBoolean } from '../lib/utils/common_utils';
import { parseBoolean, spriteIcon } from '../lib/utils/common_utils';
import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
......@@ -225,7 +225,9 @@ function UsersSelect(currentUser, els, options = {}) {
});
};
collapsedAssigneeTemplate = template(
'<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> <i class="fa fa-user"></i> <% } %>',
`<% if( avatar ) { %> <a class="author-link" href="/<%- username %>"> <img width="24" class="avatar avatar-inline s24" alt="" src="<%- avatar %>"> </a> <% } else { %> ${spriteIcon(
'user',
)} <% } %>`,
);
assigneeTemplate = template(
`<% if (username) { %> <a class="author-link bold" href="/<%- username %>"> <% if( avatar ) { %> <img width="32" class="avatar avatar-inline s32" alt="" src="<%- avatar %>"> <% } %> <span class="author"><%- name %></span> <span class="username"> @<%- username %> </span> </a> <% } else { %> <span class="no-value assign-yourself">
......
......@@ -130,10 +130,6 @@
content: '\f101';
}
.fa-trash::before {
content: '\f1f8';
}
.fa-angle-double-left::before {
content: '\f100';
}
......@@ -186,10 +182,6 @@
content: '\f1a0';
}
.fa-user::before {
content: '\f007';
}
.fa-exclamation-circle::before {
content: '\f06a';
}
......@@ -210,10 +202,6 @@
content: '\f016';
}
.fa-users::before {
content: '\f0c0';
}
.fa-tags::before {
content: '\f02c';
}
......@@ -266,10 +254,6 @@
content: '\f061';
}
.fa-user-secret::before {
content: '\f21b';
}
.fa-search-plus::before {
content: '\f00e';
}
......
......@@ -16,12 +16,11 @@ def edit
def update
saved = integration.update(service_params[:service])
overwrite = Gitlab::Utils.to_boolean(params[:overwrite])
respond_to do |format|
format.html do
if saved
PropagateIntegrationWorker.perform_async(integration.id, overwrite)
PropagateIntegrationWorker.perform_async(integration.id, false)
redirect_to scoped_edit_integration_path(integration), notice: success_message
else
render 'shared/integrations/edit'
......
......@@ -93,9 +93,10 @@ def edit
def update
return render('shared/wikis/empty') unless can?(current_user, :create_wiki, container)
@page = WikiPages::UpdateService.new(container: container, current_user: current_user, params: wiki_params).execute(page)
response = WikiPages::UpdateService.new(container: container, current_user: current_user, params: wiki_params).execute(page)
@page = response.payload[:page]
if page.valid?
if response.success?
redirect_to(
wiki_page_path(wiki, page),
notice: _('Wiki was successfully updated.')
......
# frozen_string_literal: true
module Mutations
module Ci
class Base < BaseMutation
argument :id, ::Types::GlobalIDType[::Ci::Pipeline],
required: true,
description: 'The id of the pipeline to mutate'
private
def find_object(id:)
GlobalID::Locator.locate(id)
end
end
end
end
# frozen_string_literal: true
module Mutations
module Ci
class PipelineCancel < BaseMutation
graphql_name 'PipelineCancel'
authorize :update_pipeline
def resolve
result = ::Ci::CancelUserPipelinesService.new.execute(current_user)
{
success: result.success?,
errors: [result&.message]
}
end
end
end
end
# frozen_string_literal: true
module Mutations
module Ci
class PipelineDestroy < Base
graphql_name 'PipelineDestroy'
authorize :destroy_pipeline
def resolve(id:)
pipeline = authorized_find!(id: id)
project = pipeline.project
result = ::Ci::DestroyPipelineService.new(project, current_user).execute(pipeline)
{
success: result.success?,
errors: result.errors
}
end
end
end
end