Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
27622f7417
commit
9b14160725
|
@ -7,6 +7,7 @@ stages:
|
|||
- post-test
|
||||
- review-prepare
|
||||
- review
|
||||
- dast
|
||||
- qa
|
||||
- post-qa
|
||||
- pages
|
||||
|
@ -104,3 +105,4 @@ include:
|
|||
- local: .gitlab/ci/yaml.gitlab-ci.yml
|
||||
- local: .gitlab/ci/releases.gitlab-ci.yml
|
||||
- local: .gitlab/ci/notify.gitlab-ci.yml
|
||||
- local: .gitlab/ci/dast.gitlab-ci.yml
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
.dast_conf:
|
||||
tags:
|
||||
- prm
|
||||
# For scheduling dast job
|
||||
extends:
|
||||
- .reports:schedule-dast
|
||||
image:
|
||||
name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION"
|
||||
resource_group: dast_scan
|
||||
variables:
|
||||
DAST_USERNAME_FIELD: "user[login]"
|
||||
DAST_PASSWORD_FIELD: "user[password]"
|
||||
DAST_FULL_SCAN_ENABLED: "true"
|
||||
DAST_SPIDER_MINS: 0
|
||||
# TBD pin to a version
|
||||
DAST_VERSION: 1.22.1
|
||||
# -Xmx is used to set the JVM memory to 6GB to prevent DAST OutOfMemoryError.
|
||||
DAST_ZAP_CLI_OPTIONS: "-Xmx6144m"
|
||||
DAST_RULES: "41,42,43,10027,10032,10041,10042,10045,10047,10052,10053,10057,10061,10096,10097,10104,10106,20012,20014,20015,20016,20017,20018,40019,40020,40021,40024,40025,40027,40029,40032,90001,90019,10109,10026,10028,10029,10030,10031,10033,10034,10035,10036,10038,10039,10043,10044,10048,10050,10051,10058,10062,10095,10107,10108,30003,40013,40022,40023,40028,90021,90023,90024,90025,90027,90028,10003,50003,0,2,3,6,7,10010,10011,10015,10017,10019,10020,10021,10023,10024,10025,10037,10040,10054,10055,10056,10098,10105,10202,20019,30001,30002,40003,40008,40009,40012,40014,40016,40017,40018,50000,50001,90011,90020,90022,90033"
|
||||
before_script:
|
||||
- 'export DAST_WEBSITE="${DAST_WEBSITE:-$(cat environment_url.txt)}"'
|
||||
- 'export DAST_AUTH_URL="${DAST_WEBSITE}/users/sign_in"'
|
||||
- 'export DAST_PASSWORD="${REVIEW_APPS_ROOT_PASSWORD}"'
|
||||
# Below three lines can be removed once https://gitlab.com/gitlab-org/gitlab/-/issues/230687 is fixed
|
||||
- mkdir -p /zap/xml
|
||||
- 'sed -i "84 s/true/false/" /zap/xml/config.xml'
|
||||
- cat /zap/xml/config.xml
|
||||
# Help pages are excluded from scan as they are static pages.
|
||||
# profile/two_factor_auth is excluded from scan to prevent 2FA from being turned on from user profile, which will reduce coverage.
|
||||
- 'export DAST_AUTH_EXCLUDE_URLS="${DAST_WEBSITE}/help/.*,${DAST_WEBSITE}/profile/two_factor_auth,${DAST_WEBSITE}/users/sign_out"'
|
||||
- enable_rule () { read all_rules; rule=$1; echo $all_rules | sed -r "s/(,)?$rule(,)?/\1-1\2/" ; }
|
||||
# Sort ids in DAST_RULES ascendingly, which is required when using DAST_RULES as argument to enable_rule
|
||||
- 'DAST_RULES=$(echo $DAST_RULES | tr "," "\n" | sort -n | paste -sd ",")'
|
||||
needs: ["review-deploy"]
|
||||
stage: dast
|
||||
# Default job timeout set to 90m and dast rules needs 2h to so that it won't timeout.
|
||||
timeout: 2h
|
||||
artifacts:
|
||||
paths:
|
||||
- gl-dast-report.json # GitLab-specific
|
||||
reports:
|
||||
dast: gl-dast-report.json
|
||||
expire_in: 1 week # GitLab-specific
|
||||
|
||||
# DAST scan with a subset of Release scan rules.
|
||||
DAST-fullscan-ruleset1:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user1"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 10019 | enable_rule 10020 | enable_rule 10021 | enable_rule 10023 | enable_rule 10024 | enable_rule 10025 | enable_rule 10037 | enable_rule 10040 | enable_rule 10054 | enable_rule 10055 | enable_rule 10056)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with a subset of Release scan rules.
|
||||
DAST-fullscan-ruleset2:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user2"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 90011 | enable_rule 90020 | enable_rule 90022 | enable_rule 90033)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with a subset of Release scan rules.
|
||||
DAST-fullscan-ruleset3:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user3"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 40016 | enable_rule 40017 | enable_rule 50000 | enable_rule 50001)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with a subset of Release scan rules.
|
||||
DAST-fullscan-ruleset4:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user4"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 0 | enable_rule 2 | enable_rule 3 | enable_rule 7 )
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with a subset of Release scan rules.
|
||||
DAST-fullscan-ruleset5:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user5"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 10010 | enable_rule 10011 | enable_rule 10015 | enable_rule 10017 | enable_rule 10019)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with a subset of Release scan rules.
|
||||
DAST-fullscan-ruleset6:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user6"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 30001 | enable_rule 40009)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# Enable when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39749 is fixed
|
||||
# DAST scan with a subset of Beta scan rules.
|
||||
# DAST-fullscan-ruleset7:
|
||||
# extends:
|
||||
# - .dast_conf
|
||||
# variables:
|
||||
# DAST_USERNAME: "user7"
|
||||
# script:
|
||||
# - export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 10098 | enable_rule 10105 | enable_rule 10202 | enable_rule 30002 | enable_rule 40003 | enable_rule 40008 | enable_rule 40009)
|
||||
# - echo $DAST_EXCLUDE_RULES
|
||||
# - /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# Enable when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39749 is fixed
|
||||
# Below jobs runs DAST scans with one time consuming scan rule. These scan rules are disabled in above jobs so that those jobs won't timeout.
|
||||
# DAST scan with rule - 20019 External Redirect
|
||||
# DAST-fullscan-rule-20019:
|
||||
# extends:
|
||||
# - .dast_conf
|
||||
# variables:
|
||||
# DAST_USERNAME: "user8"
|
||||
# script:
|
||||
# - export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 20019)
|
||||
# - echo $DAST_EXCLUDE_RULES
|
||||
# - /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# Enable when https://gitlab.com/gitlab-org/gitlab/-/merge_requests/39749 is fixed
|
||||
# DAST scan with rule - 10107 Httpoxy - Proxy Header Misuse - Active/beta
|
||||
# DAST-fullscan-rule-10107:
|
||||
# extends:
|
||||
# - .dast_conf
|
||||
# variables:
|
||||
# DAST_USERNAME: "user9"
|
||||
# script:
|
||||
# - export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 10107)
|
||||
# - echo $DAST_EXCLUDE_RULES
|
||||
# - /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with rule - 90020 Remote OS Command Injection
|
||||
DAST-fullscan-rule-90020:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user10"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 90020)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with rule - 40018 SQL Injection - Active/release
|
||||
DAST-fullscan-rule-40018:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user11"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 40018)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with rule - 40014 Cross Site Scripting (Persistent) - Active/release
|
||||
DAST-fullscan-rule-40014:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user12"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 40014)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with rule - 6 Path travesal
|
||||
DAST-fullscan-rule-6:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user13"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 6)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
||||
|
||||
# DAST scan with rule - 40012 Cross Site Scripting (Reflected)
|
||||
DAST-fullscan-rule-40012:
|
||||
extends:
|
||||
- .dast_conf
|
||||
variables:
|
||||
DAST_USERNAME: "user14"
|
||||
script:
|
||||
- export DAST_EXCLUDE_RULES=$(echo $DAST_RULES | enable_rule 40012)
|
||||
- echo $DAST_EXCLUDE_RULES
|
||||
- /analyze -t $DAST_WEBSITE -d
|
|
@ -145,45 +145,3 @@ dependency_scanning:
|
|||
reports:
|
||||
dependency_scanning: gl-dependency-scanning-report.json
|
||||
expire_in: 1 week # GitLab-specific
|
||||
|
||||
# Temporarily disabling review apps
|
||||
## We need to duplicate this job's definition because it seems it's impossible to
|
||||
## override an included `only.refs`.
|
||||
## See https://gitlab.com/gitlab-org/gitlab/issues/31371.
|
||||
# dast:
|
||||
# extends:
|
||||
# - .default-retry
|
||||
# - .reports:rules:dast
|
||||
# # This is needed so that manual jobs with needs don't block the pipeline.
|
||||
# # See https://gitlab.com/gitlab-org/gitlab/-/issues/199979.
|
||||
# dependencies: ["review-deploy"]
|
||||
# stage: qa # GitLab-specific
|
||||
# image:
|
||||
# name: "registry.gitlab.com/gitlab-org/security-products/dast:$DAST_VERSION"
|
||||
# variables:
|
||||
# # To be done in a later iteration
|
||||
# # DAST_USERNAME: "root"
|
||||
# # DAST_USERNAME_FIELD: "user[login]"
|
||||
# # DAST_PASSWORD_FIELD: "user[passowrd]"
|
||||
# DAST_VERSION: 1
|
||||
# script:
|
||||
# - 'export DAST_WEBSITE="${DAST_WEBSITE:-$(cat environment_url.txt)}"'
|
||||
# # To be done in a later iteration
|
||||
# # - 'export DAST_AUTH_URL="${DAST_WEBSITE}/users/sign_in"'
|
||||
# # - 'export DAST_PASSWORD="${REVIEW_APPS_ROOT_PASSWORD}"'
|
||||
# - /analyze -t $DAST_WEBSITE
|
||||
# timeout: 4h
|
||||
# artifacts:
|
||||
# paths:
|
||||
# - gl-dast-report.json # GitLab-specific
|
||||
# reports:
|
||||
# dast: gl-dast-report.json
|
||||
# expire_in: 1 week # GitLab-specific
|
||||
|
||||
# To be done in a later iteration: https://gitlab.com/gitlab-org/gitlab/issues/31160#note_278188255
|
||||
# schedule:dast:
|
||||
# extends:
|
||||
# - dast
|
||||
# - .reports:schedule-dast
|
||||
# variables:
|
||||
# DAST_FULL_SCAN_ENABLED: "true"
|
||||
|
|
|
@ -77,6 +77,11 @@ review-deploy:
|
|||
# to have to manually start the jobs in sequence, so we do it for them.
|
||||
- '[ -z $CI_JOB_MANUAL ] || play_job "review-qa-smoke"'
|
||||
- '[ -z $CI_JOB_MANUAL ] || play_job "review-performance"'
|
||||
after_script:
|
||||
# Run seed-dast-test-data.sh only when DAST_RUN is set to true. This is to pupulate review app with data for DAST scan.
|
||||
# Set DAST_RUN to true when jobs are manually scheduled.
|
||||
- if [ "$DAST_RUN" == "true" ]; then source scripts/review_apps/seed-dast-test-data.sh; TRACE=1 trigger_proj_user_creation; fi
|
||||
|
||||
artifacts:
|
||||
paths: [environment_url.txt]
|
||||
expire_in: 2 days
|
||||
|
|
|
@ -645,6 +645,7 @@
|
|||
- if: '$DAST_DISABLED || $GITLAB_FEATURES !~ /\bdast\b/'
|
||||
when: never
|
||||
- <<: *if-dot-com-gitlab-org-schedule
|
||||
allow_failure: true
|
||||
|
||||
################
|
||||
# Review rules #
|
||||
|
@ -665,6 +666,8 @@
|
|||
|
||||
.review:rules:mr-and-schedule-auto-if-frontend-manual-otherwise:
|
||||
rules:
|
||||
- if: '$DAST_RUN == "true"' # Skip this job when DAST is run
|
||||
when: never
|
||||
- <<: *if-not-ee
|
||||
when: never
|
||||
- <<: *if-dot-com-gitlab-org-merge-request
|
||||
|
|
|
@ -68,10 +68,10 @@ a nightly pipeline, select ~"found:nightly".
|
|||
|
||||
<!--
|
||||
https://about.gitlab.com/handbook/engineering/quality/guidelines/#priorities:
|
||||
- ~P::1: Tests that are needed to verify fundamental GitLab functionality.
|
||||
- ~P::2: Tests that deal with external integrations which may take a longer time to debug and fix.
|
||||
- ~"priority::1": Tests that are needed to verify fundamental GitLab functionality.
|
||||
- ~"priority::2": Tests that deal with external integrations which may take a longer time to debug and fix.
|
||||
-->
|
||||
/label ~P::
|
||||
/label ~priority::
|
||||
|
||||
<!-- Select the current milestone if ~P::1 or the next milestone if ~P::2. -->
|
||||
<!-- Select the current milestone if ~"priority::1" or the next milestone if ~"priority::2". -->
|
||||
/milestone %
|
||||
|
|
|
@ -23,7 +23,6 @@ See [the general developer security release guidelines](https://gitlab.com/gitla
|
|||
- [ ] Ensure it's approved by an AppSec engineer.
|
||||
- If you're unsure who should approve, find the AppSec engineer associated to the issue in the [Canonical repository], or ask #sec-appsec on Slack.
|
||||
- Trigger the [`package-and-qa` build]. The docker image generated will be used by the AppSec engineer to validate the security vulnerability has been remediated.
|
||||
- [ ] Merge request _must_ close the corresponding security issue.
|
||||
- [ ] For a backport MR targeting a versioned stable branch (`X-Y-stable-ee`)
|
||||
- [ ] Ensure it's approved by a maintainer.
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { mapActions, mapGetters, mapState } from 'vuex';
|
||||
import { GlLoadingIcon, GlIcon } from '@gitlab/ui';
|
||||
import { GlLoadingIcon, GlButton, GlIcon } from '@gitlab/ui';
|
||||
import { sprintf, n__ } from '~/locale';
|
||||
import DraftsCount from './drafts_count.vue';
|
||||
import PublishButton from './publish_button.vue';
|
||||
|
@ -9,6 +9,7 @@ import PreviewItem from './preview_item.vue';
|
|||
export default {
|
||||
components: {
|
||||
GlLoadingIcon,
|
||||
GlButton,
|
||||
GlIcon,
|
||||
DraftsCount,
|
||||
PublishButton,
|
||||
|
@ -28,7 +29,7 @@ export default {
|
|||
watch: {
|
||||
showPreviewDropdown() {
|
||||
if (this.showPreviewDropdown && this.$refs.dropdown) {
|
||||
this.$nextTick(() => this.$refs.dropdown.focus());
|
||||
this.$nextTick(() => this.$refs.dropdown.$el.focus());
|
||||
}
|
||||
},
|
||||
},
|
||||
|
@ -62,16 +63,18 @@ export default {
|
|||
show: showPreviewDropdown,
|
||||
}"
|
||||
>
|
||||
<button
|
||||
<gl-button
|
||||
ref="dropdown"
|
||||
type="button"
|
||||
class="btn btn-success review-preview-dropdown-toggle qa-review-preview-toggle"
|
||||
category="primary"
|
||||
variant="success"
|
||||
class="review-preview-dropdown-toggle qa-review-preview-toggle"
|
||||
@click="toggleReviewDropdown"
|
||||
>
|
||||
{{ __('Finish review') }}
|
||||
<drafts-count />
|
||||
<gl-icon name="angle-up" />
|
||||
</button>
|
||||
</gl-button>
|
||||
<div
|
||||
class="dropdown-menu dropdown-menu-large dropdown-menu-right dropdown-open-top"
|
||||
:class="{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable class-methods-use-this */
|
||||
|
||||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class TemplateSelector {
|
||||
constructor({ dropdown, data, pattern, wrapper, editor, $input } = {}) {
|
||||
|
@ -19,7 +19,7 @@ export default class TemplateSelector {
|
|||
}
|
||||
|
||||
initDropdown(dropdown, data) {
|
||||
return $(dropdown).glDropdown({
|
||||
return initDeprecatedJQueryDropdown($(dropdown), {
|
||||
data,
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import FileTemplateSelector from '../file_template_selector';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class BlobCiYamlSelector extends FileTemplateSelector {
|
||||
constructor({ mediator }) {
|
||||
|
@ -15,7 +16,7 @@ export default class BlobCiYamlSelector extends FileTemplateSelector {
|
|||
|
||||
initDropdown() {
|
||||
// maybe move to super class as well
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.$dropdown.data('data'),
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import FileTemplateSelector from '../file_template_selector';
|
||||
import { __ } from '~/locale';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class DockerfileSelector extends FileTemplateSelector {
|
||||
constructor({ mediator }) {
|
||||
|
@ -16,7 +17,7 @@ export default class DockerfileSelector extends FileTemplateSelector {
|
|||
|
||||
initDropdown() {
|
||||
// maybe move to super class as well
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.$dropdown.data('data'),
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import FileTemplateSelector from '../file_template_selector';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class BlobGitignoreSelector extends FileTemplateSelector {
|
||||
constructor({ mediator }) {
|
||||
|
@ -14,7 +15,7 @@ export default class BlobGitignoreSelector extends FileTemplateSelector {
|
|||
}
|
||||
|
||||
initDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.$dropdown.data('data'),
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import FileTemplateSelector from '../file_template_selector';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class BlobLicenseSelector extends FileTemplateSelector {
|
||||
constructor({ mediator }) {
|
||||
|
@ -14,7 +15,7 @@ export default class BlobLicenseSelector extends FileTemplateSelector {
|
|||
}
|
||||
|
||||
initDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.$dropdown.data('data'),
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import FileTemplateSelector from '../file_template_selector';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class MetricsDashboardSelector extends FileTemplateSelector {
|
||||
constructor({ mediator }) {
|
||||
|
@ -14,7 +15,7 @@ export default class MetricsDashboardSelector extends FileTemplateSelector {
|
|||
}
|
||||
|
||||
initDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.$dropdown.data('data'),
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import FileTemplateSelector from '../file_template_selector';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class FileTemplateTypeSelector extends FileTemplateSelector {
|
||||
constructor({ mediator, dropdownData }) {
|
||||
|
@ -12,7 +13,7 @@ export default class FileTemplateTypeSelector extends FileTemplateSelector {
|
|||
}
|
||||
|
||||
initDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.config.dropdownData,
|
||||
filterable: false,
|
||||
selectable: true,
|
||||
|
|
|
@ -83,7 +83,7 @@ export default Vue.extend({
|
|||
|
||||
$('.js-issue-board-sidebar', this.$el).each((i, el) => {
|
||||
$(el)
|
||||
.data('glDropdown')
|
||||
.data('deprecatedJQueryDropdown')
|
||||
.clearMenu();
|
||||
});
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ export default Vue.extend({
|
|||
},
|
||||
},
|
||||
created() {
|
||||
// Get events from glDropdown
|
||||
// Get events from deprecatedJQueryDropdown
|
||||
eventHub.$on('sidebar.removeAssignee', this.removeAssignee);
|
||||
eventHub.$on('sidebar.addAssignee', this.addAssignee);
|
||||
eventHub.$on('sidebar.removeAllAssignees', this.removeAllAssignees);
|
||||
|
|
|
@ -6,6 +6,7 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import { deprecatedCreateFlash as flash } from '~/flash';
|
||||
import CreateLabelDropdown from '../../create_label';
|
||||
import boardsStore from '../stores/boards_store';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
$(document)
|
||||
.off('created.label')
|
||||
|
@ -36,7 +37,7 @@ export default function initNewListDropdown() {
|
|||
$dropdownToggle.data('projectPath'),
|
||||
);
|
||||
|
||||
$dropdownToggle.glDropdown({
|
||||
initDeprecatedJQueryDropdown($dropdownToggle, {
|
||||
data(term, callback) {
|
||||
axios
|
||||
.get($dropdownToggle.attr('data-list-labels-path'))
|
||||
|
|
|
@ -6,6 +6,7 @@ import { __ } from '~/locale';
|
|||
import eventHub from '../eventhub';
|
||||
import Api from '../../api';
|
||||
import { featureAccessLevel } from '~/pages/projects/shared/permissions/constants';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default {
|
||||
name: 'BoardProjectSelect',
|
||||
|
@ -36,7 +37,7 @@ export default {
|
|||
},
|
||||
},
|
||||
mounted() {
|
||||
$(this.$refs.projectsDropdown).glDropdown({
|
||||
initDeprecatedJQueryDropdown($(this.$refs.projectsDropdown), {
|
||||
filterable: true,
|
||||
filterRemote: true,
|
||||
search: {
|
||||
|
|
|
@ -53,7 +53,7 @@ export default class VariableList {
|
|||
},
|
||||
environment_scope: {
|
||||
// We can't use a `.js-` class here because
|
||||
// gl_dropdown replaces the <input> and doesn't copy over the class
|
||||
// deprecated_jquery_dropdown replaces the <input> and doesn't copy over the class
|
||||
// See https://gitlab.com/gitlab-org/gitlab-foss/issues/42458
|
||||
selector: `input[name="${this.formField}[variables_attributes][][environment_scope]"]`,
|
||||
default: '*',
|
||||
|
|
|
@ -5,6 +5,7 @@ import { __ } from './locale';
|
|||
import axios from './lib/utils/axios_utils';
|
||||
import { deprecatedCreateFlash as flash } from './flash';
|
||||
import { capitalizeFirstCharacter } from './lib/utils/text_utility';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default function initCompareAutocomplete(limitTo = null, clickHandler = () => {}) {
|
||||
$('.js-compare-dropdown').each(function() {
|
||||
|
@ -13,7 +14,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = (
|
|||
const $dropdownContainer = $dropdown.closest('.dropdown');
|
||||
const $fieldInput = $(`input[name="${$dropdown.data('fieldName')}"]`, $dropdownContainer);
|
||||
const $filterInput = $('input[type="search"]', $dropdownContainer);
|
||||
$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown($dropdown, {
|
||||
data(term, callback) {
|
||||
const params = {
|
||||
ref: $dropdown.data('ref'),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { escape } from 'lodash';
|
||||
import '~/gl_dropdown';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class CreateItemDropdown {
|
||||
/**
|
||||
|
@ -28,7 +28,7 @@ export default class CreateItemDropdown {
|
|||
}
|
||||
|
||||
buildDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.getData.bind(this),
|
||||
filterable: true,
|
||||
filterRemote: this.getDataRemote,
|
||||
|
@ -67,12 +67,12 @@ export default class CreateItemDropdown {
|
|||
e.preventDefault();
|
||||
|
||||
this.refreshData();
|
||||
this.$dropdown.data('glDropdown').selectRowAtIndex();
|
||||
this.$dropdown.data('deprecatedJQueryDropdown').selectRowAtIndex();
|
||||
}
|
||||
|
||||
refreshData() {
|
||||
// Refresh the dropdown's data, which ends up calling `getData`
|
||||
this.$dropdown.data('glDropdown').remote.execute();
|
||||
this.$dropdown.data('deprecatedJQueryDropdown').remote.execute();
|
||||
}
|
||||
|
||||
getData(term, callback) {
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
import $ from 'jquery';
|
||||
import { escape } from 'lodash';
|
||||
import fuzzaldrinPlus from 'fuzzaldrin-plus';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import axios from '../lib/utils/axios_utils';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { isObject } from './lib/utils/type_utility';
|
||||
import renderItem from './gl_dropdown/render';
|
||||
import { isObject } from '~/lib/utils/type_utility';
|
||||
import renderItem from './render';
|
||||
|
||||
const BLUR_KEYCODES = [27, 40];
|
||||
|
||||
|
@ -890,12 +890,11 @@ class GitLabDropdown {
|
|||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line func-names
|
||||
$.fn.glDropdown = function(opts) {
|
||||
export default function initDeprecatedJQueryDropdown($el, opts) {
|
||||
// eslint-disable-next-line func-names
|
||||
return this.each(function() {
|
||||
if (!$.data(this, 'glDropdown')) {
|
||||
return $.data(this, 'glDropdown', new GitLabDropdown(this, opts));
|
||||
return $el.each(function() {
|
||||
if (!$.data(this, 'deprecatedJQueryDropdown')) {
|
||||
$.data(this, 'deprecatedJQueryDropdown', new GitLabDropdown(this, opts));
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
|
@ -6,6 +6,7 @@ import { __ } from '~/locale';
|
|||
import axios from './lib/utils/axios_utils';
|
||||
import { timeFor, parsePikadayDate, pikadayToString } from './lib/utils/datetime_utility';
|
||||
import boardsStore from './boards/stores/boards_store';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
class DueDateSelect {
|
||||
constructor({ $dropdown, $loading } = {}) {
|
||||
|
@ -35,7 +36,7 @@ class DueDateSelect {
|
|||
}
|
||||
|
||||
initGlDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
opened: () => {
|
||||
const calendar = this.$datePicker.data('pikaday');
|
||||
calendar.show();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import $ from 'jquery';
|
||||
import { __ } from '~/locale';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class TransferDropdown {
|
||||
constructor() {
|
||||
|
@ -16,7 +17,7 @@ export default class TransferDropdown {
|
|||
buildDropdown() {
|
||||
const extraOptions = [{ id: '-1', text: __('No parent group') }, { type: 'divider' }];
|
||||
|
||||
this.groupDropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.groupDropdown, {
|
||||
selectable: true,
|
||||
filterable: true,
|
||||
toggleLabel: item => item.text,
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<script>
|
||||
import { mapActions, mapState } from 'vuex';
|
||||
import tooltip from '~/vue_shared/directives/tooltip';
|
||||
import Icon from '~/vue_shared/components/icon.vue';
|
||||
import IdeSidebarNav from '../ide_sidebar_nav.vue';
|
||||
|
||||
export default {
|
||||
|
@ -10,7 +9,6 @@ export default {
|
|||
tooltip,
|
||||
},
|
||||
components: {
|
||||
Icon,
|
||||
IdeSidebarNav,
|
||||
},
|
||||
props: {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import $ from 'jquery';
|
||||
import { stickyMonitor } from './lib/utils/sticky';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default stickyTop => {
|
||||
stickyMonitor(document.querySelector('.js-diff-files-changed'), stickyTop);
|
||||
|
||||
$('.js-diff-stats-dropdown').glDropdown({
|
||||
initDeprecatedJQueryDropdown($('.js-diff-stats-dropdown'), {
|
||||
filterable: true,
|
||||
remoteFilter: false,
|
||||
});
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import $ from 'jquery';
|
||||
import { __ } from './locale';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default function issueStatusSelect() {
|
||||
$('.js-issue-status').each((i, el) => {
|
||||
const fieldName = $(el).data('fieldName');
|
||||
return $(el).glDropdown({
|
||||
initDeprecatedJQueryDropdown($(el), {
|
||||
selectable: true,
|
||||
fieldName,
|
||||
toggleLabel(selected, element, instance) {
|
||||
|
|
|
@ -12,6 +12,7 @@ import { deprecatedCreateFlash as flash } from './flash';
|
|||
import ModalStore from './boards/stores/modal_store';
|
||||
import boardsStore from './boards/stores/boards_store';
|
||||
import { isScopedLabel } from '~/lib/utils/common_utils';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class LabelsSelect {
|
||||
constructor(els, options = {}) {
|
||||
|
@ -173,7 +174,7 @@ export default class LabelsSelect {
|
|||
})
|
||||
.catch(() => flash(__('Error saving label update.')));
|
||||
};
|
||||
$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown($dropdown, {
|
||||
showMenuAbove,
|
||||
data(term, callback) {
|
||||
const labelUrl = $dropdown.attr('data-labels');
|
||||
|
@ -203,7 +204,7 @@ export default class LabelsSelect {
|
|||
|
||||
callback(data);
|
||||
if (showMenuAbove) {
|
||||
$dropdown.data('glDropdown').positionMenuAbove();
|
||||
$dropdown.data('deprecatedJQueryDropdown').positionMenuAbove();
|
||||
}
|
||||
})
|
||||
.catch(() => flash(__('Error fetching labels.')));
|
||||
|
@ -348,7 +349,7 @@ export default class LabelsSelect {
|
|||
} else {
|
||||
if (!$dropdown.hasClass('js-filter-bulk-update')) {
|
||||
saveLabelData();
|
||||
$dropdown.data('glDropdown').clearMenu();
|
||||
$dropdown.data('deprecatedJQueryDropdown').clearMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -455,7 +456,7 @@ export default class LabelsSelect {
|
|||
if ($dropdown.hasClass('js-issue-board-sidebar')) {
|
||||
const previousSelection = $dropdown.attr('data-selected');
|
||||
this.selected = previousSelection ? previousSelection.split(',') : [];
|
||||
$dropdown.data('glDropdown').updateLabel();
|
||||
$dropdown.data('deprecatedJQueryDropdown').updateLabel();
|
||||
}
|
||||
},
|
||||
preserveContext: true,
|
||||
|
|
|
@ -22,7 +22,6 @@ import { getLocationHash, visitUrl } from './lib/utils/url_utility';
|
|||
// everything else
|
||||
import loadAwardsHandler from './awards_handler';
|
||||
import { deprecatedCreateFlash as Flash, removeFlashClickListener } from './flash';
|
||||
import './gl_dropdown';
|
||||
import initTodoToggle from './header';
|
||||
import initImporterStatus from './importer_status';
|
||||
import initLayoutNav from './layout_nav';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import $ from 'jquery';
|
||||
import { disableButtonIfEmptyField } from '~/lib/utils/common_utils';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class Members {
|
||||
constructor() {
|
||||
|
@ -37,7 +38,7 @@ export default class Members {
|
|||
$('.js-member-permissions-dropdown').each((i, btn) => {
|
||||
const $btn = $(btn);
|
||||
|
||||
$btn.glDropdown({
|
||||
initDeprecatedJQueryDropdown($btn, {
|
||||
selectable: true,
|
||||
isSelectable: (selected, $el) => this.dropdownIsSelectable(selected, $el),
|
||||
fieldName: $btn.data('fieldName'),
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import $ from 'jquery';
|
||||
import { template, escape } from 'lodash';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import '~/gl_dropdown';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
import Api from '~/api';
|
||||
import axios from './lib/utils/axios_utils';
|
||||
import { timeFor, parsePikadayDate, dateInWords } from './lib/utils/datetime_utility';
|
||||
|
@ -69,7 +69,7 @@ export default class MilestoneSelect {
|
|||
);
|
||||
milestoneLinkNoneTemplate = `<span class="no-value">${__('None')}</span>`;
|
||||
}
|
||||
return $dropdown.glDropdown({
|
||||
return initDeprecatedJQueryDropdown($dropdown, {
|
||||
showMenuAbove,
|
||||
data: (term, callback) => {
|
||||
let contextId = $dropdown.get(0).dataset.projectId;
|
||||
|
@ -138,7 +138,7 @@ export default class MilestoneSelect {
|
|||
|
||||
callback(extraOptions.concat(data));
|
||||
if (showMenuAbove) {
|
||||
$dropdown.data('glDropdown').positionMenuAbove();
|
||||
$dropdown.data('deprecatedJQueryDropdown').positionMenuAbove();
|
||||
}
|
||||
$(`[data-milestone-id="${selectedMilestone}"] > a`).addClass('is-active');
|
||||
});
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import Api from './api';
|
||||
import { mergeUrlParams } from './lib/utils/url_utility';
|
||||
import { parseBoolean } from '~/lib/utils/common_utils';
|
||||
import { __ } from './locale';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class NamespaceSelect {
|
||||
constructor(opts) {
|
||||
const isFilter = parseBoolean(opts.dropdown.dataset.isFilter);
|
||||
const fieldName = opts.dropdown.dataset.fieldName || 'namespace_id';
|
||||
|
||||
$(opts.dropdown).glDropdown({
|
||||
initDeprecatedJQueryDropdown($(opts.dropdown), {
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
filterRemote: true,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable class-methods-use-this, no-unneeded-ternary */
|
||||
|
||||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import UsersSelect from '~/users_select';
|
||||
import { isMetaClick } from '~/lib/utils/common_utils';
|
||||
|
@ -50,7 +50,7 @@ export default class Todos {
|
|||
}
|
||||
|
||||
initFilterDropdown($dropdown, fieldName, searchFields) {
|
||||
$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown($dropdown, {
|
||||
fieldName,
|
||||
selectable: true,
|
||||
filterable: searchFields ? true : false,
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import $ from 'jquery';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default () => {
|
||||
const $targetProjectDropdown = $('.js-target-project');
|
||||
$targetProjectDropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown($targetProjectDropdown, {
|
||||
selectable: true,
|
||||
fieldName: $targetProjectDropdown.data('fieldName'),
|
||||
filterable: true,
|
||||
|
@ -16,7 +17,7 @@ export default () => {
|
|||
$('.mr_target_commit').empty();
|
||||
const $targetBranchDropdown = $('.js-target-branch');
|
||||
$targetBranchDropdown.data('refsUrl', $el.data('refsUrl'));
|
||||
$targetBranchDropdown.data('glDropdown').clearMenu();
|
||||
$targetBranchDropdown.data('deprecatedJQueryDropdown').clearMenu();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class TargetBranchDropdown {
|
||||
constructor() {
|
||||
|
@ -10,7 +11,7 @@ export default class TargetBranchDropdown {
|
|||
}
|
||||
|
||||
initDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.formatBranchesList(),
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
const defaultTimezone = { name: 'UTC', offset: 0 };
|
||||
const defaults = {
|
||||
$inputEl: null,
|
||||
|
@ -42,7 +44,7 @@ export default class TimezoneDropdown {
|
|||
}
|
||||
|
||||
initDropdown() {
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.timezoneData,
|
||||
filterable: true,
|
||||
selectable: true,
|
||||
|
|
|
@ -8,6 +8,7 @@ import { serializeForm } from '~/lib/utils/forms';
|
|||
import axios from '~/lib/utils/axios_utils';
|
||||
import { deprecatedCreateFlash as flash } from '~/flash';
|
||||
import projectSelect from '../../project_select';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class Project {
|
||||
constructor() {
|
||||
|
@ -104,7 +105,7 @@ export default class Project {
|
|||
const action = $form.attr('action');
|
||||
const linkTarget = mergeUrlParams(serializeForm($form[0]), action);
|
||||
|
||||
return $dropdown.glDropdown({
|
||||
return initDeprecatedJQueryDropdown($dropdown, {
|
||||
data(term, callback) {
|
||||
axios
|
||||
.get($dropdown.data('refsUrl'), {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
import { deprecatedCreateFlash as Flash } from '~/flash';
|
||||
import Api from '~/api';
|
||||
import { __ } from '~/locale';
|
||||
|
@ -20,7 +20,7 @@ export default class Search {
|
|||
this.eventListeners();
|
||||
refreshCounts();
|
||||
|
||||
$groupDropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown($groupDropdown, {
|
||||
selectable: true,
|
||||
filterable: true,
|
||||
filterRemote: true,
|
||||
|
@ -46,7 +46,7 @@ export default class Search {
|
|||
clicked: () => Search.submitSearch(),
|
||||
});
|
||||
|
||||
$projectDropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown($projectDropdown, {
|
||||
selectable: true,
|
||||
filterable: true,
|
||||
filterRemote: true,
|
||||
|
|
|
@ -4,6 +4,7 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import { deprecatedCreateFlash as Flash } from '~/flash';
|
||||
import { n__, s__, __ } from '~/locale';
|
||||
import { LEVEL_TYPES, LEVEL_ID_PROP, ACCESS_LEVEL_NONE } from './constants';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class AccessDropdown {
|
||||
constructor(options) {
|
||||
|
@ -29,7 +30,7 @@ export default class AccessDropdown {
|
|||
|
||||
initDropdown() {
|
||||
const { onSelect, onHide } = this.options;
|
||||
this.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdown, {
|
||||
data: this.getData.bind(this),
|
||||
selectable: true,
|
||||
filterable: true,
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { __ } from '~/locale';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default class ProtectedTagAccessDropdown {
|
||||
constructor(options) {
|
||||
|
@ -8,7 +9,7 @@ export default class ProtectedTagAccessDropdown {
|
|||
|
||||
initDropdown() {
|
||||
const { onSelect } = this.options;
|
||||
this.options.$dropdown.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.options.$dropdown, {
|
||||
data: this.options.data,
|
||||
selectable: true,
|
||||
inputId: this.options.$dropdown.data('inputId'),
|
||||
|
|
|
@ -23,7 +23,7 @@ export default class ProtectedTagCreate {
|
|||
});
|
||||
|
||||
// Select default
|
||||
$allowedToCreateDropdown.data('glDropdown').selectRowAtIndex(0);
|
||||
$allowedToCreateDropdown.data('deprecatedJQueryDropdown').selectRowAtIndex(0);
|
||||
|
||||
// Protected tag dropdown
|
||||
this.createItemDropdown = new CreateItemDropdown({
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
class RefSelectDropdown {
|
||||
constructor($dropdownButton, availableRefs) {
|
||||
const availableRefsValue =
|
||||
availableRefs || JSON.parse(document.getElementById('availableRefs').innerHTML);
|
||||
$dropdownButton.glDropdown({
|
||||
initDeprecatedJQueryDropdown($dropdownButton, {
|
||||
data: availableRefsValue,
|
||||
filterable: true,
|
||||
filterByText: true,
|
||||
|
|
|
@ -13,6 +13,7 @@ import {
|
|||
spriteIcon,
|
||||
} from './lib/utils/common_utils';
|
||||
import Tracking from '~/tracking';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
/**
|
||||
* Search input in top navigation bar.
|
||||
|
@ -119,7 +120,7 @@ export class SearchAutocomplete {
|
|||
}
|
||||
|
||||
createAutocomplete() {
|
||||
return this.searchInput.glDropdown({
|
||||
return initDeprecatedJQueryDropdown(this.searchInput, {
|
||||
filterInputBlur: false,
|
||||
filterable: true,
|
||||
filterRemote: true,
|
||||
|
@ -145,10 +146,10 @@ export class SearchAutocomplete {
|
|||
if (!term) {
|
||||
const contents = this.getCategoryContents();
|
||||
if (contents) {
|
||||
const glDropdownInstance = this.searchInput.data('glDropdown');
|
||||
const deprecatedJQueryDropdownInstance = this.searchInput.data('deprecatedJQueryDropdown');
|
||||
|
||||
if (glDropdownInstance) {
|
||||
glDropdownInstance.filter.options.callback(contents);
|
||||
if (deprecatedJQueryDropdownInstance) {
|
||||
deprecatedJQueryDropdownInstance.filter.options.callback(contents);
|
||||
}
|
||||
this.enableAutocomplete();
|
||||
}
|
||||
|
@ -463,7 +464,7 @@ export class SearchAutocomplete {
|
|||
}
|
||||
|
||||
highlightFirstRow() {
|
||||
this.searchInput.data('glDropdown').highlightRowAtIndex(null, 0);
|
||||
this.searchInput.data('deprecatedJQueryDropdown').highlightRowAtIndex(null, 0);
|
||||
}
|
||||
|
||||
getAvatar(item) {
|
||||
|
|
|
@ -62,7 +62,7 @@ export default {
|
|||
this.addAssignee = this.store.addAssignee.bind(this.store);
|
||||
this.removeAllAssignees = this.store.removeAllAssignees.bind(this.store);
|
||||
|
||||
// Get events from glDropdown
|
||||
// Get events from deprecatedJQueryDropdown
|
||||
eventHub.$on('sidebar.removeAssignee', this.removeAssignee);
|
||||
eventHub.$on('sidebar.addAssignee', this.addAssignee);
|
||||
eventHub.$on('sidebar.removeAllAssignees', this.removeAllAssignees);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import { escape } from 'lodash';
|
||||
import { __ } from '~/locale';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
function isValidProjectId(id) {
|
||||
return id > 0;
|
||||
|
@ -27,7 +27,7 @@ class SidebarMoveIssue {
|
|||
}
|
||||
|
||||
initDropdown() {
|
||||
this.$dropdownToggle.glDropdown({
|
||||
initDeprecatedJQueryDropdown(this.$dropdownToggle, {
|
||||
search: {
|
||||
fields: ['name_with_namespace'],
|
||||
},
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import $ from 'jquery';
|
||||
import { __ } from './locale';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default function subscriptionSelect() {
|
||||
$('.js-subscription-event').each((i, element) => {
|
||||
const fieldName = $(element).data('fieldName');
|
||||
|
||||
return $(element).glDropdown({
|
||||
return initDeprecatedJQueryDropdown($(element), {
|
||||
selectable: true,
|
||||
fieldName,
|
||||
toggleLabel(selected, el, instance) {
|
||||
|
|
|
@ -33,7 +33,7 @@ export default class IssuableTemplateSelector extends TemplateSelector {
|
|||
this.templateWarningEl.find('.js-close-btn').on('click', () => {
|
||||
// Explicitly check against 0 value
|
||||
if (this.previousSelectedIndex !== undefined) {
|
||||
this.dropdown.data('glDropdown').selectRowAtIndex(this.previousSelectedIndex);
|
||||
this.dropdown.data('deprecatedJQueryDropdown').selectRowAtIndex(this.previousSelectedIndex);
|
||||
} else {
|
||||
this.reset();
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ export default class IssuableTemplateSelector extends TemplateSelector {
|
|||
}
|
||||
|
||||
setSelectedIndex() {
|
||||
this.previousSelectedIndex = this.dropdown.data('glDropdown').selectedIndex;
|
||||
this.previousSelectedIndex = this.dropdown.data('deprecatedJQueryDropdown').selectedIndex;
|
||||
}
|
||||
|
||||
onDropdownClicked(query) {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import $ from 'jquery';
|
||||
import Api from './api';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
export default () => {
|
||||
$('#js-project-dropdown').glDropdown({
|
||||
initDeprecatedJQueryDropdown($('#js-project-dropdown'), {
|
||||
data: (term, callback) => {
|
||||
Api.projects(
|
||||
term,
|
||||
|
|
|
@ -13,6 +13,7 @@ import { s__, __, sprintf } from '../locale';
|
|||
import ModalStore from '../boards/stores/modal_store';
|
||||
import { parseBoolean } from '../lib/utils/common_utils';
|
||||
import { getAjaxUsersSelectOptions, getAjaxUsersSelectParams } from './utils';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
// TODO: remove eventHub hack after code splitting refactor
|
||||
window.emitSidebarEvent = window.emitSidebarEvent || $.noop;
|
||||
|
@ -233,14 +234,14 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
closingTag: '</a>',
|
||||
})}</span> <% } %>`,
|
||||
);
|
||||
return $dropdown.glDropdown({
|
||||
return initDeprecatedJQueryDropdown($dropdown, {
|
||||
showMenuAbove,
|
||||
data(term, callback) {
|
||||
return userSelect.users(term, options, users => {
|
||||
// GitLabDropdownFilter returns this.instance
|
||||
// GitLabDropdownRemote returns this.options.instance
|
||||
const glDropdown = this.instance || this.options.instance;
|
||||
glDropdown.options.processData(term, users, callback);
|
||||
const deprecatedJQueryDropdown = this.instance || this.options.instance;
|
||||
deprecatedJQueryDropdown.options.processData(term, users, callback);
|
||||
});
|
||||
},
|
||||
processData(term, data, callback) {
|
||||
|
@ -349,7 +350,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
|
||||
callback(users);
|
||||
if (showMenuAbove) {
|
||||
$dropdown.data('glDropdown').positionMenuAbove();
|
||||
$dropdown.data('deprecatedJQueryDropdown').positionMenuAbove();
|
||||
}
|
||||
},
|
||||
filterable: true,
|
||||
|
@ -359,13 +360,13 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
},
|
||||
selectable: true,
|
||||
fieldName: $dropdown.data('fieldName'),
|
||||
toggleLabel(selected, el, glDropdown) {
|
||||
const inputValue = glDropdown.filterInput.val();
|
||||
toggleLabel(selected, el, deprecatedJQueryDropdown) {
|
||||
const inputValue = deprecatedJQueryDropdown.filterInput.val();
|
||||
|
||||
if (this.multiSelect && inputValue === '') {
|
||||
// Remove non-users from the fullData array
|
||||
const users = glDropdown.filteredFullData();
|
||||
const callback = glDropdown.parseData.bind(glDropdown);
|
||||
const users = deprecatedJQueryDropdown.filteredFullData();
|
||||
const callback = deprecatedJQueryDropdown.parseData.bind(deprecatedJQueryDropdown);
|
||||
|
||||
// Update the data model
|
||||
this.processData(inputValue, users, callback);
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
<script>
|
||||
import { GlIcon } from '@gitlab/ui';
|
||||
|
||||
export default GlIcon;
|
||||
</script>
|
|
@ -2,7 +2,6 @@ import { isEmpty } from 'lodash';
|
|||
import { sprintf, __ } from '~/locale';
|
||||
import { formatDate } from '~/lib/utils/datetime_utility';
|
||||
import tooltip from '~/vue_shared/directives/tooltip';
|
||||
import icon from '~/vue_shared/components/icon.vue';
|
||||
import timeagoMixin from '~/vue_shared/mixins/timeago';
|
||||
|
||||
const mixins = {
|
||||
|
@ -100,9 +99,6 @@ const mixins = {
|
|||
default: () => ({}),
|
||||
},
|
||||
},
|
||||
components: {
|
||||
icon,
|
||||
},
|
||||
directives: {
|
||||
tooltip,
|
||||
},
|
||||
|
|
|
@ -105,7 +105,7 @@ input[type='checkbox']:hover {
|
|||
}
|
||||
|
||||
.dropdown-header {
|
||||
// Necessary because glDropdown doesn't support a second style of headers
|
||||
// Necessary because deprecatedJQueryDropdown doesn't support a second style of headers
|
||||
font-weight: $gl-font-weight-bold;
|
||||
color: $gl-text-color;
|
||||
font-size: $gl-font-size;
|
||||
|
|
|
@ -80,11 +80,15 @@ class ProjectStatistics < ApplicationRecord
|
|||
end
|
||||
|
||||
def update_storage_size
|
||||
storage_size = repository_size + wiki_size + lfs_objects_size + build_artifacts_size + packages_size + pipeline_artifacts_size
|
||||
storage_size = repository_size + wiki_size + lfs_objects_size + build_artifacts_size + packages_size
|
||||
# The `snippets_size` column was added on 20200622095419 but db/post_migrate/20190527194900_schedule_calculate_wiki_sizes.rb
|
||||
# might try to update project statistics before the `snippets_size` column has been created.
|
||||
storage_size += snippets_size if self.class.column_names.include?('snippets_size')
|
||||
|
||||
# The `pipeline_artifacts_size` column was added on 20200817142800 but db/post_migrate/20190527194900_schedule_calculate_wiki_sizes.rb
|
||||
# might try to update project statistics before the `pipeline_artifacts_size` column has been created.
|
||||
storage_size += pipeline_artifacts_size if self.class.column_names.include?('pipeline_artifacts_size')
|
||||
|
||||
self.storage_size = storage_size
|
||||
end
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Make highlighting limits stricter
|
||||
merge_request: 39934
|
||||
author:
|
||||
type: performance
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix missing pipeline e-mails when job logs moved to object storage
|
||||
merge_request: 40075
|
||||
author:
|
||||
type: fixed
|
|
@ -522,7 +522,7 @@ More information can be found in the [Push event activities limit and bulk push
|
|||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/218017) in GitLab 13.4.
|
||||
|
||||
On GitLab.com, the maximum file size for a package that's uploaded to the [GitLab Package Registry](../user/packages/package_registry/index.md)
|
||||
is 50 megabytes.
|
||||
is 5 gigabytes.
|
||||
|
||||
Limits are set per package type.
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ Most issues will have labels for at least one of the following:
|
|||
- Team: `~"Technical Writing"`, `~Delivery`
|
||||
- Specialization: `~frontend`, `~backend`, `~documentation`
|
||||
- Release Scoping: `~Deliverable`, `~Stretch`, `~"Next Patch Release"`
|
||||
- Priority: `~P::1`, `~P::2`, `~P::3`, `~P::4`
|
||||
- Severity: ~`S::1`, `~S::2`, `~S::3`, `~S::4`
|
||||
- Priority: `~"priority::1"`, `~"priority::2"`, `~"priority::3"`, `~"priority::4"`
|
||||
- Severity: ~`"severity::1"`, `~"severity::2"`, `~"severity::3"`, `~"severity::4"`
|
||||
|
||||
All labels, their meaning and priority are defined on the
|
||||
[labels page](https://gitlab.com/gitlab-org/gitlab/-/labels).
|
||||
|
@ -275,10 +275,10 @@ or ~"Stretch". Any open issue for a previous milestone should be labeled
|
|||
|
||||
We have the following priority labels:
|
||||
|
||||
- ~P::1
|
||||
- ~P::2
|
||||
- ~P::3
|
||||
- ~P::4
|
||||
- ~"priority::1"
|
||||
- ~"priority::2"
|
||||
- ~"priority::3"
|
||||
- ~"priority::4"
|
||||
|
||||
Please refer to the issue triage [priority label](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#priority) section in our handbook to see how it's used.
|
||||
|
||||
|
@ -286,10 +286,10 @@ Please refer to the issue triage [priority label](https://about.gitlab.com/handb
|
|||
|
||||
We have the following severity labels:
|
||||
|
||||
- ~S::1
|
||||
- ~S::2
|
||||
- ~S::3
|
||||
- ~S::4
|
||||
- ~"severity::1"
|
||||
- ~"severity::2"
|
||||
- ~"severity::3"
|
||||
- ~"severity::4"
|
||||
|
||||
Please refer to the issue triage [severity label](https://about.gitlab.com/handbook/engineering/quality/issue-triage/#severity) section in our handbook to see how it's used.
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ For keeping transaction as minimal as possible, please consider using `AfterComm
|
|||
module or `after_commit` AR hook.
|
||||
|
||||
Here is [an example](https://gitlab.com/gitlab-org/gitlab/-/issues/36154#note_247228859)
|
||||
that one request to Gitaly instance during transaction triggered a P::1 issue.
|
||||
that one request to Gitaly instance during transaction triggered a ~"priority::1" issue.
|
||||
|
||||
## Eager Loading
|
||||
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
After Width: | Height: | Size: 115 KiB |
|
@ -129,6 +129,14 @@ characters to begin your search. For example, if you want to search for
|
|||
issues that have the assignee "Simone Presley", you'll need to type at
|
||||
least "Sim" before autocomplete gives any relevant results.
|
||||
|
||||
## Code search
|
||||
|
||||
To search through code or other documents in a single project, you can use
|
||||
the search field on the top-right of your screen while the project page is open.
|
||||
|
||||
![code search dropdown](img/project_search_dropdown.png)
|
||||
![code search results](img/project_code_search.png)
|
||||
|
||||
## Search history
|
||||
|
||||
You can view recent searches by clicking on the little arrow-clock icon, which is to the left of the search input. Click the search entry to run that search again. This feature is available for issues and merge requests. Searches are stored locally in your browser.
|
||||
|
|
|
@ -79,22 +79,15 @@ module Gitlab
|
|||
job.trace_chunks.any? || current_path.present? || old_trace.present?
|
||||
end
|
||||
|
||||
def read
|
||||
stream = Gitlab::Ci::Trace::Stream.new do
|
||||
if trace_artifact
|
||||
trace_artifact.open
|
||||
elsif job.trace_chunks.any?
|
||||
Gitlab::Ci::Trace::ChunkedIO.new(job)
|
||||
elsif current_path
|
||||
File.open(current_path, "rb")
|
||||
elsif old_trace
|
||||
StringIO.new(old_trace)
|
||||
end
|
||||
end
|
||||
def read(&block)
|
||||
should_retry = true if lock_taken?(lock_key)
|
||||
|
||||
yield stream
|
||||
ensure
|
||||
stream&.close
|
||||
read_stream(&block)
|
||||
rescue Errno::ENOENT
|
||||
raise unless should_retry
|
||||
|
||||
job.reset
|
||||
read_stream(&block)
|
||||
end
|
||||
|
||||
def write(mode, &blk)
|
||||
|
@ -141,6 +134,24 @@ module Gitlab
|
|||
|
||||
private
|
||||
|
||||
def read_stream
|
||||
stream = Gitlab::Ci::Trace::Stream.new do
|
||||
if trace_artifact
|
||||
trace_artifact.open
|
||||
elsif job.trace_chunks.any?
|
||||
Gitlab::Ci::Trace::ChunkedIO.new(job)
|
||||
elsif current_path
|
||||
File.open(current_path, "rb")
|
||||
elsif old_trace
|
||||
StringIO.new(old_trace)
|
||||
end
|
||||
end
|
||||
|
||||
yield stream
|
||||
ensure
|
||||
stream&.close
|
||||
end
|
||||
|
||||
def unsafe_write!(mode, &blk)
|
||||
stream = Gitlab::Ci::Trace::Stream.new do
|
||||
if trace_artifact
|
||||
|
@ -184,10 +195,13 @@ module Gitlab
|
|||
end
|
||||
|
||||
def in_write_lock(&blk)
|
||||
lock_key = "trace:write:lock:#{job.id}"
|
||||
in_lock(lock_key, ttl: LOCK_TTL, retries: LOCK_RETRIES, sleep_sec: LOCK_SLEEP, &blk)
|
||||
end
|
||||
|
||||
def lock_key
|
||||
"trace:write:lock:#{job.id}"
|
||||
end
|
||||
|
||||
def archive_stream!(stream)
|
||||
clone_file!(stream, JobArtifactUploader.workhorse_upload_path) do |clone_path|
|
||||
create_build_trace!(job, clone_path)
|
||||
|
|
|
@ -39,5 +39,10 @@ module Gitlab
|
|||
ensure
|
||||
lease&.cancel
|
||||
end
|
||||
|
||||
def lock_taken?(key)
|
||||
lease = Gitlab::ExclusiveLease.new(key, timeout: 0)
|
||||
lease.exists?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
module Gitlab
|
||||
class Highlight
|
||||
TIMEOUT_BACKGROUND = 30.seconds
|
||||
TIMEOUT_FOREGROUND = 3.seconds
|
||||
MAXIMUM_TEXT_HIGHLIGHT_SIZE = 1.megabyte
|
||||
TIMEOUT_FOREGROUND = 1.5.seconds
|
||||
MAXIMUM_TEXT_HIGHLIGHT_SIZE = 512.kilobytes
|
||||
|
||||
def self.highlight(blob_name, blob_content, language: nil, plain: false)
|
||||
new(blob_name, blob_content, language: language)
|
||||
|
|
|
@ -28,6 +28,25 @@ module Gitlab
|
|||
end
|
||||
# rubocop:enable Rails/Output
|
||||
|
||||
module Workhorse
|
||||
extend Gitlab::SetupHelper
|
||||
class << self
|
||||
def configuration_toml(dir, _)
|
||||
config = { redis: { URL: redis_url } }
|
||||
|
||||
TomlRB.dump(config)
|
||||
end
|
||||
|
||||
def redis_url
|
||||
Gitlab::Redis::SharedState.url
|
||||
end
|
||||
|
||||
def get_config_path(dir)
|
||||
File.join(dir, 'config.toml')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Gitaly
|
||||
extend Gitlab::SetupHelper
|
||||
class << self
|
||||
|
|
|
@ -27066,6 +27066,9 @@ msgstr ""
|
|||
msgid "ValueStreamAnalytics|Median time from issue created to issue closed."
|
||||
msgstr ""
|
||||
|
||||
msgid "ValueStream|The Default Value Stream cannot be deleted"
|
||||
msgstr ""
|
||||
|
||||
msgid "Variable"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
[[ "$TRACE" ]] && set -x
|
||||
|
||||
function create_user() {
|
||||
local user="${1}"
|
||||
|
||||
# API details at https://docs.gitlab.com/ee/api/users.html#user-creation
|
||||
#
|
||||
# We set "can_create_group=false" because we don't want the DAST user to create groups.
|
||||
# Otherwise, the DAST user likely creates a group and enables 2FA for all group members,
|
||||
# which leads to the DAST scan getting "stuck" on the 2FA set up page.
|
||||
# Once https://gitlab.com/gitlab-org/gitlab/-/issues/231447 is resolved, we can use
|
||||
# DAST_AUTH_EXCLUDE_URLS instead to prevent DAST from enabling 2FA.
|
||||
curl --silent --show-error --header "PRIVATE-TOKEN: ${REVIEW_APPS_ROOT_TOKEN}" \
|
||||
--data "email=${user}@example.com" \
|
||||
--data "name=${user}" \
|
||||
--data "username=${user}" \
|
||||
--data "password=${REVIEW_APPS_ROOT_PASSWORD}" \
|
||||
--data "skip_confirmation=true" \
|
||||
--data "can_create_group=false" \
|
||||
"${CI_ENVIRONMENT_URL}/api/v4/users" > /tmp/user.json
|
||||
|
||||
[[ "$TRACE" ]] && cat /tmp/user.json >&2
|
||||
|
||||
jq .id /tmp/user.json
|
||||
}
|
||||
|
||||
function create_project_for_user() {
|
||||
local userid="${1}"
|
||||
|
||||
# API details at https://docs.gitlab.com/ee/api/projects.html#create-project-for-user
|
||||
curl --silent --show-error --header "PRIVATE-TOKEN: ${REVIEW_APPS_ROOT_TOKEN}" \
|
||||
--data "user_id=${userid}" \
|
||||
--data "name=awesome-test-project-${userid}" \
|
||||
--data "visibility=private" \
|
||||
"${CI_ENVIRONMENT_URL}/api/v4/projects/user/${userid}" > /tmp/project.json
|
||||
|
||||
[[ "$TRACE" ]] && cat /tmp/project.json >&2
|
||||
}
|
||||
|
||||
function trigger_proj_user_creation(){
|
||||
local u1=$(create_user "user1")
|
||||
create_project_for_user $u1
|
||||
local u2=$(create_user "user2")
|
||||
create_project_for_user $u2
|
||||
local u3=$(create_user "user3")
|
||||
create_project_for_user $u3
|
||||
local u4=$(create_user "user4")
|
||||
create_project_for_user $u4
|
||||
local u5=$(create_user "user5")
|
||||
create_project_for_user $u5
|
||||
local u6=$(create_user "user6")
|
||||
create_project_for_user $u6
|
||||
local u7=$(create_user "user7")
|
||||
create_project_for_user $u7
|
||||
local u8=$(create_user "user8")
|
||||
create_project_for_user $u8
|
||||
local u9=$(create_user "user9")
|
||||
create_project_for_user $u9
|
||||
local u10=$(create_user "user10")
|
||||
create_project_for_user $u10
|
||||
local u11=$(create_user "user11")
|
||||
create_project_for_user $u11
|
||||
local u12=$(create_user "user12")
|
||||
create_project_for_user $u12
|
||||
local u13=$(create_user "user13")
|
||||
create_project_for_user $u13
|
||||
local u14=$(create_user "user14")
|
||||
create_project_for_user $u14
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable no-param-reassign */
|
||||
|
||||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
import '~/lib/utils/common_utils';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
|
||||
|
@ -9,8 +9,8 @@ jest.mock('~/lib/utils/url_utility', () => ({
|
|||
visitUrl: jest.fn().mockName('visitUrl'),
|
||||
}));
|
||||
|
||||
describe('glDropdown', () => {
|
||||
preloadFixtures('static/gl_dropdown.html');
|
||||
describe('deprecatedJQueryDropdown', () => {
|
||||
preloadFixtures('static/deprecated_jquery_dropdown.html');
|
||||
|
||||
const NON_SELECTABLE_CLASSES =
|
||||
'.divider, .separator, .dropdown-header, .dropdown-menu-empty-item';
|
||||
|
@ -60,14 +60,12 @@ describe('glDropdown', () => {
|
|||
id: project => project.id,
|
||||
...extraOpts,
|
||||
};
|
||||
test.dropdownButtonElement = $(
|
||||
'#js-project-dropdown',
|
||||
test.dropdownContainerElement,
|
||||
).glDropdown(options);
|
||||
test.dropdownButtonElement = $('#js-project-dropdown', test.dropdownContainerElement);
|
||||
initDeprecatedJQueryDropdown(test.dropdownButtonElement, options);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
loadFixtures('static/gl_dropdown.html');
|
||||
loadFixtures('static/deprecated_jquery_dropdown.html');
|
||||
test.dropdownContainerElement = $('.dropdown.inline');
|
||||
test.$dropdownMenuElement = $('.dropdown-menu', test.dropdownContainerElement);
|
||||
test.projectsData = getJSONFixture('static/projects.json');
|
||||
|
@ -248,9 +246,9 @@ describe('glDropdown', () => {
|
|||
function dropdownWithOptions(options) {
|
||||
const $dropdownDiv = $('<div />');
|
||||
|
||||
$dropdownDiv.glDropdown(options);
|
||||
initDeprecatedJQueryDropdown($dropdownDiv, options);
|
||||
|
||||
return $dropdownDiv.data('glDropdown');
|
||||
return $dropdownDiv.data('deprecatedJQueryDropdown');
|
||||
}
|
||||
|
||||
function basicDropdown() {
|
|
@ -7,7 +7,6 @@ import axios from '~/lib/utils/axios_utils';
|
|||
import IssuableContext from '~/issuable_context';
|
||||
import LabelsSelect from '~/labels_select';
|
||||
|
||||
import '~/gl_dropdown';
|
||||
import 'select2';
|
||||
import '~/api';
|
||||
import '~/create_label';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { shallowMount } from '@vue/test-utils';
|
||||
import { GlBarChart } from '@gitlab/ui/dist/charts';
|
||||
import Bar from '~/monitoring/components/charts/bar.vue';
|
||||
import { barMockData } from '../../mock_data';
|
||||
import { barGraphData } from '../../graph_data';
|
||||
|
||||
jest.mock('~/lib/utils/icon_utils', () => ({
|
||||
getSvgIconPathContent: jest.fn().mockResolvedValue('mockSvgPathContent'),
|
||||
|
@ -10,11 +10,14 @@ jest.mock('~/lib/utils/icon_utils', () => ({
|
|||
describe('Bar component', () => {
|
||||
let barChart;
|
||||
let store;
|
||||
let graphData;
|
||||
|
||||
beforeEach(() => {
|
||||
graphData = barGraphData();
|
||||
|
||||
barChart = shallowMount(Bar, {
|
||||
propsData: {
|
||||
graphData: barMockData,
|
||||
graphData,
|
||||
},
|
||||
store,
|
||||
});
|
||||
|
@ -31,7 +34,7 @@ describe('Bar component', () => {
|
|||
|
||||
beforeEach(() => {
|
||||
glbarChart = barChart.find(GlBarChart);
|
||||
chartData = barChart.vm.chartData[barMockData.metrics[0].label];
|
||||
chartData = barChart.vm.chartData[graphData.metrics[0].label];
|
||||
});
|
||||
|
||||
it('is a Vue instance', () => {
|
||||
|
@ -39,7 +42,7 @@ describe('Bar component', () => {
|
|||
});
|
||||
|
||||
it('should display a label on the x axis', () => {
|
||||
expect(glbarChart.vm.xAxisTitle).toBe(barMockData.xLabel);
|
||||
expect(glbarChart.props('xAxisTitle')).toBe(graphData.xLabel);
|
||||
});
|
||||
|
||||
it('should return chartData as array of arrays', () => {
|
||||
|
|
|
@ -15,10 +15,14 @@ import {
|
|||
mockNamespace,
|
||||
mockNamespacedData,
|
||||
mockTimeRange,
|
||||
barMockData,
|
||||
} from '../mock_data';
|
||||
import { dashboardProps, graphData, graphDataEmpty } from '../fixture_data';
|
||||
import { anomalyGraphData, singleStatGraphData, heatmapGraphData } from '../graph_data';
|
||||
import {
|
||||
anomalyGraphData,
|
||||
singleStatGraphData,
|
||||
heatmapGraphData,
|
||||
barGraphData,
|
||||
} from '../graph_data';
|
||||
|
||||
import { panelTypes } from '~/monitoring/constants';
|
||||
|
||||
|
@ -240,7 +244,7 @@ describe('Dashboard Panel', () => {
|
|||
${dataWithType(panelTypes.COLUMN)} | ${MonitorColumnChart} | ${false}
|
||||
${dataWithType(panelTypes.STACKED_COLUMN)} | ${MonitorStackedColumnChart} | ${false}
|
||||
${heatmapGraphData()} | ${MonitorHeatmapChart} | ${false}
|
||||
${barMockData} | ${MonitorBarChart} | ${false}
|
||||
${barGraphData()} | ${MonitorBarChart} | ${false}
|
||||
`('when $data.type data is provided', ({ data, component, hasCtxMenu }) => {
|
||||
const attrs = { attr1: 'attr1Value', attr2: 'attr2Value' };
|
||||
|
||||
|
|
|
@ -259,3 +259,16 @@ export const stackedColumnGraphData = (panelOptions = {}, dataOptions = {}) => {
|
|||
type: panelTypes.STACKED_COLUMN,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates bar mock graph data according to options
|
||||
*
|
||||
* @param {Object} panelOptions - Panel options as in YML.
|
||||
* @param {Object} dataOptions
|
||||
*/
|
||||
export const barGraphData = (panelOptions = {}, dataOptions = {}) => {
|
||||
return {
|
||||
...timeSeriesGraphData(panelOptions, dataOptions),
|
||||
type: panelTypes.BAR,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,56 +1,55 @@
|
|||
import $ from 'jquery';
|
||||
import NamespaceSelect from '~/namespace_select';
|
||||
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
|
||||
|
||||
jest.mock('~/deprecated_jquery_dropdown');
|
||||
|
||||
describe('NamespaceSelect', () => {
|
||||
beforeEach(() => {
|
||||
jest.spyOn($.fn, 'glDropdown').mockImplementation(() => {});
|
||||
});
|
||||
|
||||
it('initializes glDropdown', () => {
|
||||
it('initializes deprecatedJQueryDropdown', () => {
|
||||
const dropdown = document.createElement('div');
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new NamespaceSelect({ dropdown });
|
||||
|
||||
expect($.fn.glDropdown).toHaveBeenCalled();
|
||||
expect(initDeprecatedJQueryDropdown).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe('as input', () => {
|
||||
let glDropdownOptions;
|
||||
let deprecatedJQueryDropdownOptions;
|
||||
|
||||
beforeEach(() => {
|
||||
const dropdown = document.createElement('div');
|
||||
// eslint-disable-next-line no-new
|
||||
new NamespaceSelect({ dropdown });
|
||||
[[glDropdownOptions]] = $.fn.glDropdown.mock.calls;
|
||||
[[, deprecatedJQueryDropdownOptions]] = initDeprecatedJQueryDropdown.mock.calls;
|
||||
});
|
||||
|
||||
it('prevents click events', () => {
|
||||
const dummyEvent = new Event('dummy');
|
||||
jest.spyOn(dummyEvent, 'preventDefault').mockImplementation(() => {});
|
||||
|
||||
glDropdownOptions.clicked({ e: dummyEvent });
|
||||
// expect(foo).toContain('test');
|
||||
deprecatedJQueryDropdownOptions.clicked({ e: dummyEvent });
|
||||
|
||||
expect(dummyEvent.preventDefault).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('as filter', () => {
|
||||
let glDropdownOptions;
|
||||
let deprecatedJQueryDropdownOptions;
|
||||
|
||||
beforeEach(() => {
|
||||
const dropdown = document.createElement('div');
|
||||
dropdown.dataset.isFilter = 'true';
|
||||
// eslint-disable-next-line no-new
|
||||
new NamespaceSelect({ dropdown });
|
||||
[[glDropdownOptions]] = $.fn.glDropdown.mock.calls;
|
||||
[[, deprecatedJQueryDropdownOptions]] = initDeprecatedJQueryDropdown.mock.calls;
|
||||
});
|
||||
|
||||
it('does not prevent click events', () => {
|
||||
const dummyEvent = new Event('dummy');
|
||||
jest.spyOn(dummyEvent, 'preventDefault').mockImplementation(() => {});
|
||||
|
||||
glDropdownOptions.clicked({ e: dummyEvent });
|
||||
deprecatedJQueryDropdownOptions.clicked({ e: dummyEvent });
|
||||
|
||||
expect(dummyEvent.preventDefault).not.toHaveBeenCalled();
|
||||
});
|
||||
|
@ -58,7 +57,7 @@ describe('NamespaceSelect', () => {
|
|||
it('sets URL of dropdown items', () => {
|
||||
const dummyNamespace = { id: 'eal' };
|
||||
|
||||
const itemUrl = glDropdownOptions.url(dummyNamespace);
|
||||
const itemUrl = deprecatedJQueryDropdownOptions.url(dummyNamespace);
|
||||
|
||||
expect(itemUrl).toContain(`namespace_id=${dummyNamespace.id}`);
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@ import $ from 'jquery';
|
|||
import MockAdapter from 'axios-mock-adapter';
|
||||
import Todos from '~/pages/dashboard/todos/index/todos';
|
||||
import '~/lib/utils/common_utils';
|
||||
import '~/gl_dropdown';
|
||||
import axios from '~/lib/utils/axios_utils';
|
||||
import { addDelimiter } from '~/lib/utils/text_utility';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import TimezoneDropdown, {
|
||||
formatUtcOffset,
|
||||
formatTimezone,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import AccessDropdown from '~/projects/settings/access_dropdown';
|
||||
import { LEVEL_TYPES } from '~/projects/settings/constants';
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/* eslint-disable no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign */
|
||||
|
||||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
import AxiosMockAdapter from 'axios-mock-adapter';
|
||||
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
|
||||
import initSearchAutocomplete from '~/search_autocomplete';
|
||||
|
@ -215,7 +214,7 @@ describe('Search autocomplete dropdown', () => {
|
|||
|
||||
function triggerAutocomplete() {
|
||||
return new Promise(resolve => {
|
||||
const dropdown = widget.searchInput.data('glDropdown');
|
||||
const dropdown = widget.searchInput.data('deprecatedJQueryDropdown');
|
||||
const filterCallback = dropdown.filter.options.callback;
|
||||
dropdown.filter.options.callback = jest.fn(data => {
|
||||
filterCallback(data);
|
||||
|
|
|
@ -68,12 +68,10 @@ describe('SidebarMoveIssue', () => {
|
|||
});
|
||||
|
||||
describe('initDropdown', () => {
|
||||
it('should initialize the gl_dropdown', () => {
|
||||
jest.spyOn($.fn, 'glDropdown').mockImplementation(() => {});
|
||||
|
||||
it('should initialize the deprecatedJQueryDropdown', () => {
|
||||
test.sidebarMoveIssue.initDropdown();
|
||||
|
||||
expect($.fn.glDropdown).toHaveBeenCalled();
|
||||
expect(test.sidebarMoveIssue.$dropdownToggle.data('deprecatedJQueryDropdown')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('escapes html from project name', done => {
|
||||
|
|
|
@ -11,6 +11,41 @@ RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state do
|
|||
it { expect(trace).to delegate_method(:old_trace).to(:job) }
|
||||
end
|
||||
|
||||
context 'when trace is migrated to object storage' do
|
||||
let!(:job) { create(:ci_build, :trace_artifact) }
|
||||
let!(:artifact1) { job.job_artifacts_trace }
|
||||
let!(:artifact2) { job.reload.job_artifacts_trace }
|
||||
let(:test_data) { "hello world" }
|
||||
|
||||
before do
|
||||
stub_artifacts_object_storage
|
||||
|
||||
artifact1.file.migrate!(ObjectStorage::Store::REMOTE)
|
||||
end
|
||||
|
||||
context 'when write lock is not present' do
|
||||
it 'raises an exception' do
|
||||
expect { artifact2.job.trace.raw }.to raise_error(Errno::ENOENT)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when write lock is present', :clean_gitlab_redis_shared_state do
|
||||
before do
|
||||
Gitlab::ExclusiveLease.new("trace:write:lock:#{job.id}", timeout: 10.seconds).try_obtain
|
||||
end
|
||||
|
||||
it 'reloads the trace after is it migrated' do
|
||||
stub_const('Gitlab::HttpIO::BUFFER_SIZE', test_data.length)
|
||||
|
||||
expect_next_instance_of(Gitlab::HttpIO) do |http_io|
|
||||
expect(http_io).to receive(:get_chunk).and_return(test_data, "")
|
||||
end
|
||||
|
||||
expect(artifact2.job.trace.raw).to eq(test_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when live trace feature is disabled' do
|
||||
before do
|
||||
stub_feature_flags(ci_enable_live_trace: false)
|
||||
|
|
|
@ -111,4 +111,14 @@ RSpec.describe Gitlab::ExclusiveLeaseHelpers, :clean_gitlab_redis_shared_state d
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#lock_taken?' do
|
||||
it 'returns true when lock has been taken' do
|
||||
expect(class_instance.lock_taken?(unique_key)).to be false
|
||||
|
||||
class_instance.in_lock(unique_key) do
|
||||
expect(class_instance.lock_taken?(unique_key)).to be true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,9 +16,9 @@ RSpec.describe ScheduleCalculateWikiSizes do
|
|||
let(:project3) { projects.create!(name: 'wiki-project-3', path: 'wiki-project-3', namespace_id: namespace.id) }
|
||||
|
||||
context 'when missing wiki sizes exist' do
|
||||
let!(:project_statistic1) { project_statistics.create!(id: 1, project_id: project1.id, namespace_id: namespace.id, wiki_size: 1000) }
|
||||
let!(:project_statistic2) { project_statistics.create!(id: 2, project_id: project2.id, namespace_id: namespace.id, wiki_size: nil) }
|
||||
let!(:project_statistic3) { project_statistics.create!(id: 3, project_id: project3.id, namespace_id: namespace.id, wiki_size: nil) }
|
||||
let!(:project_statistic1) { project_statistics.create!(project_id: project1.id, namespace_id: namespace.id, wiki_size: 1000) }
|
||||
let!(:project_statistic2) { project_statistics.create!(project_id: project2.id, namespace_id: namespace.id, wiki_size: nil) }
|
||||
let!(:project_statistic3) { project_statistics.create!(project_id: project3.id, namespace_id: namespace.id, wiki_size: nil) }
|
||||
|
||||
it 'schedules a background migration' do
|
||||
Timecop.freeze do
|
||||
|
@ -44,7 +44,7 @@ RSpec.describe ScheduleCalculateWikiSizes do
|
|||
before do
|
||||
namespace = namespaces.create!(name: 'wiki-migration', path: 'wiki-migration')
|
||||
project = projects.create!(name: 'wiki-project-1', path: 'wiki-project-1', namespace_id: namespace.id)
|
||||
project_statistics.create!(project_id: project.id, namespace_id: 1, wiki_size: 1000)
|
||||
project_statistics.create!(project_id: project.id, namespace_id: namespace.id, wiki_size: 1000)
|
||||
end
|
||||
|
||||
it 'does not schedule a background migration' do
|
||||
|
|
|
@ -247,8 +247,9 @@ module TestEnv
|
|||
'GitLab Workhorse',
|
||||
install_dir: workhorse_dir,
|
||||
version: Gitlab::Workhorse.version,
|
||||
task: "gitlab:workhorse:install[#{install_workhorse_args}]"
|
||||
)
|
||||
task: "gitlab:workhorse:install[#{install_workhorse_args}]") do
|
||||
Gitlab::SetupHelper::Workhorse.create_configuration(workhorse_dir, nil)
|
||||
end
|
||||
end
|
||||
|
||||
def workhorse_dir
|
||||
|
@ -259,6 +260,14 @@ module TestEnv
|
|||
host = "[#{host}]" if host.include?(':')
|
||||
listen_addr = [host, port].join(':')
|
||||
|
||||
config_path = Gitlab::SetupHelper::Workhorse.get_config_path(workhorse_dir)
|
||||
|
||||
# This should be set up in setup_workhorse, but since
|
||||
# component_needs_update? only checks that versions are consistent,
|
||||
# we need to ensure the config file exists. This line can be removed
|
||||
# later after a new Workhorse version is updated.
|
||||
Gitlab::SetupHelper::Workhorse.create_configuration(workhorse_dir, nil) unless File.exist?(config_path)
|
||||
|
||||
workhorse_pid = spawn(
|
||||
{ 'PATH' => "#{ENV['PATH']}:#{workhorse_dir}" },
|
||||
File.join(workhorse_dir, 'gitlab-workhorse'),
|
||||
|
@ -266,10 +275,7 @@ module TestEnv
|
|||
'-documentRoot', Rails.root.join('public').to_s,
|
||||
'-listenAddr', listen_addr,
|
||||
'-secretPath', Gitlab::Workhorse.secret_path.to_s,
|
||||
# TODO: Needed for workhorse + redis features.
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/209245
|
||||
#
|
||||
# '-config', '',
|
||||
'-config', config_path,
|
||||
'-logFile', 'log/workhorse-test.log',
|
||||
'-logFormat', 'structured',
|
||||
'-developmentMode' # to serve assets and rich error messages
|
||||
|
|
Loading…
Reference in New Issue