New upstream version 13.10.3+ds1

This commit is contained in:
Pirate Praveen 2021-04-17 20:07:23 +05:30
parent 459ea34293
commit 26db65f672
9062 changed files with 385637 additions and 220367 deletions

View file

@ -1,15 +1,9 @@
/app/assets/javascripts/locale/**/app.js /app/assets/javascripts/locale/**/app.js
/config/
/builds/ /builds/
/coverage/ /coverage/
/coverage-frontend/ /coverage-frontend/
/coverage-javascript/ /coverage-javascript/
/node_modules/ /node_modules/
/public/ /public/
/scripts/
/tmp/ /tmp/
/vendor/ /vendor/
jest.config.js
jest.config.*.js
karma.config.js
webpack.config.js

View file

@ -43,6 +43,17 @@ rules:
promise/always-return: off promise/always-return: off
promise/no-callback-in-promise: off promise/no-callback-in-promise: off
'@gitlab/no-global-event-off': error '@gitlab/no-global-event-off': error
no-param-reassign:
- error
- props: true
ignorePropertyModificationsFor:
- acc
- accumulator
- el
- element
- state
ignorePropertyModificationsForRegex:
- '^draft'
import/order: import/order:
- error - error
- groups: - groups:
@ -89,3 +100,15 @@ overrides:
rules: rules:
'@gitlab/require-i18n-strings': off '@gitlab/require-i18n-strings': off
'@gitlab/no-runtime-template-compiler': off '@gitlab/no-runtime-template-compiler': off
- files:
- 'config/**/*'
- 'scripts/**/*'
- '*.config.js'
- '*.config.*.js'
rules:
'@gitlab/require-i18n-strings': off
import/no-extraneous-dependencies: off
import/no-commonjs: off
import/no-nodejs-modules: off
filenames/match-regex: off
no-console: off

3
.gitignore vendored
View file

@ -19,8 +19,8 @@ eslint-report.html
/.ruby-version /.ruby-version
/.tool-versions /.tool-versions
/.rvmrc /.rvmrc
.sass-cache/
/.secret /.secret
.sass-cache/
/.vagrant /.vagrant
/.yarn-cache /.yarn-cache
/.byebug_history /.byebug_history
@ -104,3 +104,4 @@ ee/changelogs/unreleased-ee
/sitespeed-result /sitespeed-result
tags.lock tags.lock
tags.temp tags.temp
.stylelintcache

View file

@ -111,4 +111,4 @@ include:
- local: .gitlab/ci/dast.gitlab-ci.yml - local: .gitlab/ci/dast.gitlab-ci.yml
- local: .gitlab/ci/workhorse.gitlab-ci.yml - local: .gitlab/ci/workhorse.gitlab-ci.yml
- local: .gitlab/ci/graphql.gitlab-ci.yml - local: .gitlab/ci/graphql.gitlab-ci.yml
- local: .gitlab/ci/verify-lockfile.gitlab-ci.yml - remote: 'https://gitlab.com/gitlab-org/frontend/untamper-my-lockfile/-/raw/main/.gitlab-ci-template.yml'

View file

@ -24,7 +24,6 @@
/doc/administration/troubleshooting @axil @marcia @mjang1 /doc/administration/troubleshooting @axil @marcia @mjang1
/doc/ci/ @marcel.amirault @sselhorn /doc/ci/ @marcel.amirault @sselhorn
/doc/ci/environments/ @axil /doc/ci/environments/ @axil
/doc/ci/release/ @axil
/doc/ci/services/ @sselhorn /doc/ci/services/ @sselhorn
/doc/ci/test_cases/ @msedlakjakubowski /doc/ci/test_cases/ @msedlakjakubowski
/doc/development/ @marcia @mjang1 /doc/development/ @marcia @mjang1
@ -101,6 +100,7 @@
/doc/api/repository_files.md @aqualls /doc/api/repository_files.md @aqualls
/doc/api/repository_submodules.md @aqualls /doc/api/repository_submodules.md @aqualls
/doc/api/search.md @aqualls /doc/api/search.md @aqualls
/doc/api/services.md @aqualls
/doc/api/snippets.md @aqualls /doc/api/snippets.md @aqualls
/doc/api/suggestions.md @aqualls /doc/api/suggestions.md @aqualls
/doc/api/tags.md @aqualls /doc/api/tags.md @aqualls
@ -110,6 +110,7 @@
/doc/topics/gitlab_flow.md @aqualls /doc/topics/gitlab_flow.md @aqualls
/doc/user/admin_area/settings/account_and_limit_settings.md @aqualls /doc/user/admin_area/settings/account_and_limit_settings.md @aqualls
/doc/user/admin_area/settings/instance_template_repository.md @aqualls /doc/user/admin_area/settings/instance_template_repository.md @aqualls
/doc/user/admin_area/settings/project_integration_management.md @aqualls
/doc/user/admin_area/settings/push_event_activities_limit.md @aqualls /doc/user/admin_area/settings/push_event_activities_limit.md @aqualls
/doc/user/admin_area/settings/visibility_and_access_controls.md @aqualls /doc/user/admin_area/settings/visibility_and_access_controls.md @aqualls
/doc/user/asciidoc.md @aqualls /doc/user/asciidoc.md @aqualls
@ -129,6 +130,15 @@
/doc/user/project/settings/import_export.md @aqualls /doc/user/project/settings/import_export.md @aqualls
/doc/user/snippets.md @aqualls /doc/user/snippets.md @aqualls
[Docs Growth]
/doc/administration/instance_review.md @aqualls
/doc/api/invitations.md @aqualls
/doc/api/experiments.md @aqualls
/doc/development/experiment_guide/ @aqualls
/doc/development/snowplow.md @aqualls
/doc/development/usage_ping/ @aqualls
/doc/user/admin_area/license.md @aqualls
[Frontend] [Frontend]
*.scss @annabeldunstone @gitlab-org/maintainers/frontend *.scss @annabeldunstone @gitlab-org/maintainers/frontend
*.js @gitlab-org/maintainers/frontend *.js @gitlab-org/maintainers/frontend
@ -170,6 +180,11 @@ Dangerfile @gl-quality/eng-prod
/scripts/review_apps/seed-dast-test-data.sh @dappelt @ngeorge1 @gl-quality/eng-prod /scripts/review_apps/seed-dast-test-data.sh @dappelt @ngeorge1 @gl-quality/eng-prod
.editorconfig @gl-quality/eng-prod .editorconfig @gl-quality/eng-prod
[Backend Static Code Analysis]
.rubocop*.yml @dstull @splattael @gl-quality/eng-prod
/rubocop/ @dstull @splattael @gl-quality/eng-prod
/spec/rubocop/ @dstull @splattael @gl-quality/eng-prod
[End-to-end] [End-to-end]
/qa/ @gl-quality /qa/ @gl-quality
@ -189,15 +204,16 @@ Dangerfile @gl-quality/eng-prod
# Secure & Threat Management ownership delineation # Secure & Threat Management ownership delineation
# https://about.gitlab.com/handbook/engineering/development/threat-management/delineate-secure-threat-management.html#technical-boundaries # https://about.gitlab.com/handbook/engineering/development/threat-management/delineate-secure-threat-management.html#technical-boundaries
[Threat Insights] [Threat Insights]
/app/models/vulnerability.rb @gitlab-org/secure/threat-insights-backend-team
/ee/app/finders/security/ @gitlab-org/secure/threat-insights-backend-team /ee/app/finders/security/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/security/ @gitlab-org/secure/threat-insights-backend-team /ee/app/models/security/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team /ee/app/models/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/vulnerability.rb @gitlab-org/secure/threat-insights-backend-team
/ee/app/policies/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team /ee/app/policies/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/policies/vulnerability*.rb @gitlab-org/secure/threat-insights-backend-team /ee/app/policies/vulnerability*.rb @gitlab-org/secure/threat-insights-backend-team
/ee/lib/api/vulnerabilit*.rb @gitlab-org/secure/threat-insights-backend-team /ee/lib/api/vulnerabilit*.rb @gitlab-org/secure/threat-insights-backend-team
/ee/spec/policies/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team /ee/spec/policies/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team
/ee/spec/policies/vulnerabilities/vulnerability*.rb @gitlab-org/secure/threat-insights-backend-team /ee/spec/policies/vulnerability*.rb @gitlab-org/secure/threat-insights-backend-team
[Secure] [Secure]
/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be /ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be /ee/lib/gitlab/ci/parsers/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
@ -244,9 +260,7 @@ Dangerfile @gl-quality/eng-prod
[Product Intelligence] [Product Intelligence]
/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers /ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers
/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/product-intelligence/engineers /ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/product-intelligence/engineers
/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/product-intelligence/engineers
/lib/gitlab/usage_data.rb @gitlab-org/growth/product_intelligence/engineers /lib/gitlab/usage_data.rb @gitlab-org/growth/product_intelligence/engineers
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/product-intelligence/engineers
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers /lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers
[Growth Experiments] [Growth Experiments]
@ -266,3 +280,6 @@ Dangerfile @gl-quality/eng-prod
[Legal] [Legal]
/config/dependency_decisions.yml @gitlab-org/legal-reviewers /config/dependency_decisions.yml @gitlab-org/legal-reviewers
[Workhorse]
/workhorse/ @jacobvosmaer-gitlab @nick.thomas @nolith @patrickbajao

View file

@ -29,6 +29,7 @@ cache-repo:
- '[ -z "$CI_REPO_CACHE_CREDENTIALS" ] || gcloud auth activate-service-account --key-file=$CI_REPO_CACHE_CREDENTIALS' - '[ -z "$CI_REPO_CACHE_CREDENTIALS" ] || gcloud auth activate-service-account --key-file=$CI_REPO_CACHE_CREDENTIALS'
script: script:
# Enable shallow repo caching only if the $ENABLE_SHALLOW_REPO_CACHING variable exists # Enable shallow repo caching only if the $ENABLE_SHALLOW_REPO_CACHING variable exists
# The `git repack` call works around a Git bug with shallow clones: https://gitlab.com/gitlab-org/git/-/issues/86
- if [ -n "$ENABLE_SHALLOW_REPO_CACHING" ]; then - if [ -n "$ENABLE_SHALLOW_REPO_CACHING" ]; then
cd .. && rm -rf $CI_PROJECT_NAME; cd .. && rm -rf $CI_PROJECT_NAME;
today=$(date +%Y-%m-%d); today=$(date +%Y-%m-%d);
@ -38,6 +39,7 @@ cache-repo:
echo "Cloning $CI_REPOSITORY_URL into $CI_PROJECT_NAME with commits from $one_year_ago."; echo "Cloning $CI_REPOSITORY_URL into $CI_PROJECT_NAME with commits from $one_year_ago.";
time git clone --progress --no-checkout --shallow-since=$one_year_ago $CI_REPOSITORY_URL $CI_PROJECT_NAME; time git clone --progress --no-checkout --shallow-since=$one_year_ago $CI_REPOSITORY_URL $CI_PROJECT_NAME;
cd $CI_PROJECT_NAME; cd $CI_PROJECT_NAME;
time git repack -d;
echo "Archiving $CI_PROJECT_NAME into /tmp/$SHALLOW_CLONE_TAR_FILENAME."; echo "Archiving $CI_PROJECT_NAME into /tmp/$SHALLOW_CLONE_TAR_FILENAME.";
time tar cf /tmp/$SHALLOW_CLONE_TAR_FILENAME .; time tar cf /tmp/$SHALLOW_CLONE_TAR_FILENAME .;
echo "GZipping /tmp/$SHALLOW_CLONE_TAR_FILENAME."; echo "GZipping /tmp/$SHALLOW_CLONE_TAR_FILENAME.";

View file

@ -131,6 +131,24 @@ rspec-ee frontend_fixture:
- .frontend:rules:default-frontend-jobs - .frontend:rules:default-frontend-jobs
parallel: 2 parallel: 2
graphql-schema-dump:
variables:
SETUP_DB: "false"
extends:
- .default-retry
- .rails-cache
- .default-before_script
- .frontend:rules:default-frontend-jobs
stage: fixtures
needs: []
script:
- bundle exec rake gitlab:graphql:schema:dump
artifacts:
name: graphql-schema
paths:
- tmp/tests/graphql/gitlab_schema.graphql
- tmp/tests/graphql/gitlab_schema.json
.frontend-test-base: .frontend-test-base:
extends: extends:
- .frontend-base - .frontend-base
@ -214,7 +232,7 @@ jest-integration:
- *yarn-install - *yarn-install
- run_timed_command "yarn jest:integration --ci" - run_timed_command "yarn jest:integration --ci"
# Don't use `needs` since `rspec-ee frontend_fixture` doesn't exist in `gitlab-foss` pipelines. # Don't use `needs` since `rspec-ee frontend_fixture` doesn't exist in `gitlab-foss` pipelines.
dependencies: ["rspec frontend_fixture", "rspec-ee frontend_fixture"] dependencies: ["rspec frontend_fixture", "rspec-ee frontend_fixture", "graphql-schema-dump"]
jest-as-if-foss: jest-as-if-foss:
extends: extends:

View file

@ -49,6 +49,14 @@
- vendor/ruby/ - vendor/ruby/
policy: pull policy: pull
.danger-review-cache:
cache:
key: "danger-review-v1"
paths:
- vendor/ruby/
- node_modules/
policy: pull
.qa-cache: .qa-cache:
cache: cache:
key: "qa-v2" key: "qa-v2"
@ -102,7 +110,7 @@
- name: postgres:11.6 - name: postgres:11.6
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine - name: redis:5.0-alpine
- name: elasticsearch:7.10.1 - name: elasticsearch:7.11.1
command: ["elasticsearch", "-E", "discovery.type=single-node"] command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables: variables:
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust
@ -113,7 +121,7 @@
- name: postgres:12 - name: postgres:12
command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"]
- name: redis:5.0-alpine - name: redis:5.0-alpine
- name: elasticsearch:7.10.1 - name: elasticsearch:7.11.1
command: ["elasticsearch", "-E", "discovery.type=single-node"] command: ["elasticsearch", "-E", "discovery.type=single-node"]
variables: variables:
POSTGRES_HOST_AUTH_METHOD: trust POSTGRES_HOST_AUTH_METHOD: trust

View file

@ -11,4 +11,3 @@ graphql-verify:
script: script:
- bundle exec rake gitlab:graphql:validate - bundle exec rake gitlab:graphql:validate
- bundle exec rake gitlab:graphql:check_docs - bundle exec rake gitlab:graphql:check_docs
- bundle exec rake gitlab:graphql:check_schema

View file

@ -6,7 +6,12 @@
- .default-before_script - .default-before_script
- .rails-cache - .rails-cache
.base-script: &base-script .minimal-bundle-install:
script:
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519"
.base-script:
script:
# Only install knapsack after bundle install! Otherwise oddly some native # Only install knapsack after bundle install! Otherwise oddly some native
# gems could not be found under some circumstance. No idea why, hours wasted. # gems could not be found under some circumstance. No idea why, hours wasted.
- run_timed_command "gem install knapsack --no-document" - run_timed_command "gem install knapsack --no-document"
@ -27,7 +32,7 @@
RECORD_DEPRECATIONS: "true" RECORD_DEPRECATIONS: "true"
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets", "detect-tests"] needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets", "detect-tests"]
script: script:
- *base-script - !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag ~level:migration" - rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag ~level:migration"
artifacts: artifacts:
expire_in: 31d expire_in: 31d
@ -49,7 +54,7 @@
.rspec-base-migration: .rspec-base-migration:
extends: .rails:rules:ee-and-foss-migration extends: .rails:rules:ee-and-foss-migration
script: script:
- *base-script - !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag level:migration" - rspec_paralellized_job "--tag ~quarantine --tag ~geo --tag level:migration"
.rspec-base-pg11: .rspec-base-pg11:
@ -82,7 +87,7 @@
.rspec-ee-base-geo: .rspec-ee-base-geo:
extends: .rspec-base extends: .rspec-base
script: script:
- *base-script - !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag geo" - rspec_paralellized_job "--tag ~quarantine --tag geo"
.rspec-ee-base-geo-pg11: .rspec-ee-base-geo-pg11:
@ -142,7 +147,7 @@ setup-test-env:
extends: extends:
- .rails-job-base - .rails-job-base
- .setup-test-env-cache - .setup-test-env-cache
- .rails:rules:default-refs-code-backstage-qa - .rails:rules:code-backstage-qa
- .use-pg11 - .use-pg11
stage: prepare stage: prepare
variables: variables:
@ -162,6 +167,7 @@ setup-test-env:
- tmp/tests/gitaly/gitaly-lfs-smudge - tmp/tests/gitaly/gitaly-lfs-smudge
- tmp/tests/gitaly/gitaly-ssh - tmp/tests/gitaly/gitaly-ssh
- tmp/tests/gitaly/internal/ - tmp/tests/gitaly/internal/
- tmp/tests/gitaly/internal_gitaly2/
- tmp/tests/gitaly/internal_sockets/ - tmp/tests/gitaly/internal_sockets/
- tmp/tests/gitaly/Makefile - tmp/tests/gitaly/Makefile
- tmp/tests/gitaly/praefect - tmp/tests/gitaly/praefect
@ -212,7 +218,7 @@ update-coverage-cache:
- .shared:rules:update-cache - .shared:rules:update-cache
stage: prepare stage: prepare
script: script:
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519" - !reference [.minimal-bundle-install, script]
cache: cache:
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up. policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.
@ -243,7 +249,7 @@ update-static-analysis-cache:
static-analysis: static-analysis:
extends: extends:
- .static-analysis-base - .static-analysis-base
- .rails:rules:default-refs-code-backstage-qa - .rails:rules:code-backstage-qa
stage: test stage: test
parallel: 4 parallel: 4
script: script:
@ -316,7 +322,7 @@ rspec db-library-code pg12:
- .rspec-base-pg12 - .rspec-base-pg12
- .rails:rules:ee-and-foss-db-library-code - .rails:rules:ee-and-foss-db-library-code
script: script:
- *base-script - !reference [.base-script, script]
- rspec_db_library_code - rspec_db_library_code
rspec fast_spec_helper: rspec fast_spec_helper:
@ -405,7 +411,7 @@ gitlab:setup:
# db/fixtures/development/04_project.rb thanks to SIZE=1 below # db/fixtures/development/04_project.rb thanks to SIZE=1 below
- git clone https://gitlab.com/gitlab-org/gitlab-test.git - git clone https://gitlab.com/gitlab-org/gitlab-test.git
/home/git/repositories/gitlab-org/gitlab-test.git /home/git/repositories/gitlab-org/gitlab-test.git
- *base-script - !reference [.base-script, script]
- force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup - force=yes SIZE=1 FIXTURE_PATH="db/fixtures/development" bundle exec rake gitlab:setup
artifacts: artifacts:
when: on_failure when: on_failure
@ -485,7 +491,7 @@ rspec:coverage:
- memory-static - memory-static
- memory-on-boot - memory-on-boot
script: script:
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519" - !reference [.minimal-bundle-install, script]
- run_timed_command "bundle exec scripts/merge-simplecov" - run_timed_command "bundle exec scripts/merge-simplecov"
- run_timed_command "bundle exec scripts/gather-test-memory-data" - run_timed_command "bundle exec scripts/gather-test-memory-data"
coverage: '/LOC \((\d+\.\d+%)\) covered.$/' coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
@ -522,7 +528,7 @@ rspec:feature-flags:
- memory-static - memory-static
- memory-on-boot - memory-on-boot
script: script:
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --without default development test production puma unicorn kerberos metrics omnibus ed25519" - !reference [.minimal-bundle-install, script]
- if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then - if [ "$CI_COMMIT_BRANCH" == "$CI_DEFAULT_BRANCH" ]; then
run_timed_command "bundle exec scripts/used-feature-flags" || (scripts/slack master-broken "☠️ \`${CI_JOB_NAME}\` failed! ☠️ See ${CI_JOB_URL}" ci_failing "GitLab Bot" && exit 1); run_timed_command "bundle exec scripts/used-feature-flags" || (scripts/slack master-broken "☠️ \`${CI_JOB_NAME}\` failed! ☠️ See ${CI_JOB_URL}" ci_failing "GitLab Bot" && exit 1);
else else
@ -762,7 +768,7 @@ rspec fail-fast:
stage: test stage: test
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets", "detect-tests"] needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets", "detect-tests"]
script: script:
- *base-script - !reference [.base-script, script]
- rspec_fail_fast tmp/matching_tests.txt "--tag ~quarantine" - rspec_fail_fast tmp/matching_tests.txt "--tag ~quarantine"
artifacts: artifacts:
expire_in: 7d expire_in: 7d
@ -775,7 +781,7 @@ rspec foss-impact:
- .rails:rules:rspec-foss-impact - .rails:rules:rspec-foss-impact
needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets as-if-foss", "detect-tests as-if-foss"] needs: ["setup-test-env", "retrieve-tests-metadata", "compile-test-assets as-if-foss", "detect-tests as-if-foss"]
script: script:
- *base-script - !reference [.base-script, script]
- rspec_matched_foss_tests tmp/matching_foss_tests.txt "--tag ~quarantine" - rspec_matched_foss_tests tmp/matching_foss_tests.txt "--tag ~quarantine"
artifacts: artifacts:
expire_in: 7d expire_in: 7d

View file

@ -15,7 +15,7 @@ code_quality:
stage: test stage: test
needs: [] needs: []
variables: variables:
CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.18" CODE_QUALITY_IMAGE: "registry.gitlab.com/gitlab-org/ci-cd/codequality:0.85.23"
script: script:
- | - |
if ! docker info &>/dev/null; then if ! docker info &>/dev/null; then

View file

@ -225,12 +225,22 @@ parallel-spec-reports:
danger-review: danger-review:
extends: extends:
- .default-retry - .default-retry
- .yarn-cache - .danger-review-cache
- .review:rules:danger - .review:rules:danger
image: registry.gitlab.com/gitlab-org/gitlab-build-images:danger
stage: test stage: test
needs: [] needs: []
script: before_script:
- source ./scripts/utils.sh - source ./scripts/utils.sh
- run_timed_command "bundle install --jobs=$(nproc) --path=vendor --retry=3 --quiet --with danger"
- run_timed_command "retry yarn install --frozen-lockfile" - run_timed_command "retry yarn install --frozen-lockfile"
- danger --fail-on-errors=true --verbose script:
- run_timed_command "bundle exec danger --fail-on-errors=true --verbose"
update-danger-review-cache:
extends:
- danger-review
- .shared:rules:update-cache
stage: prepare
script: echo 'Cache is fresh!'
cache:
policy: push # We want to rebuild the cache from scratch to ensure stale dependencies are cleaned up.

View file

@ -11,25 +11,25 @@
if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"' if: '$CI_PROJECT_NAME != "gitlab-foss" && $CI_PROJECT_NAME != "gitlab-ce" && $CI_PROJECT_NAME != "gitlabhq"'
.if-default-refs: &if-default-refs .if-default-refs: &if-default-refs
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI' if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME =~ /^[\d-]+-stable(-ee)?$/ || $CI_COMMIT_REF_NAME =~ /^\d+-\d+-auto-deploy-\d+$/ || $CI_COMMIT_REF_NAME =~ /^security\// || $CI_MERGE_REQUEST_IID || $CI_COMMIT_TAG || $FORCE_GITLAB_CI'
.if-master-refs: &if-master-refs .if-master-refs: &if-master-refs
if: '$CI_COMMIT_REF_NAME == "master"' if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main"'
.if-master-push: &if-master-push .if-master-push: &if-master-push
if: '$CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE == "push"' if: '($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_REF_NAME == "main") && $CI_PIPELINE_SOURCE == "push"'
.if-master-schedule-2-hourly: &if-master-schedule-2-hourly .if-master-schedule-2-hourly: &if-master-schedule-2-hourly
if: '$CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "2-hourly"' if: '($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_REF_NAME == "main") && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "2-hourly"'
.if-master-schedule-nightly: &if-master-schedule-nightly .if-master-schedule-nightly: &if-master-schedule-nightly
if: '$CI_COMMIT_BRANCH == "master" && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "nightly"' if: '($CI_COMMIT_BRANCH == "master" || $CI_COMMIT_REF_NAME == "main") && $CI_PIPELINE_SOURCE == "schedule" && $FREQUENCY == "nightly"'
.if-auto-deploy-branches: &if-auto-deploy-branches .if-auto-deploy-branches: &if-auto-deploy-branches
if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/' if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
.if-master-or-tag: &if-master-or-tag .if-master-or-tag: &if-master-or-tag
if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_TAG' if: '$CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_TAG'
.if-merge-request: &if-merge-request .if-merge-request: &if-merge-request
if: '$CI_MERGE_REQUEST_IID' if: '$CI_MERGE_REQUEST_IID'
@ -53,7 +53,7 @@
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_PIPELINE_SOURCE == "schedule"' if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_PIPELINE_SOURCE == "schedule"'
.if-dot-com-gitlab-org-master: &if-dot-com-gitlab-org-master .if-dot-com-gitlab-org-master: &if-dot-com-gitlab-org-master
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_COMMIT_REF_NAME == "master"' if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && ($CI_COMMIT_REF_NAME == "master" || $CI_COMMIT_REF_NAME == "main")'
.if-dot-com-gitlab-org-merge-request: &if-dot-com-gitlab-org-merge-request .if-dot-com-gitlab-org-merge-request: &if-dot-com-gitlab-org-merge-request
if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_MERGE_REQUEST_IID' if: '$CI_SERVER_HOST == "gitlab.com" && $CI_PROJECT_NAMESPACE == "gitlab-org" && $CI_MERGE_REQUEST_IID'
@ -149,6 +149,7 @@
- "{,ee/}{app/channels,app/controllers,app/finders,app/graphql,app/helpers,app/mailers,app/models,app/policies,app/presenters,app/serializers,app/services,app/uploaders,app/validators,app/views,app/workers}/**/*" - "{,ee/}{app/channels,app/controllers,app/finders,app/graphql,app/helpers,app/mailers,app/models,app/policies,app/presenters,app/serializers,app/services,app/uploaders,app/validators,app/views,app/workers}/**/*"
- "{,ee/}{bin,cable,config,db,lib}/**/*" - "{,ee/}{bin,cable,config,db,lib}/**/*"
- "{,ee/}spec/**/*.rb" - "{,ee/}spec/**/*.rb"
# CI changes
- ".gitlab-ci.yml" - ".gitlab-ci.yml"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- "*_VERSION" - "*_VERSION"
@ -162,6 +163,9 @@
- "{,ee/}spec/support/helpers/database/**/*" - "{,ee/}spec/support/helpers/database/**/*"
- "config/prometheus/common_metrics.yml" # Used by Gitlab::DatabaseImporters::CommonMetrics::Importer - "config/prometheus/common_metrics.yml" # Used by Gitlab::DatabaseImporters::CommonMetrics::Importer
- "{,ee/}app/models/project_statistics.rb" # Used to calculate sizes in migration specs - "{,ee/}app/models/project_statistics.rb" # Used to calculate sizes in migration specs
# CI changes
- ".gitlab-ci.yml"
- ".gitlab/ci/**/*"
.db-library-patterns: &db-library-patterns .db-library-patterns: &db-library-patterns
- "{,ee/}{,spec/}lib/{,ee/}gitlab/database/**/*" - "{,ee/}{,spec/}lib/{,ee/}gitlab/database/**/*"
@ -183,9 +187,11 @@
- ".csscomb.json" - ".csscomb.json"
- "Dockerfile.assets" - "Dockerfile.assets"
- "vendor/assets/**/*" - "vendor/assets/**/*"
# CI changes
- ".gitlab-ci.yml"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo}.yml"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
@ -193,6 +199,7 @@
- "config.ru" - "config.ru"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
- "data/whats_new/*.yml"
.qa-patterns: &qa-patterns .qa-patterns: &qa-patterns
- ".dockerignore" - ".dockerignore"
@ -205,9 +212,11 @@
- ".csscomb.json" - ".csscomb.json"
- "Dockerfile.assets" - "Dockerfile.assets"
- "vendor/assets/**/*" - "vendor/assets/**/*"
# CI changes
- ".gitlab-ci.yml"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo}.yml"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
@ -215,6 +224,7 @@
- "config.ru" - "config.ru"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
- "data/whats_new/*.yml"
# Backstage changes # Backstage changes
- "Dangerfile" - "Dangerfile"
- "danger/**/*" - "danger/**/*"
@ -230,9 +240,11 @@
- ".csscomb.json" - ".csscomb.json"
- "Dockerfile.assets" - "Dockerfile.assets"
- "vendor/assets/**/*" - "vendor/assets/**/*"
# CI changes
- ".gitlab-ci.yml"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo}.yml"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
@ -240,6 +252,7 @@
- "config.ru" - "config.ru"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
- "data/whats_new/*.yml"
# QA changes # QA changes
- ".dockerignore" - ".dockerignore"
- "qa/**/*" - "qa/**/*"
@ -251,9 +264,11 @@
- ".csscomb.json" - ".csscomb.json"
- "Dockerfile.assets" - "Dockerfile.assets"
- "vendor/assets/**/*" - "vendor/assets/**/*"
# CI changes
- ".gitlab-ci.yml"
- ".gitlab/ci/**/*" - ".gitlab/ci/**/*"
- ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}" - ".{eslintignore,gitattributes,nvmrc,prettierrc,stylelintrc,yamllint}"
- ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo,scss-lint}.yml" - ".{codeclimate,eslintrc,gitlab-ci,haml-lint,haml-lint_todo,rubocop,rubocop_todo,rubocop_manual_todo}.yml"
- "*_VERSION" - "*_VERSION"
- "Gemfile{,.lock}" - "Gemfile{,.lock}"
- "Rakefile" - "Rakefile"
@ -261,6 +276,7 @@
- "config.ru" - "config.ru"
- "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*" - "{,ee/}{app,bin,config,db,haml_lint,lib,locale,public,scripts,symbol,vendor}/**/*"
- "doc/api/graphql/reference/*" # Files in this folder are auto-generated - "doc/api/graphql/reference/*" # Files in this folder are auto-generated
- "data/whats_new/*.yml"
# Backstage changes # Backstage changes
- "Dangerfile" - "Dangerfile"
- "danger/**/*" - "danger/**/*"
@ -405,6 +421,7 @@
- <<: *if-security-merge-request - <<: *if-security-merge-request
changes: *code-backstage-patterns changes: *code-backstage-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
- <<: *if-merge-request-title-run-all-rspec
- <<: *if-merge-request - <<: *if-merge-request
changes: *ci-patterns changes: *ci-patterns
@ -445,7 +462,9 @@
.frontend:rules:bundle-size-review: .frontend:rules:bundle-size-review:
rules: rules:
- if: '$DANGER_GITLAB_API_TOKEN && $CI_MERGE_REQUEST_IID && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"' - <<: *if-not-canonical-namespace
when: never
- if: '$DANGER_GITLAB_API_TOKEN && $CI_MERGE_REQUEST_IID && ($CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master" || $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "main")'
changes: *frontend-patterns changes: *frontend-patterns
allow_failure: true allow_failure: true
@ -483,6 +502,7 @@
- <<: *if-security-merge-request - <<: *if-security-merge-request
changes: *code-qa-patterns changes: *code-qa-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
- <<: *if-merge-request-title-run-all-rspec
- <<: *if-merge-request - <<: *if-merge-request
changes: *ci-patterns changes: *ci-patterns
@ -602,10 +622,9 @@
- <<: *if-merge-request - <<: *if-merge-request
changes: ["config/**/*"] changes: ["config/**/*"]
.rails:rules:default-refs-code-backstage-qa: .rails:rules:code-backstage-qa:
rules: rules:
- <<: *if-default-refs - changes: *code-backstage-qa-patterns
changes: *code-backstage-qa-patterns
- <<: *if-merge-request-title-run-all-rspec - <<: *if-merge-request-title-run-all-rspec
.rails:rules:ee-only-migration: .rails:rules:ee-only-migration:
@ -700,6 +719,7 @@
changes: *db-patterns changes: *db-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *db-patterns changes: *db-patterns
- <<: *if-merge-request-title-run-all-rspec
- <<: *if-merge-request - <<: *if-merge-request
changes: *ci-patterns changes: *ci-patterns
@ -716,6 +736,7 @@
changes: *db-patterns changes: *db-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *db-patterns changes: *db-patterns
- <<: *if-merge-request-title-run-all-rspec
.rails:rules:as-if-foss-unit: .rails:rules:as-if-foss-unit:
rules: rules:
@ -725,6 +746,7 @@
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-run-all-rspec
- <<: *if-merge-request - <<: *if-merge-request
changes: *ci-patterns changes: *ci-patterns
@ -741,6 +763,7 @@
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-run-all-rspec
.rails:rules:as-if-foss-integration: .rails:rules:as-if-foss-integration:
rules: rules:
@ -750,6 +773,7 @@
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-run-all-rspec
- <<: *if-merge-request - <<: *if-merge-request
changes: *ci-patterns changes: *ci-patterns
@ -766,6 +790,7 @@
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *backend-patterns changes: *backend-patterns
- <<: *if-merge-request-title-run-all-rspec
.rails:rules:as-if-foss-system: .rails:rules:as-if-foss-system:
rules: rules:
@ -775,6 +800,7 @@
changes: *code-backstage-patterns changes: *code-backstage-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *code-backstage-patterns changes: *code-backstage-patterns
- <<: *if-merge-request-title-run-all-rspec
- <<: *if-merge-request - <<: *if-merge-request
changes: *ci-patterns changes: *ci-patterns
@ -791,6 +817,7 @@
changes: *code-backstage-patterns changes: *code-backstage-patterns
- <<: *if-merge-request-title-as-if-foss - <<: *if-merge-request-title-as-if-foss
changes: *code-backstage-patterns changes: *code-backstage-patterns
- <<: *if-merge-request-title-run-all-rspec
.rails:rules:ee-and-foss-db-library-code: .rails:rules:ee-and-foss-db-library-code:
rules: rules:
@ -809,8 +836,7 @@
.rails:rules:detect-tests: .rails:rules:detect-tests:
rules: rules:
- <<: *if-default-refs - changes: *code-backstage-patterns
changes: *code-backstage-patterns
- <<: *if-merge-request-title-run-all-rspec - <<: *if-merge-request-title-run-all-rspec
.rails:rules:rspec-foss-impact: .rails:rules:rspec-foss-impact:
@ -1123,8 +1149,7 @@
####################### #######################
.test-metadata:rules:retrieve-tests-metadata: .test-metadata:rules:retrieve-tests-metadata:
rules: rules:
- <<: *if-default-refs - changes: *code-backstage-patterns
changes: *code-backstage-patterns
when: on_success when: on_success
- <<: *if-merge-request-title-run-all-rspec - <<: *if-merge-request-title-run-all-rspec
@ -1136,7 +1161,6 @@
- ".gitlab/ci/test-metadata.gitlab-ci.yml" - ".gitlab/ci/test-metadata.gitlab-ci.yml"
- "scripts/rspec_helpers.sh" - "scripts/rspec_helpers.sh"
- <<: *if-dot-com-ee-schedule - <<: *if-dot-com-ee-schedule
changes: *code-backstage-patterns
################### ###################
# workhorse rules # # workhorse rules #

View file

@ -1,11 +0,0 @@
verify_lockfile:
stage: test
image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.7.2-git-2.29-lfs-2.9-node-14.15-yarn-1.22-graphicsmagick-1.3.34
needs: []
rules:
- changes:
- yarn.lock
script:
- npm config set @dappelt:registry https://gitlab.com/api/v4/projects/22564149/packages/npm/
- npx lockfile-lint@4.3.7 --path yarn.lock --allowed-hosts yarn --validate-https
- npx @dappelt/untamper-my-lockfile --lockfile yarn.lock

View file

@ -1,20 +1,10 @@
workhorse:
extends: .workhorse:rules:workhorse
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.14
stage: test
needs: []
script:
- rm .git/hooks/post-checkout
- git checkout .
- scripts/update-workhorse check
- make -C workhorse
workhorse:verify: workhorse:verify:
extends: .workhorse:rules:workhorse extends: .workhorse:rules:workhorse
image: ${GITLAB_DEPENDENCY_PROXY}golang:1.15 image: ${GITLAB_DEPENDENCY_PROXY}golang:1.15
stage: test stage: test
needs: [] needs: []
script: script:
- make -C workhorse # test build
- make -C workhorse verify - make -C workhorse verify
.workhorse:test: .workhorse:test:

View file

@ -1,14 +0,0 @@
#Design
<!-- This should include the contexts that determine the reproducibility (stickiness) of an experiment. This means that if you want the same behavior for a user, the context would be user, or if you want all users when viewing a specific project, the context would be the project being viewed, etc. -->
#Rollout strategy
<!-- This is currently called A/B test, which isn't accurate for multi-variants. Let's call this rollout strategy. It should outline the percentages for variants and if there's more than one step to this, each of those steps and the timing for those steps (e.g. 30 days after initial rollout). -->
#Inclusions and exclusions
<!-- These would be the rules for which given context (and are limited to context or resolvable at experiment time details) is included or excluded from the test. An example of this would be to only run an experiment on groups less than N number of days old. -->
#Segmentation
<!-- Rules for always saying context with these criteria always get this variant. For instance, if you want to always give groups less than N number of days old the experiment experience, they are specified here. This is different from the exclusion rules above. -->
#Tracking

View file

@ -10,9 +10,10 @@ The changes need to become an official part of the product.
- [ ] Determine whether the feature should apply to SaaS and/or self-managed - [ ] Determine whether the feature should apply to SaaS and/or self-managed
- [ ] Determine whether the feature should apply to EE - and which tiers - and/or Core - [ ] Determine whether the feature should apply to EE - and which tiers - and/or Core
- [ ] Determine if tracking should be kept as is, removed, or modified. - [ ] Determine if tracking should be kept as is, removed, or modified.
- [ ] Migrate experiment to a default enabled [feature flag](https://docs.gitlab.com/ee/development/feature_flags/development.html) for one milestone and add a changelog. Converting to a feature flag can be skipped at the ICs discretion if risk is deemed low with consideration to both SaaS and (if applicable) self managed.
- [ ] Ensure any relevant documentation has been updated. - [ ] Ensure any relevant documentation has been updated.
- [ ] In the next milestone, [remove the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up). - [ ] Consider changes to any `feature_category:` introduced by the experiment if ownership is changing (PM for Growth and PM for the new category as DRIs)
- [ ] Optional: Migrate experiment to a default enabled [feature flag](https://docs.gitlab.com/ee/development/feature_flags) for one milestone and add a changelog. Converting to a feature flag can be skipped at the ICs discretion if risk is deemed low with consideration to both SaaS and (if applicable) self managed
- [ ] In the next milestone, [remove the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) if applicable
- [ ] After the flag removal is deployed, [clean up the feature/experiment feature flags](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel - [ ] After the flag removal is deployed, [clean up the feature/experiment feature flags](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
/label ~"feature" ~"feature::maintenance" ~"workflow::scheduling" ~"growth experiment" ~"feature flag" /label ~"feature" ~"feature::maintenance" ~"workflow::scheduling" ~"growth experiment" ~"feature flag"

View file

@ -0,0 +1,25 @@
<!-- Title suggestion: Experiment: [description] -->
# Experiment Summary
<!-- Quick rundown of what is being done -->
# Design
<!-- This should include the contexts that determine the reproducibility (stickiness) of an experiment. This means that if you want the same behavior for a user, the context would be user, or if you want all users when viewing a specific project, the context would be the project being viewed, etc. -->
# Rollout strategy
<!-- This is currently called A/B test, which isn't accurate for multi-variants. Let's call this rollout strategy. It should outline the percentages for variants and if there's more than one step to this, each of those steps and the timing for those steps (e.g. 30 days after initial rollout). -->
# Inclusions and exclusions
<!-- These would be the rules for which given context (and are limited to context or resolvable at experiment time details) is included or excluded from the test. An example of this would be to only run an experiment on groups less than N number of days old. -->
# Segmentation
<!-- Rules for always saying context with these criteria always get this variant. For instance, if you want to always give groups less than N number of days old the experiment experience, they are specified here. This is different from the exclusion rules above. -->
# Tracking Details
- [json schema](https://gitlab.com/gitlab-org/iglu/-/blob/master/public/schemas/com.gitlab/gitlab_experiment/jsonschema/0-3-0) used in `gitlab-experiment` tracking.
- see [taxonomy](https://docs.gitlab.com/ee/development/snowplow.html#structured-event-taxonomy) for a guide.
| activity | category | action | label | context | property | value |
| -------- | -------- | ------ | ----- | ------- | -------- | ----- |
| | | | | json schema | | |

View file

@ -18,7 +18,7 @@ Remove the `:feature_name` feature flag ...
### What can we monitor to detect problems with this? ### What can we monitor to detect problems with this?
<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can alse be useful to review --> <!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can also be useful to review -->
## Beta groups/projects ## Beta groups/projects

View file

@ -1,6 +1,6 @@
## Description ## Description
As the name implies, the purpose of the template is to detail underperforming queries for futher investigation. As the name implies, the purpose of the template is to detail underperforming queries for further investigation.
### Steps ### Steps
@ -14,8 +14,10 @@ As the name implies, the purpose of the template is to detail underperforming qu
Please provide as many of these fields as possible when submitting a query performance report. Please provide as many of these fields as possible when submitting a query performance report.
- TPS - Queries per second (on average or peak)
- Duration - Number of calls per second and relative to total number of calls
- Query timings (on average or peak)
- Database time relative to total database time
- Source of calls (Sidekiq, WebAPI, etc) - Source of calls (Sidekiq, WebAPI, etc)
- Query ID - Query ID
- SQL Statement - SQL Statement

View file

@ -0,0 +1,94 @@
<!-- Title suggestion: [Experiment Tracking] experiment-key - description of experiment -->
## What
Track the status of an experiment through to removal.
1. Experiment key: `<experiment-key>`
1. Framework: `experimentation.rb` | `gitlab_experiment`
1. Feature flag name: <experiment-key>_experiment_percentage` | `<experiment-key>`
This is an experiment tracking issue for: `<issue or epic link>`
using the scoped [experiment label](https://about.gitlab.com/handbook/engineering/development/growth/#experiment-tracking-issue).
As well as defining the experiment rollout and cleanup, this issue incorporates the relevant
[`Feature Flag Roll Out`](https://gitlab.com/gitlab-org/gitlab/-/edit/master/.gitlab/issue_templates/Feature%20Flag%20Roll%20Out.md) steps.
## Owners
- Team: `group::TEAM_NAME`
- Most appropriate slack channel to reach out to: `#g_TEAM_NAME`
- Best individual to reach out to: NAME
## Expectations
### What are we expecting to happen?
### What might happen if this goes wrong?
### What can we monitor to detect problems with this?
<!-- Which dashboards from https://dashboards.gitlab.net are most relevant? Sentry errors reports can alse be useful to review -->
### Tracked data
<!-- brief description or link to issue or Sisense dashboard -->
Note: you can utilize [CXL calculator](https://cxl.com/ab-test-calculator/) to determine if your experiment has reached signifigance, it also includes an estimate for how much longer an experiment will need to run for before reaching signifigance.
### Staging Test
<!-- For experiments using `experimentation.rb`: To force this experiment on staging use `?force_experiment=<experiment-key>` -->
<!-- list any steps required to setup this experiment, and link to a separate Staging environment test issue is applicable -->
<!-- uncomment if testing with specific groups/projects on GitLab.com
## Beta groups/projects
If applicable, any groups/projects that are happy to have this feature turned on early. Some organizations may wish to test big changes they are interested in with a small subset of users ahead of time for example.
- `gitlab-org/gitlab` project
- `gitlab-org`/`gitlab-com` groups
- ...
-->
### Experiment tracking log
<!-- Add an overview and method for modifying the feature flag
* Runtime: 30 days or until we reach statistical significance
* We will roll this out behind a feature flag and expose this to 20% of users to start then ramp it up from there.
* feature flag based on experiment key `<experiment-key>` (see `experimentation.rb` in GitLab, append '_experiment_percentage')
`/chatops run feature set <experiment-key>_experiment_percentage <INITIAL_PERCENTAGE>`
-->
<!-- Add bullet points to track changes to the rollout of this experiment (feature flag changes)
* YYYY-MM-DD UTC - initial rollout to 20% of users
* TBD - review - increase to 50% of users
-->
### Experiment Results
<!-- update when experiment in/validated, set the scoped `~experiment::` status accordingly -->
## Roll Out Steps
- [ ] Confirm that QA tests pass with the feature flag enabled (if you're unsure how, contact the relevant [stable counterpart in the Quality department](https://about.gitlab.com/handbook/engineering/quality/#individual-contributors))
- [ ] Enable on staging (`/chatops run feature set feature_name true --staging`)
- [ ] Test on staging
- [ ] Ensure that documentation has been updated
- [ ] Enable on GitLab.com for individual groups/projects listed above and verify behaviour (`/chatops run feature set --project=gitlab-org/gitlab feature_name true`)
- [ ] Coordinate a time to enable the flag with the SRE oncall and release managers
- In `#production` mention `@sre-oncall` and `@release-managers`. Once an SRE on call and Release Manager on call confirm, you can proceed with the rollout
- [ ] Announce on the issue an estimated time this will be enabled on GitLab.com
- [ ] Enable on GitLab.com by running chatops command in `#production` (`/chatops run feature set feature_name true`)
- [ ] Cross post chatops Slack command to `#support_gitlab-com` ([more guidance when this is necessary in the dev docs](https://docs.gitlab.com/ee/development/feature_flags/controls.html#where-to-run-commands)) and in your team channel
- [ ] Announce on the issue that the flag has been enabled
- [ ] Remove experiment code and feature flag and add changelog entry - a separate [cleanup issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Experiment%20Successful%20Cleanup) might be required
- [ ] After the flag removal is deployed, [clean up the feature flag](https://docs.gitlab.com/ee/development/feature_flags/controls.html#cleaning-up) by running chatops command in `#production` channel
## Rollback Steps
- [ ] This feature can be disabled by running the following Chatops command:
```
/chatops run feature set feature_name false
```
/label ~"feature flag" ~"devops::growth" ~"growth experiment" ~"experiment tracking" ~Engineering ~"workflow::scheduling" ~"experiment::pending"

View file

@ -201,7 +201,6 @@ linters:
- 'app/views/projects/imports/new.html.haml' - 'app/views/projects/imports/new.html.haml'
- 'app/views/projects/imports/show.html.haml' - 'app/views/projects/imports/show.html.haml'
- 'app/views/projects/issues/_new_branch.html.haml' - 'app/views/projects/issues/_new_branch.html.haml'
- 'app/views/projects/issues/import_csv/_modal.html.haml'
- 'app/views/projects/issues/show.html.haml' - 'app/views/projects/issues/show.html.haml'
- 'app/views/projects/jobs/_header.html.haml' - 'app/views/projects/jobs/_header.html.haml'
- 'app/views/projects/jobs/_table.html.haml' - 'app/views/projects/jobs/_table.html.haml'
@ -213,12 +212,6 @@ linters:
- 'app/views/projects/mattermosts/new.html.haml' - 'app/views/projects/mattermosts/new.html.haml'
- 'app/views/projects/merge_requests/_commits.html.haml' - 'app/views/projects/merge_requests/_commits.html.haml'
- 'app/views/projects/merge_requests/_mr_title.html.haml' - 'app/views/projects/merge_requests/_mr_title.html.haml'
- 'app/views/projects/merge_requests/conflicts/_commit_stats.html.haml'
- 'app/views/projects/merge_requests/conflicts/_file_actions.html.haml'
- 'app/views/projects/merge_requests/conflicts/_submit_form.html.haml'
- 'app/views/projects/merge_requests/conflicts/components/_diff_file_editor.html.haml'
- 'app/views/projects/merge_requests/conflicts/components/_inline_conflict_lines.html.haml'
- 'app/views/projects/merge_requests/conflicts/show.html.haml'
- 'app/views/projects/merge_requests/creations/_diffs.html.haml' - 'app/views/projects/merge_requests/creations/_diffs.html.haml'
- 'app/views/projects/merge_requests/creations/_new_compare.html.haml' - 'app/views/projects/merge_requests/creations/_new_compare.html.haml'
- 'app/views/projects/merge_requests/creations/_new_submit.html.haml' - 'app/views/projects/merge_requests/creations/_new_submit.html.haml'
@ -297,8 +290,6 @@ linters:
- 'app/views/shared/milestones/_sidebar.html.haml' - 'app/views/shared/milestones/_sidebar.html.haml'
- 'app/views/shared/milestones/_top.html.haml' - 'app/views/shared/milestones/_top.html.haml'
- 'app/views/shared/notes/_hints.html.haml' - 'app/views/shared/notes/_hints.html.haml'
- 'app/views/shared/notifications/_button.html.haml'
- 'app/views/shared/notifications/_new_button.html.haml'
- 'app/views/shared/runners/_runner_description.html.haml' - 'app/views/shared/runners/_runner_description.html.haml'
- 'app/views/shared/runners/show.html.haml' - 'app/views/shared/runners/show.html.haml'
- 'app/views/shared/snippets/_header.html.haml' - 'app/views/shared/snippets/_header.html.haml'

View file

@ -1,9 +1,9 @@
/app/assets/javascripts/locale/**/app.js /app/assets/javascripts/locale/**/app.js
/fixtures/lib/gitlab/graphql/
/node_modules/ /node_modules/
/public/ /public/
/vendor/ /vendor/
/tmp/ /tmp/
doc/api/graphql/reference/gitlab_schema.graphql
# ignore stylesheets for now as this clashes with our linter # ignore stylesheets for now as this clashes with our linter
*.css *.css

View file

@ -7,8 +7,10 @@ require:
- rubocop-rspec - rubocop-rspec
inherit_from: inherit_from:
- .rubocop_manual_todo.yml <% unless ENV['REVEAL_RUBOCOP_TODO'] == '1' %>
- .rubocop_todo.yml - '.rubocop_manual_todo.yml'
- '.rubocop_todo.yml'
<% end %>
- ./rubocop/rubocop-migrations.yml - ./rubocop/rubocop-migrations.yml
- ./rubocop/rubocop-usage-data.yml - ./rubocop/rubocop-usage-data.yml
- ./rubocop/rubocop-code_reuse.yml - ./rubocop/rubocop-code_reuse.yml
@ -16,6 +18,7 @@ inherit_from:
inherit_mode: inherit_mode:
merge: merge:
- Include - Include
- Exclude
AllCops: AllCops:
TargetRubyVersion: 2.7 TargetRubyVersion: 2.7
@ -87,6 +90,17 @@ RSpec/FilePath:
- 'ee/spec/frontend/fixtures/*' - 'ee/spec/frontend/fixtures/*'
- 'spec/requests/api/v3/*' - 'spec/requests/api/v3/*'
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:
Max: 28
AllowSubject: true
Exclude:
- 'spec/migrations/**/*.rb'
- 'spec/lib/gitlab/background_migration/populate_project_snippet_statistics_spec.rb'
- 'spec/lib/gitlab/background_migration/populate_finding_uuid_for_vulnerability_feedback_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/populate_uuids_for_security_findings_spec.rb'
- 'ee/spec/lib/gitlab/background_migration/user_mentions/create_resource_user_mention_spec.rb'
Naming/FileName: Naming/FileName:
ExpectMatchingDefinition: true ExpectMatchingDefinition: true
Exclude: Exclude:
@ -240,7 +254,7 @@ Gitlab/Json:
- 'db/**/*' - 'db/**/*'
- 'qa/**/*' - 'qa/**/*'
- 'scripts/**/*' - 'scripts/**/*'
- 'lib/rspec_flaky/**/*' - 'tooling/rspec_flaky/**/*'
- 'lib/quality/**/*' - 'lib/quality/**/*'
- 'tooling/danger/**/*' - 'tooling/danger/**/*'
@ -595,3 +609,23 @@ FactoryBot/InlineAssociation:
Include: Include:
- 'spec/factories/**/*.rb' - 'spec/factories/**/*.rb'
- 'ee/spec/factories/**/*.rb' - 'ee/spec/factories/**/*.rb'
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/321982
Gitlab/NamespacedClass:
Exclude:
- 'config/**/*.rb'
- 'db/**/*.rb'
- 'ee/bin/**/*'
- 'ee/db/**/*.rb'
- 'ee/elastic/**/*.rb'
- 'scripts/**/*'
- 'spec/migrations/**/*.rb'
Lint/HashCompareByIdentity:
Enabled: true
Lint/RedundantSafeNavigation:
Enabled: true
Style/ClassEqualityComparison:
Enabled: true

View file

@ -10,57 +10,48 @@
# - guidelines for use found in # - guidelines for use found in
# https://docs.gitlab.com/ee/development/contributing/style_guides.html#resolving-rubocop-exceptions. # https://docs.gitlab.com/ee/development/contributing/style_guides.html#resolving-rubocop-exceptions.
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/322903
Graphql/Descriptions:
Exclude:
- 'app/graphql/types/access_level_enum.rb'
- 'app/graphql/types/base_enum.rb'
- 'app/graphql/types/ci/pipeline_config_source_enum.rb'
- 'app/graphql/types/ci/pipeline_status_enum.rb'
- 'app/graphql/types/container_expiration_policy_cadence_enum.rb'
- 'app/graphql/types/container_expiration_policy_keep_enum.rb'
- 'app/graphql/types/container_expiration_policy_older_than_enum.rb'
- 'app/graphql/types/notes/position_type_enum.rb'
- 'app/graphql/types/packages/package_type_enum.rb'
- 'app/graphql/types/snippets/blob_action_enum.rb'
- 'app/graphql/types/snippets/type_enum.rb'
- 'app/graphql/types/snippets/visibility_scopes_enum.rb'
- 'app/graphql/types/todo_action_enum.rb'
- 'app/graphql/types/tree/type_enum.rb'
- 'ee/app/graphql/ee/types/list_limit_metric_enum.rb'
- 'ee/app/graphql/types/alert_management/payload_alert_field_name_enum.rb'
- 'ee/app/graphql/types/epic_state_enum.rb'
- 'ee/app/graphql/types/health_status_enum.rb'
- 'ee/app/graphql/types/iteration_state_enum.rb'
- 'ee/app/graphql/types/requirements_management/requirement_state_enum.rb'
- 'ee/app/graphql/types/requirements_management/test_report_state_enum.rb'
- 'ee/app/graphql/types/security_scanner_type_enum.rb'
- 'ee/app/graphql/types/vulnerability/issue_link_type_enum.rb'
- 'ee/app/graphql/types/vulnerability_grade_enum.rb'
- 'ee/app/graphql/types/vulnerability_report_type_enum.rb'
- 'ee/app/graphql/types/vulnerability_severity_enum.rb'
- 'ee/app/graphql/types/vulnerability_state_enum.rb'
# WIP See https://gitlab.com/gitlab-org/gitlab/-/issues/267606
FactoryBot/InlineAssociation: FactoryBot/InlineAssociation:
Exclude: Exclude:
- 'ee/spec/factories/analytics/cycle_analytics/group_stages.rb'
- 'ee/spec/factories/geo/event_log.rb'
- 'ee/spec/factories/merge_request_blocks.rb'
- 'ee/spec/factories/vulnerabilities/feedback.rb'
- 'spec/factories/atlassian_identities.rb' - 'spec/factories/atlassian_identities.rb'
- 'spec/factories/events.rb' - 'spec/factories/events.rb'
- 'spec/factories/git_wiki_commit_details.rb' - 'spec/factories/git_wiki_commit_details.rb'
- 'spec/factories/gitaly/commit.rb' - 'spec/factories/gitaly/commit.rb'
- 'spec/factories/go_module_commits.rb'
- 'spec/factories/go_module_versions.rb'
- 'spec/factories/go_modules.rb'
- 'spec/factories/group_group_links.rb' - 'spec/factories/group_group_links.rb'
- 'spec/factories/import_export_uploads.rb' - 'spec/factories/import_export_uploads.rb'
- 'spec/factories/uploads.rb'
- 'spec/factories/wiki_pages.rb'
InternalAffairs/DeprecateCopHelper: # issue to resolve: https://gitlab.com/gitlab-org/gitlab/-/issues/276734
Exclude:
- 'spec/rubocop/cop/migration/safer_boolean_column_spec.rb'
- 'spec/rubocop/cop/migration/remove_index_spec.rb'
- 'spec/rubocop/cop/migration/add_index_spec.rb'
- 'spec/rubocop/cop/migration/drop_table_spec.rb'
- 'spec/rubocop/cop/migration/hash_index_spec.rb'
- 'spec/rubocop/cop/migration/datetime_spec.rb'
- 'spec/rubocop/cop/migration/add_column_with_default_spec.rb'
- 'spec/rubocop/cop/migration/prevent_strings_spec.rb'
- 'spec/rubocop/cop/migration/add_timestamps_spec.rb'
- 'spec/rubocop/cop/migration/add_concurrent_index_spec.rb'
- 'spec/rubocop/cop/migration/update_column_in_batches_spec.rb'
- 'spec/rubocop/cop/migration/complex_indexes_require_name_spec.rb'
- 'spec/rubocop/cop/migration/refer_to_index_by_name_spec.rb'
- 'spec/rubocop/cop/migration/schedule_async_spec.rb'
- 'spec/rubocop/cop/migration/timestamps_spec.rb'
- 'spec/rubocop/cop/migration/remove_concurrent_index_spec.rb'
- 'spec/rubocop/cop/migration/add_columns_to_wide_tables_spec.rb'
- 'spec/rubocop/cop/migration/with_lock_retries_disallowed_method_spec.rb'
- 'spec/rubocop/cop/migration/add_reference_spec.rb'
- 'spec/rubocop/cop/migration/remove_column_spec.rb'
- 'spec/rubocop/cop/migration/create_table_with_foreign_keys_spec.rb'
- 'spec/rubocop/cop/migration/add_concurrent_foreign_key_spec.rb'
- 'spec/rubocop/cop/migration/with_lock_retries_with_change_spec.rb'
- 'spec/rubocop/cop/migration/add_limit_to_text_columns_spec.rb'
- 'spec/rubocop/cop/avoid_return_from_blocks_spec.rb'
- 'spec/rubocop/cop/avoid_route_redirect_leading_slash_spec.rb'
- 'spec/rubocop/cop/put_group_routes_under_scope_spec.rb'
- 'spec/rubocop/cop/sidekiq_options_queue_spec.rb'
- 'spec/rubocop/cop/ignored_columns_spec.rb'
- 'spec/rubocop/cop/prefer_class_methods_over_module_spec.rb'
# WIP: See https://gitlab.com/gitlab-org/gitlab/-/issues/220040
Rails/SaveBang: Rails/SaveBang:
Exclude: Exclude:
- 'ee/spec/controllers/projects/merge_requests_controller_spec.rb' - 'ee/spec/controllers/projects/merge_requests_controller_spec.rb'
@ -516,8 +507,8 @@ Rails/TimeZone:
- 'lib/json_web_token/token.rb' - 'lib/json_web_token/token.rb'
- 'lib/object_storage/direct_upload.rb' - 'lib/object_storage/direct_upload.rb'
- 'lib/quality/seeders/issues.rb' - 'lib/quality/seeders/issues.rb'
- 'lib/rspec_flaky/flaky_example.rb' - 'tooling/rspec_flaky/flaky_example.rb'
- 'lib/rspec_flaky/report.rb' - 'tooling/rspec_flaky/report.rb'
- 'lib/tasks/gitlab/assets.rake' - 'lib/tasks/gitlab/assets.rake'
- 'lib/tasks/gitlab/backup.rake' - 'lib/tasks/gitlab/backup.rake'
- 'lib/tasks/gitlab/cleanup.rake' - 'lib/tasks/gitlab/cleanup.rake'
@ -583,9 +574,9 @@ Rails/TimeZone:
- 'spec/lib/gitlab/x509/signature_spec.rb' - 'spec/lib/gitlab/x509/signature_spec.rb'
- 'spec/lib/grafana/time_window_spec.rb' - 'spec/lib/grafana/time_window_spec.rb'
- 'spec/lib/json_web_token/hmac_token_spec.rb' - 'spec/lib/json_web_token/hmac_token_spec.rb'
- 'spec/lib/rspec_flaky/flaky_example_spec.rb' - 'spec/tooling/rspec_flaky/flaky_example_spec.rb'
- 'spec/lib/rspec_flaky/listener_spec.rb' - 'spec/tooling/rspec_flaky/listener_spec.rb'
- 'spec/lib/rspec_flaky/report_spec.rb' - 'spec/tooling/rspec_flaky/report_spec.rb'
RSpec/TimecopFreeze: RSpec/TimecopFreeze:
Exclude: Exclude:
@ -658,8 +649,8 @@ RSpec/TimecopFreeze:
- 'spec/lib/gitlab/puma_logging/json_formatter_spec.rb' - 'spec/lib/gitlab/puma_logging/json_formatter_spec.rb'
- 'spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb' - 'spec/lib/gitlab/sidekiq_logging/structured_logger_spec.rb'
- 'spec/lib/json_web_token/hmac_token_spec.rb' - 'spec/lib/json_web_token/hmac_token_spec.rb'
- 'spec/lib/rspec_flaky/flaky_example_spec.rb' - 'spec/tooling/rspec_flaky/flaky_example_spec.rb'
- 'spec/lib/rspec_flaky/listener_spec.rb' - 'spec/tooling/rspec_flaky/listener_spec.rb'
- 'spec/models/active_session_spec.rb' - 'spec/models/active_session_spec.rb'
- 'spec/serializers/entity_date_helper_spec.rb' - 'spec/serializers/entity_date_helper_spec.rb'
- 'spec/support/cycle_analytics_helpers/test_generation.rb' - 'spec/support/cycle_analytics_helpers/test_generation.rb'
@ -812,7 +803,7 @@ RSpec/AnyInstanceOf:
- 'ee/spec/services/slash_commands/global_slack_handler_spec.rb' - 'ee/spec/services/slash_commands/global_slack_handler_spec.rb'
- 'ee/spec/support/helpers/ee/stub_configuration.rb' - 'ee/spec/support/helpers/ee/stub_configuration.rb'
- 'ee/spec/support/shared_examples/controllers/analytics/cycle_analytics/shared_stage_shared_examples.rb' - 'ee/spec/support/shared_examples/controllers/analytics/cycle_analytics/shared_stage_shared_examples.rb'
- 'ee/spec/support/shared_examples/features/gold_trial_callout_shared_examples.rb' - 'ee/spec/support/shared_examples/features/ultimate_trial_callout_shared_examples.rb'
- 'ee/spec/support/shared_examples/lib/gitlab/geo/geo_logs_event_source_info_shared_examples.rb' - 'ee/spec/support/shared_examples/lib/gitlab/geo/geo_logs_event_source_info_shared_examples.rb'
- 'ee/spec/support/shared_examples/models/member_shared_examples.rb' - 'ee/spec/support/shared_examples/models/member_shared_examples.rb'
- 'ee/spec/support/shared_examples/services/base_sync_service_shared_examples.rb' - 'ee/spec/support/shared_examples/services/base_sync_service_shared_examples.rb'
@ -1207,22 +1198,9 @@ RSpec/AnyInstanceOf:
- 'spec/workers/wait_for_cluster_creation_worker_spec.rb' - 'spec/workers/wait_for_cluster_creation_worker_spec.rb'
- 'ee/spec/workers/security/auto_fix_worker_spec.rb' - 'ee/spec/workers/security/auto_fix_worker_spec.rb'
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/321982
Gitlab/NamespacedClass: Gitlab/NamespacedClass:
Exclude: Exclude:
- 'config/**/*.rb'
- 'db/**/*.rb'
- 'ee/bin/**/*'
- 'ee/db/**/*.rb'
- 'ee/elastic/**/*.rb'
- 'scripts/**/*'
- 'spec/migrations/**/*.rb'
# The list above represents the permanent exclusions for this rule
# due to the fact these files are related to infrastructure code.
# This list should eventually be moved to .rubocop.yml after all TODOs
# are addressed.
#
# The list below represents the classes that require
# a namespace as they make the domain related code.
- 'app/channels/issues_channel.rb' - 'app/channels/issues_channel.rb'
- 'app/controllers/abuse_reports_controller.rb' - 'app/controllers/abuse_reports_controller.rb'
- 'app/controllers/acme_challenges_controller.rb' - 'app/controllers/acme_challenges_controller.rb'
@ -2021,7 +1999,6 @@ Gitlab/NamespacedClass:
- 'app/validators/untrusted_regexp_validator.rb' - 'app/validators/untrusted_regexp_validator.rb'
- 'app/validators/nested_attributes_duplicates_validator.rb' - 'app/validators/nested_attributes_duplicates_validator.rb'
- 'app/validators/x509_certificate_credentials_validator.rb' - 'app/validators/x509_certificate_credentials_validator.rb'
- 'app/validators/zoom_url_validator.rb'
- 'app/workers/admin_email_worker.rb' - 'app/workers/admin_email_worker.rb'
- 'app/workers/approve_blocked_pending_approval_users_worker.rb' - 'app/workers/approve_blocked_pending_approval_users_worker.rb'
- 'app/workers/archive_trace_worker.rb' - 'app/workers/archive_trace_worker.rb'
@ -2296,6 +2273,7 @@ Gitlab/NamespacedClass:
- 'ee/app/policies/instance_security_dashboard_policy.rb' - 'ee/app/policies/instance_security_dashboard_policy.rb'
- 'ee/app/policies/issuable_metric_image_policy.rb' - 'ee/app/policies/issuable_metric_image_policy.rb'
- 'ee/app/policies/iteration_policy.rb' - 'ee/app/policies/iteration_policy.rb'
- 'ee/app/policies/push_rule_policy.rb'
- 'ee/app/policies/saml_provider_policy.rb' - 'ee/app/policies/saml_provider_policy.rb'
- 'ee/app/policies/timelog_policy.rb' - 'ee/app/policies/timelog_policy.rb'
- 'ee/app/policies/vulnerability_policy.rb' - 'ee/app/policies/vulnerability_policy.rb'
@ -2372,7 +2350,6 @@ Gitlab/NamespacedClass:
- 'ee/app/serializers/vulnerability_note_serializer.rb' - 'ee/app/serializers/vulnerability_note_serializer.rb'
- 'ee/app/serializers/vulnerability_serializer.rb' - 'ee/app/serializers/vulnerability_serializer.rb'
- 'ee/app/services/clear_namespace_shared_runners_minutes_service.rb' - 'ee/app/services/clear_namespace_shared_runners_minutes_service.rb'
- 'ee/app/services/fetch_subscription_plans_service.rb'
- 'ee/app/services/ldap_group_reset_service.rb' - 'ee/app/services/ldap_group_reset_service.rb'
- 'ee/app/services/start_pull_mirroring_service.rb' - 'ee/app/services/start_pull_mirroring_service.rb'
- 'ee/app/services/timebox_report_service.rb' - 'ee/app/services/timebox_report_service.rb'
@ -2473,3 +2450,60 @@ Gitlab/NamespacedClass:
- 'spec/support/sidekiq_middleware.rb' - 'spec/support/sidekiq_middleware.rb'
- 'spec/tasks/gitlab/task_helpers_spec.rb' - 'spec/tasks/gitlab/task_helpers_spec.rb'
- 'spec/uploaders/object_storage_spec.rb' - 'spec/uploaders/object_storage_spec.rb'
# WIP: https://gitlab.com/gitlab-org/gitlab/-/issues/322739
Style/HashTransformation:
Exclude:
- 'app/controllers/projects/branches_controller.rb'
- 'app/finders/ci/commit_statuses_finder.rb'
- 'app/helpers/learn_gitlab_helper.rb'
- 'app/models/ci/build_trace_chunk.rb'
- 'app/models/concerns/cache_markdown_field.rb'
- 'app/models/gpg_key.rb'
- 'app/presenters/packages/npm/package_presenter.rb'
- 'app/services/ci/pipeline_processing/atomic_processing_service/status_collection.rb'
- 'app/services/ci/retry_build_service.rb'
- 'app/services/packages/nuget/create_dependency_service.rb'
- 'ee/app/models/ee/ci/build.rb'
- 'ee/app/models/productivity_analytics.rb'
- 'ee/app/models/sca/license_compliance.rb'
- 'ee/app/services/security/store_report_service.rb'
- 'ee/lib/ee/gitlab/auth/ldap/sync/group.rb'
- 'ee/lib/ee/gitlab/usage_data.rb'
- 'ee/lib/gitlab/custom_file_templates.rb'
- 'ee/spec/elastic_integration/global_search_spec.rb'
- 'ee/spec/lib/ee/gitlab/application_context_spec.rb'
- 'lib/api/helpers/packages/conan/api_helpers.rb'
- 'lib/api/projects.rb'
- 'lib/atlassian/jira_connect/client.rb'
- 'lib/banzai/filter/repository_link_filter.rb'
- 'lib/gitlab/ci/config/entry/product/variables.rb'
- 'lib/gitlab/ci/config/entry/variables.rb'
- 'lib/gitlab/ci/variables/collection.rb'
- 'lib/gitlab/ci/variables/helpers.rb'
- 'lib/gitlab/git/commit.rb'
- 'lib/gitlab/import_sources.rb'
- 'lib/gitlab/language_detection.rb'
- 'lib/gitlab/metrics/samplers/database_sampler.rb'
- 'lib/gitlab/metrics/subscribers/active_record.rb'
- 'lib/gitlab/phabricator_import/project_creator.rb'
- 'lib/gitlab/prometheus_client.rb'
- 'lib/gitlab/repository_hash_cache.rb'
- 'lib/gitlab/static_site_editor/config/file_config.rb'
- 'lib/gitlab/template/base_template.rb'
- 'lib/gitlab/usage_data_counters/base_counter.rb'
- 'lib/gitlab/usage_data_counters/note_counter.rb'
- 'spec/lib/atlassian/jira_connect/serializers/pull_request_entity_spec.rb'
- 'spec/lib/gitlab/ci/status/composite_spec.rb'
- 'spec/lib/gitlab/conflict/file_spec.rb'
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
- 'spec/models/concerns/featurable_spec.rb'
- 'spec/models/event_spec.rb'
- 'spec/models/packages/dependency_spec.rb'
- 'spec/requests/api/graphql/project/alert_management/alert/assignees_spec.rb'
- 'spec/requests/api/graphql/project/alert_management/alert/notes_spec.rb'
- 'spec/requests/api/graphql/project/alert_management/alert/todos_spec.rb'
- 'spec/requests/api/projects_spec.rb'
- 'spec/support/helpers/graphql_helpers.rb'
- 'spec/support/import_export/project_tree_expectations.rb'
- 'spec/support/shared_contexts/services/projects/container_repository/delete_tags_service_shared_context.rb'

View file

@ -1,17 +1,17 @@
# This configuration was generated by # This configuration was generated by
# `rubocop --auto-gen-config` # `rubocop --auto-gen-config`
# on 2021-01-11 15:49:32 UTC using RuboCop version 0.91.1. # on 2021-02-24 14:52:20 UTC using RuboCop version 0.93.1.
# The point is for the user to remove these configuration records # The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base. # one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new # Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again. # versions of RuboCop, may require this file to be generated again.
# Offense count: 313 # Offense count: 314
# Cop supports --auto-correct. # Cop supports --auto-correct.
Capybara/CurrentPathExpectation: Capybara/CurrentPathExpectation:
Enabled: false Enabled: false
# Offense count: 218 # Offense count: 221
Capybara/VisibilityMatcher: Capybara/VisibilityMatcher:
Enabled: false Enabled: false
@ -25,7 +25,7 @@ Graphql/IDType:
Exclude: Exclude:
- 'app/graphql/mutations/boards/issues/issue_move_list.rb' - 'app/graphql/mutations/boards/issues/issue_move_list.rb'
# Offense count: 2054 # Offense count: 2270
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth. # Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: with_first_argument, with_fixed_indentation # SupportedStyles: with_first_argument, with_fixed_indentation
@ -50,28 +50,28 @@ Layout/BeginEndAlignment:
- 'lib/gitlab/phabricator_import/project_creator.rb' - 'lib/gitlab/phabricator_import/project_creator.rb'
- 'scripts/gitaly_test.rb' - 'scripts/gitaly_test.rb'
# Offense count: 52 # Offense count: 54
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowAliasSyntax, AllowedMethods. # Configuration parameters: AllowAliasSyntax, AllowedMethods.
# AllowedMethods: alias_method, public, protected, private # AllowedMethods: alias_method, public, protected, private
Layout/EmptyLinesAroundAttributeAccessor: Layout/EmptyLinesAroundAttributeAccessor:
Enabled: false Enabled: false
# Offense count: 721 # Offense count: 771
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth. # Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_brackets # SupportedStyles: special_inside_parentheses, consistent, align_brackets
Layout/FirstArrayElementIndentation: Layout/FirstArrayElementIndentation:
Enabled: false Enabled: false
# Offense count: 1592 # Offense count: 1684
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth. # Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: special_inside_parentheses, consistent, align_braces # SupportedStyles: special_inside_parentheses, consistent, align_braces
Layout/FirstHashElementIndentation: Layout/FirstHashElementIndentation:
Enabled: false Enabled: false
# Offense count: 3019 # Offense count: 3233
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle. # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
# SupportedHashRocketStyles: key, separator, table # SupportedHashRocketStyles: key, separator, table
@ -80,14 +80,14 @@ Layout/FirstHashElementIndentation:
Layout/HashAlignment: Layout/HashAlignment:
Enabled: false Enabled: false
# Offense count: 73 # Offense count: 14544
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
# URISchemes: http, https # URISchemes: http, https
Layout/LineLength: Layout/LineLength:
Max: 1313 Max: 1313
# Offense count: 163 # Offense count: 170
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, IndentationWidth. # Configuration parameters: EnforcedStyle, IndentationWidth.
# SupportedStyles: aligned, indented # SupportedStyles: aligned, indented
@ -113,22 +113,23 @@ Layout/RescueEnsureAlignment:
Layout/SpaceAroundMethodCallOperator: Layout/SpaceAroundMethodCallOperator:
Enabled: false Enabled: false
# Offense count: 725 # Offense count: 754
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: require_no_space, require_space # SupportedStyles: require_no_space, require_space
Layout/SpaceInLambdaLiteral: Layout/SpaceInLambdaLiteral:
Enabled: false Enabled: false
# Offense count: 218 # Offense count: 1209
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters. # Configuration parameters: EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
# SupportedStyles: space, no_space # SupportedStyles: space, no_space
# SupportedStylesForEmptyBraces: space, no_space # SupportedStylesForEmptyBraces: space, no_space
Layout/SpaceInsideBlockBraces: Layout/SpaceInsideBlockBraces:
Enabled: false Enabled: false
EnforcedStyle: space
# Offense count: 559 # Offense count: 585
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: space, no_space # SupportedStyles: space, no_space
@ -141,7 +142,6 @@ Lint/BinaryOperatorWithIdenticalOperands:
- 'ee/spec/lib/ee/gitlab/application_context_spec.rb' - 'ee/spec/lib/ee/gitlab/application_context_spec.rb'
- 'spec/helpers/visibility_level_helper_spec.rb' - 'spec/helpers/visibility_level_helper_spec.rb'
- 'spec/lib/gitlab/conan_token_spec.rb' - 'spec/lib/gitlab/conan_token_spec.rb'
- 'spec/tooling/danger/sidekiq_queues_spec.rb'
- 'spec/lib/gitlab/git/conflict/parser_spec.rb' - 'spec/lib/gitlab/git/conflict/parser_spec.rb'
- 'spec/lib/gitlab/graphql/lazy_spec.rb' - 'spec/lib/gitlab/graphql/lazy_spec.rb'
- 'spec/models/ci/build_trace_chunk_spec.rb' - 'spec/models/ci/build_trace_chunk_spec.rb'
@ -150,8 +150,9 @@ Lint/BinaryOperatorWithIdenticalOperands:
- 'spec/models/metrics/dashboard/annotation_spec.rb' - 'spec/models/metrics/dashboard/annotation_spec.rb'
- 'spec/models/repository_spec.rb' - 'spec/models/repository_spec.rb'
- 'spec/models/ssh_host_key_spec.rb' - 'spec/models/ssh_host_key_spec.rb'
- 'spec/tooling/danger/sidekiq_queues_spec.rb'
# Offense count: 83 # Offense count: 84
Lint/ConstantDefinitionInBlock: Lint/ConstantDefinitionInBlock:
Enabled: false Enabled: false
@ -174,12 +175,12 @@ Lint/IdentityComparison:
- 'spec/tooling/danger/weightage/maintainers_spec.rb' - 'spec/tooling/danger/weightage/maintainers_spec.rb'
- 'spec/tooling/danger/weightage/reviewers_spec.rb' - 'spec/tooling/danger/weightage/reviewers_spec.rb'
# Offense count: 184 # Offense count: 208
# Configuration parameters: MaximumRangeSize. # Configuration parameters: MaximumRangeSize.
Lint/MissingCopEnableDirective: Lint/MissingCopEnableDirective:
Enabled: false Enabled: false
# Offense count: 14 # Offense count: 13
Lint/MixedRegexpCaptureTypes: Lint/MixedRegexpCaptureTypes:
Exclude: Exclude:
- 'app/models/alert_management/alert.rb' - 'app/models/alert_management/alert.rb'
@ -188,7 +189,6 @@ Lint/MixedRegexpCaptureTypes:
- 'ee/lib/gitlab/code_owners/reference_extractor.rb' - 'ee/lib/gitlab/code_owners/reference_extractor.rb'
- 'lib/gitlab/ci/pipeline/expression/lexeme/string.rb' - 'lib/gitlab/ci/pipeline/expression/lexeme/string.rb'
- 'lib/gitlab/dependency_linker/gemfile_linker.rb' - 'lib/gitlab/dependency_linker/gemfile_linker.rb'
- 'lib/gitlab/diff/inline_diff.rb'
- 'lib/gitlab/diff/suggestions_parser.rb' - 'lib/gitlab/diff/suggestions_parser.rb'
- 'lib/gitlab/github_import/representation/note.rb' - 'lib/gitlab/github_import/representation/note.rb'
- 'lib/gitlab/metrics/system.rb' - 'lib/gitlab/metrics/system.rb'
@ -197,11 +197,26 @@ Lint/MixedRegexpCaptureTypes:
- 'lib/gitlab/slash_commands/issue_new.rb' - 'lib/gitlab/slash_commands/issue_new.rb'
- 'lib/gitlab/slash_commands/run.rb' - 'lib/gitlab/slash_commands/run.rb'
# Offense count: 141 # Offense count: 200
# Cop supports --auto-correct. # Cop supports --auto-correct.
Lint/RedundantCopDisableDirective: Lint/RedundantCopDisableDirective:
Enabled: false Enabled: false
# Offense count: 9
# Cop supports --auto-correct.
# Configuration parameters: AllowedMethods.
# AllowedMethods: instance_of?, kind_of?, is_a?, eql?, respond_to?, equal?
Lint/RedundantSafeNavigation:
Exclude:
- 'app/controllers/concerns/labels_as_hash.rb'
- 'app/policies/note_policy.rb'
- 'app/services/users/update_canonical_email_service.rb'
- 'ee/app/presenters/iteration_presenter.rb'
- 'ee/app/services/ee/members/destroy_service.rb'
- 'ee/lib/ee/gitlab/email/handler/reply_processing.rb'
- 'qa/qa/specs/helpers/quarantine.rb'
- 'spec/controllers/boards/issues_controller_spec.rb'
# Offense count: 1 # Offense count: 1
Lint/SelfAssignment: Lint/SelfAssignment:
Exclude: Exclude:
@ -225,57 +240,20 @@ Lint/UnreachableLoop:
Lint/UselessMethodDefinition: Lint/UselessMethodDefinition:
Enabled: false Enabled: false
# Offense count: 7 # Offense count: 5
# Configuration parameters: IgnoredMethods, Max. # Configuration parameters: IgnoredMethods.
Metrics/AbcSize: Metrics/AbcSize:
Exclude: Max: 61
- 'app/helpers/issuables_helper.rb'
- 'app/services/merge_requests/build_service.rb'
- 'app/services/projects/create_service.rb'
- 'lib/api/helpers.rb'
- 'lib/gitlab/lograge/custom_options.rb'
- 'lib/gitlab/rack_attack.rb'
- 'qa/qa/resource/repository/push.rb'
# Offense count: 15 # Offense count: 13
# Configuration parameters: IgnoredMethods, Max. # Configuration parameters: IgnoredMethods.
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:
Exclude: Max: 25
- 'app/services/projects/create_service.rb'
- 'app/services/system_hooks_service.rb'
- 'ee/app/controllers/ee/groups_controller.rb'
- 'ee/app/helpers/ee/groups_helper.rb'
- 'ee/lib/security/ci_configuration/sast_build_actions.rb'
- 'lib/banzai/filter/abstract_reference_filter.rb'
- 'lib/declarative_policy/runner.rb'
- 'lib/gitlab/conflict/file.rb'
- 'tooling/danger/roulette.rb'
- 'lib/gitlab/diff/parser.rb'
- 'lib/gitlab/rack_attack.rb'
- 'lib/gitlab/sidekiq_cluster/cli.rb'
- 'lib/gitlab/utils/merge_hash.rb'
- 'lib/kramdown/parser/atlassian_document_format.rb'
- 'spec/support/cycle_analytics_helpers/test_generation.rb'
# Offense count: 15 # Offense count: 14
# Configuration parameters: IgnoredMethods, Max. # Configuration parameters: IgnoredMethods.
Metrics/PerceivedComplexity: Metrics/PerceivedComplexity:
Exclude: Max: 25
- 'app/helpers/submodule_helper.rb'
- 'app/helpers/tab_helper.rb'
- 'app/services/projects/create_service.rb'
- 'ee/app/controllers/ee/groups_controller.rb'
- 'ee/app/helpers/ee/groups_helper.rb'
- 'ee/lib/security/ci_configuration/sast_build_actions.rb'
- 'lib/banzai/filter/abstract_reference_filter.rb'
- 'lib/banzai/renderer.rb'
- 'lib/declarative_policy/runner.rb'
- 'lib/gitlab/conflict/file.rb'
- 'tooling/danger/roulette.rb'
- 'lib/gitlab/rack_attack.rb'
- 'lib/gitlab/sidekiq_cluster/cli.rb'
- 'lib/gitlab/utils/merge_hash.rb'
- 'spec/support/cycle_analytics_helpers/test_generation.rb'
# Offense count: 1 # Offense count: 1
# Cop supports --auto-correct. # Cop supports --auto-correct.
@ -283,7 +261,7 @@ Migration/DepartmentName:
Exclude: Exclude:
- 'app/models/commit.rb' - 'app/models/commit.rb'
# Offense count: 184 # Offense count: 196
# Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, Regex, IgnoreExecutableScripts, AllowedAcronyms. # Configuration parameters: ExpectMatchingDefinition, CheckDefinitionPathHierarchy, Regex, IgnoreExecutableScripts, AllowedAcronyms.
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS # AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
Naming/FileName: Naming/FileName:
@ -300,7 +278,7 @@ Naming/HeredocDelimiterCase:
- 'spec/support/helpers/repo_helpers.rb' - 'spec/support/helpers/repo_helpers.rb'
- 'spec/support/helpers/seed_repo.rb' - 'spec/support/helpers/seed_repo.rb'
# Offense count: 308 # Offense count: 321
# Configuration parameters: ForbiddenDelimiters. # Configuration parameters: ForbiddenDelimiters.
# ForbiddenDelimiters: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$)) # ForbiddenDelimiters: (?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))
Naming/HeredocDelimiterNaming: Naming/HeredocDelimiterNaming:
@ -314,7 +292,7 @@ Naming/MethodParameterName:
- 'lib/gitlab/diff/inline_diff.rb' - 'lib/gitlab/diff/inline_diff.rb'
- 'spec/support/helpers/key_generator_helper.rb' - 'spec/support/helpers/key_generator_helper.rb'
# Offense count: 206 # Offense count: 218
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: PreferredName. # Configuration parameters: PreferredName.
Naming/RescuedExceptionsVariableName: Naming/RescuedExceptionsVariableName:
@ -326,17 +304,17 @@ Performance/AncestorsInclude:
Exclude: Exclude:
- 'lib/gitlab/ci/config/extendable/entry.rb' - 'lib/gitlab/ci/config/extendable/entry.rb'
# Offense count: 39 # Offense count: 40
# Cop supports --auto-correct. # Cop supports --auto-correct.
Performance/BlockGivenWithExplicitBlock: Performance/BlockGivenWithExplicitBlock:
Enabled: false Enabled: false
# Offense count: 28 # Offense count: 29
# Configuration parameters: MinSize. # Configuration parameters: MinSize.
Performance/CollectionLiteralInLoop: Performance/CollectionLiteralInLoop:
Enabled: false Enabled: false
# Offense count: 37 # Offense count: 41
# Cop supports --auto-correct. # Cop supports --auto-correct.
Performance/ConstantRegexp: Performance/ConstantRegexp:
Enabled: false Enabled: false
@ -382,7 +360,6 @@ Performance/DeleteSuffix:
- 'app/workers/concerns/application_worker.rb' - 'app/workers/concerns/application_worker.rb'
- 'ee/app/models/geo/upload_registry.rb' - 'ee/app/models/geo/upload_registry.rb'
- 'ee/app/workers/geo/file_download_dispatch_worker/attachment_job_finder.rb' - 'ee/app/workers/geo/file_download_dispatch_worker/attachment_job_finder.rb'
- 'lib/sentry/client/issue.rb'
# Offense count: 13 # Offense count: 13
# Cop supports --auto-correct. # Cop supports --auto-correct.
@ -395,7 +372,7 @@ Performance/Detect:
- 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb' - 'spec/lib/gitlab/import_export/project/tree_restorer_spec.rb'
- 'spec/models/event_spec.rb' - 'spec/models/event_spec.rb'
# Offense count: 116 # Offense count: 121
Performance/MethodObjectAsBlock: Performance/MethodObjectAsBlock:
Enabled: false Enabled: false
@ -439,7 +416,7 @@ Performance/Sum:
- 'lib/peek/views/detailed_view.rb' - 'lib/peek/views/detailed_view.rb'
- 'spec/models/namespace/root_storage_statistics_spec.rb' - 'spec/models/namespace/root_storage_statistics_spec.rb'
# Offense count: 14717 # Offense count: 15209
# Configuration parameters: Prefixes. # Configuration parameters: Prefixes.
# Prefixes: when, with, without # Prefixes: when, with, without
RSpec/ContextWording: RSpec/ContextWording:
@ -452,22 +429,17 @@ RSpec/EmptyExampleGroup:
- 'ee/spec/services/personal_access_tokens/revoke_invalid_tokens_spec.rb' - 'ee/spec/services/personal_access_tokens/revoke_invalid_tokens_spec.rb'
- 'spec/services/projects/prometheus/alerts/notify_service_spec.rb' - 'spec/services/projects/prometheus/alerts/notify_service_spec.rb'
# Offense count: 1365 # Offense count: 1428
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: method_call, block # SupportedStyles: method_call, block
RSpec/ExpectChange: RSpec/ExpectChange:
Enabled: false Enabled: false
# Offense count: 889 # Offense count: 930
RSpec/ExpectInHook: RSpec/ExpectInHook:
Enabled: false Enabled: false
# Offense count: 16403
# Configuration parameters: AllowSubject.
RSpec/MultipleMemoizedHelpers:
Max: 40
# Offense count: 2352 # Offense count: 2352
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: Strict, EnforcedStyle, AllowedExplicitMatchers. # Configuration parameters: Strict, EnforcedStyle, AllowedExplicitMatchers.
@ -475,27 +447,27 @@ RSpec/MultipleMemoizedHelpers:
RSpec/PredicateMatcher: RSpec/PredicateMatcher:
Enabled: false Enabled: false
# Offense count: 112 # Offense count: 118
RSpec/RepeatedExampleGroupBody: RSpec/RepeatedExampleGroupBody:
Enabled: false Enabled: false
# Offense count: 219 # Offense count: 225
RSpec/RepeatedExampleGroupDescription: RSpec/RepeatedExampleGroupDescription:
Enabled: false Enabled: false
# Offense count: 655 # Offense count: 667
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: and_return, block # SupportedStyles: and_return, block
RSpec/ReturnFromStub: RSpec/ReturnFromStub:
Enabled: false Enabled: false
# Offense count: 596 # Offense count: 610
# Cop supports --auto-correct. # Cop supports --auto-correct.
RSpec/ScatteredLet: RSpec/ScatteredLet:
Enabled: false Enabled: false
# Offense count: 6 # Offense count: 4
RSpec/ScatteredSetup: RSpec/ScatteredSetup:
Exclude: Exclude:
- 'spec/requests/api/jobs_spec.rb' - 'spec/requests/api/jobs_spec.rb'
@ -520,7 +492,7 @@ RSpec/VariableName:
- 'spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb' - 'spec/support/shared_examples/requests/api/graphql/group_and_project_boards_query_shared_examples.rb'
- 'spec/support/shared_examples/services/boards/boards_list_service_shared_examples.rb' - 'spec/support/shared_examples/services/boards/boards_list_service_shared_examples.rb'
# Offense count: 25 # Offense count: 26
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
@ -549,25 +521,25 @@ Rails/BelongsTo:
- 'app/models/deployment.rb' - 'app/models/deployment.rb'
- 'app/models/environment.rb' - 'app/models/environment.rb'
# Offense count: 90 # Offense count: 93
# Configuration parameters: Database, Include. # Configuration parameters: Database, Include.
# SupportedDatabases: mysql, postgresql # SupportedDatabases: mysql, postgresql
# Include: db/migrate/*.rb # Include: db/migrate/*.rb
Rails/BulkChangeTable: Rails/BulkChangeTable:
Enabled: false Enabled: false
# Offense count: 153 # Offense count: 155
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/ContentTag: Rails/ContentTag:
Enabled: false Enabled: false
# Offense count: 300 # Offense count: 313
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: db/migrate/*.rb # Include: db/migrate/*.rb
Rails/CreateTableWithTimestamps: Rails/CreateTableWithTimestamps:
Enabled: false Enabled: false
# Offense count: 347 # Offense count: 361
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: slashes, arguments # SupportedStyles: slashes, arguments
Rails/FilePath: Rails/FilePath:
@ -589,13 +561,13 @@ Rails/FindById:
- 'spec/finders/concerns/finder_methods_spec.rb' - 'spec/finders/concerns/finder_methods_spec.rb'
- 'spec/finders/concerns/finder_with_cross_project_access_spec.rb' - 'spec/finders/concerns/finder_with_cross_project_access_spec.rb'
# Offense count: 346 # Offense count: 354
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
Rails/HasManyOrHasOneDependent: Rails/HasManyOrHasOneDependent:
Enabled: false Enabled: false
# Offense count: 539 # Offense count: 537
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/helpers/**/*.rb # Include: app/helpers/**/*.rb
Rails/HelperInstanceVariable: Rails/HelperInstanceVariable:
@ -615,11 +587,11 @@ Rails/IndexBy:
- 'ee/lib/gitlab/analytics/type_of_work/tasks_by_type.rb' - 'ee/lib/gitlab/analytics/type_of_work/tasks_by_type.rb'
- 'ee/lib/gitlab/elastic/document_reference.rb' - 'ee/lib/gitlab/elastic/document_reference.rb'
- 'ee/lib/gitlab/group_plans_preloader.rb' - 'ee/lib/gitlab/group_plans_preloader.rb'
- 'tooling/danger/sidekiq_queues.rb'
- 'lib/gitlab/database/count/reltuples_count_strategy.rb' - 'lib/gitlab/database/count/reltuples_count_strategy.rb'
- 'lib/gitlab/language_detection.rb' - 'lib/gitlab/language_detection.rb'
- 'tooling/danger/sidekiq_queues.rb'
# Offense count: 45 # Offense count: 47
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/IndexWith: Rails/IndexWith:
Enabled: false Enabled: false
@ -629,24 +601,23 @@ Rails/Inquiry:
Exclude: Exclude:
- 'spec/helpers/labels_helper_spec.rb' - 'spec/helpers/labels_helper_spec.rb'
# Offense count: 115 # Offense count: 118
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/models/**/*.rb # Include: app/models/**/*.rb
Rails/InverseOf: Rails/InverseOf:
Enabled: false Enabled: false
# Offense count: 60 # Offense count: 62
# Configuration parameters: Include. # Configuration parameters: Include.
# Include: app/controllers/**/*.rb # Include: app/controllers/**/*.rb
Rails/LexicallyScopedActionFilter: Rails/LexicallyScopedActionFilter:
Enabled: false Enabled: false
# Offense count: 3 # Offense count: 2
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/LinkToBlank: Rails/LinkToBlank:
Exclude: Exclude:
- 'app/helpers/projects_helper.rb' - 'app/helpers/projects_helper.rb'
- 'app/helpers/wiki_helper.rb'
- 'ee/app/helpers/ee/user_callouts_helper.rb' - 'ee/app/helpers/ee/user_callouts_helper.rb'
# Offense count: 1 # Offense count: 1
@ -662,12 +633,12 @@ Rails/MailerName:
Rails/NegateInclude: Rails/NegateInclude:
Enabled: false Enabled: false
# Offense count: 44 # Offense count: 46
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/Pick: Rails/Pick:
Enabled: false Enabled: false
# Offense count: 110 # Offense count: 123
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/Pluck: Rails/Pluck:
Enabled: false Enabled: false
@ -679,7 +650,7 @@ Rails/Pluck:
Rails/RakeEnvironment: Rails/RakeEnvironment:
Enabled: false Enabled: false
# Offense count: 58 # Offense count: 62
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/RedundantForeignKey: Rails/RedundantForeignKey:
Enabled: false Enabled: false
@ -699,23 +670,23 @@ Rails/ShortI18n:
- 'app/uploaders/content_type_whitelist.rb' - 'app/uploaders/content_type_whitelist.rb'
- 'spec/views/shared/runners/show.html.haml_spec.rb' - 'spec/views/shared/runners/show.html.haml_spec.rb'
# Offense count: 1080 # Offense count: 1144
# Configuration parameters: ForbiddenMethods, AllowedMethods. # Configuration parameters: ForbiddenMethods, AllowedMethods.
# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all # ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all
Rails/SkipsModelValidations: Rails/SkipsModelValidations:
Enabled: false Enabled: false
# Offense count: 251 # Offense count: 278
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/SquishedSQLHeredocs: Rails/SquishedSQLHeredocs:
Enabled: false Enabled: false
# Offense count: 45 # Offense count: 44
# Cop supports --auto-correct. # Cop supports --auto-correct.
Rails/WhereEquals: Rails/WhereEquals:
Enabled: false Enabled: false
# Offense count: 40 # Offense count: 44
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: exists, where # SupportedStyles: exists, where
@ -744,7 +715,7 @@ Security/YAMLLoad:
Style/AccessorGrouping: Style/AccessorGrouping:
Enabled: false Enabled: false
# Offense count: 12 # Offense count: 11
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ArrayCoercion: Style/ArrayCoercion:
Exclude: Exclude:
@ -756,12 +727,11 @@ Style/ArrayCoercion:
- 'db/post_migrate/20200311130802_schedule_populate_user_highest_roles_table.rb' - 'db/post_migrate/20200311130802_schedule_populate_user_highest_roles_table.rb'
- 'db/post_migrate/20200805152108_migrate_null_external_diff_store_to_local_value.rb' - 'db/post_migrate/20200805152108_migrate_null_external_diff_store_to_local_value.rb'
- 'db/post_migrate/20200806173633_migrate_null_package_files_file_store_to_local_value.rb' - 'db/post_migrate/20200806173633_migrate_null_package_files_file_store_to_local_value.rb'
- 'ee/app/services/geo/blob_verification_secondary_service.rb'
- 'ee/app/services/geo/repository_verification_secondary_service.rb' - 'ee/app/services/geo/repository_verification_secondary_service.rb'
- 'ee/lib/ee/banzai/pipeline/gfm_pipeline.rb' - 'ee/lib/ee/banzai/pipeline/gfm_pipeline.rb'
- 'spec/support/helpers/lfs_http_helpers.rb' - 'spec/support/helpers/lfs_http_helpers.rb'
# Offense count: 183 # Offense count: 188
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: percent_q, bare_percent # SupportedStyles: percent_q, bare_percent
@ -775,20 +745,35 @@ Style/BisectedAttrAccessor:
- 'lib/system_check/base_check.rb' - 'lib/system_check/base_check.rb'
- 'qa/qa/resource/api_fabricator.rb' - 'qa/qa/resource/api_fabricator.rb'
# Offense count: 36 # Offense count: 42
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/CaseLikeIf: Style/CaseLikeIf:
Enabled: false Enabled: false
# Offense count: 15 # Offense count: 10
# Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods.
# IgnoredMethods: ==, equal?, eql?
Style/ClassEqualityComparison:
Exclude:
- 'app/finders/security/jobs_finder.rb'
- 'app/services/projects/overwrite_project_service.rb'
- 'app/uploaders/dependency_proxy/file_uploader.rb'
- 'ee/app/graphql/resolvers/vulnerabilities/issue_links_resolver.rb'
- 'lib/gitlab/background_migration/user_mentions/models/note.rb'
- 'lib/gitlab/diff/file.rb'
- 'lib/gitlab/git.rb'
- 'lib/gitlab/import_export/relation_tree_restorer.rb'
- 'spec/requests/api/services_spec.rb'
- 'spec/support/shared_examples/lib/gitlab/import_export/relation_factory_shared_examples.rb'
# Offense count: 13
Style/CombinableLoops: Style/CombinableLoops:
Exclude: Exclude:
- 'app/models/application_setting.rb'
- 'ee/db/fixtures/development/30_customizable_cycle_analytics.rb' - 'ee/db/fixtures/development/30_customizable_cycle_analytics.rb'
- 'ee/lib/gitlab/audit/events/preloader.rb' - 'ee/lib/gitlab/audit/events/preloader.rb'
- 'ee/spec/finders/snippets_finder_spec.rb' - 'ee/spec/finders/snippets_finder_spec.rb'
- 'ee/spec/lib/ee/gitlab/background_migration/remove_duplicate_cs_findings_spec.rb' - 'ee/spec/lib/ee/gitlab/background_migration/remove_duplicate_cs_findings_spec.rb'
- 'rubocop/code_reuse_helpers.rb'
- 'spec/features/merge_request/user_suggests_changes_on_diff_spec.rb' - 'spec/features/merge_request/user_suggests_changes_on_diff_spec.rb'
- 'spec/finders/packages/group_packages_finder_spec.rb' - 'spec/finders/packages/group_packages_finder_spec.rb'
- 'spec/migrations/cleanup_optimistic_locking_nulls_pt2_fixed_spec.rb' - 'spec/migrations/cleanup_optimistic_locking_nulls_pt2_fixed_spec.rb'
@ -814,14 +799,14 @@ Style/EachWithObject:
- 'lib/gitlab/i18n/po_linter.rb' - 'lib/gitlab/i18n/po_linter.rb'
- 'lib/gitlab/import_export/members_mapper.rb' - 'lib/gitlab/import_export/members_mapper.rb'
# Offense count: 53 # Offense count: 55
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: empty, nil, both # SupportedStyles: empty, nil, both
Style/EmptyElse: Style/EmptyElse:
Enabled: false Enabled: false
# Offense count: 197 # Offense count: 205
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: compact, expanded # SupportedStyles: compact, expanded
@ -835,66 +820,75 @@ Style/ExpandPathArguments:
- 'cable/config.ru' - 'cable/config.ru'
- 'config.ru' - 'config.ru'
# Offense count: 116 # Offense count: 118
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ExplicitBlockArgument: Style/ExplicitBlockArgument:
Enabled: false Enabled: false
# Offense count: 555 # Offense count: 581
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: format, sprintf, percent # SupportedStyles: format, sprintf, percent
Style/FormatString: Style/FormatString:
Enabled: false Enabled: false
# Offense count: 61 # Offense count: 67
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/GlobalStdStream: Style/GlobalStdStream:
Enabled: false Enabled: false
# Offense count: 879 # Offense count: 897
# Configuration parameters: MinBodyLength. # Configuration parameters: MinBodyLength.
Style/GuardClause: Style/GuardClause:
Enabled: false Enabled: false
# Offense count: 56 # Offense count: 59
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: braces, no_braces # SupportedStyles: braces, no_braces
Style/HashAsLastArrayItem: Style/HashAsLastArrayItem:
Enabled: false Enabled: false
# Offense count: 66 # Offense count: 70
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/HashEachMethods: Style/HashEachMethods:
Enabled: false Enabled: false
# Offense count: 33 # Offense count: 34
# Configuration parameters: AllowIfModifier. # Configuration parameters: AllowIfModifier.
Style/IfInsideElse: Style/IfInsideElse:
Enabled: false Enabled: false
# Offense count: 1888 # Offense count: 1934
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/IfUnlessModifier: Style/IfUnlessModifier:
Enabled: false Enabled: false
# Offense count: 68 # Offense count: 64
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/KeywordParametersOrder: Style/KeywordParametersOrder:
Enabled: false Enabled: false
# Offense count: 431 # Offense count: 458
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: line_count_dependent, lambda, literal # SupportedStyles: line_count_dependent, lambda, literal
Style/Lambda: Style/Lambda:
Enabled: false Enabled: false
# Offense count: 20 # Offense count: 21
Style/MissingRespondToMissing: Style/MissingRespondToMissing:
Enabled: false Enabled: false
# Offense count: 5
Style/MixinUsage:
Exclude:
- 'spec/factories/ci/builds.rb'
- 'spec/factories/ci/job_artifacts.rb'
- 'spec/factories/lfs_objects.rb'
- 'spec/factories/notes.rb'
- 'spec/lib/gitlab/import_export/version_checker_spec.rb'
# Offense count: 35 # Offense count: 35
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, MinBodyLength. # Configuration parameters: EnforcedStyle, MinBodyLength.
@ -902,36 +896,44 @@ Style/MissingRespondToMissing:
Style/Next: Style/Next:
Enabled: false Enabled: false
# Offense count: 98 # Offense count: 101
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedOctalStyle. # Configuration parameters: EnforcedOctalStyle.
# SupportedOctalStyles: zero_with_o, zero_only # SupportedOctalStyles: zero_with_o, zero_only
Style/NumericLiteralPrefix: Style/NumericLiteralPrefix:
Enabled: false Enabled: false
# Offense count: 135 # Offense count: 140
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/ParallelAssignment: Style/ParallelAssignment:
Enabled: false Enabled: false
# Offense count: 2601 # Offense count: 2698
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: PreferredDelimiters. # Configuration parameters: PreferredDelimiters.
Style/PercentLiteralDelimiters: Style/PercentLiteralDelimiters:
Enabled: false Enabled: false
# Offense count: 1 # Offense count: 247
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: .
# SupportedStyles: compact, exploded # SupportedStyles: compact, exploded
Style/RaiseArgs: Style/RaiseArgs:
Enabled: false Enabled: false
EnforcedStyle: exploded
# Offense count: 65 # Offense count: 73
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantAssignment: Style/RedundantAssignment:
Enabled: false Enabled: false
# Offense count: 2
# Cop supports --auto-correct.
Style/RedundantBegin:
Exclude:
- 'app/services/clusters/applications/check_installation_progress_service.rb'
- 'lib/gitlab/database/postgres_hll/batch_distinct_counter.rb'
# Offense count: 26 # Offense count: 26
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: SafeForConstants. # Configuration parameters: SafeForConstants.
@ -949,21 +951,23 @@ Style/RedundantFetchBlock:
Style/RedundantFileExtensionInRequire: Style/RedundantFileExtensionInRequire:
Enabled: false Enabled: false
# Offense count: 220 # Offense count: 248
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantFreeze: Style/RedundantFreeze:
Enabled: false Enabled: false
# Offense count: 182 # Offense count: 206
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantInterpolation: Style/RedundantInterpolation:
Enabled: false Enabled: false
# Offense count: 8 # Offense count: 10
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantRegexpCharacterClass: Style/RedundantRegexpCharacterClass:
Exclude: Exclude:
- 'app/models/concerns/taskable.rb' - 'app/models/concerns/taskable.rb'
- 'ee/app/models/saml_provider.rb'
- 'lib/banzai/filter/markdown_pre_escape_filter.rb'
- 'lib/gitlab/authorized_keys.rb' - 'lib/gitlab/authorized_keys.rb'
- 'lib/gitlab/fogbugz_import/repository.rb' - 'lib/gitlab/fogbugz_import/repository.rb'
- 'lib/gitlab/quick_actions/substitution_definition.rb' - 'lib/gitlab/quick_actions/substitution_definition.rb'
@ -971,12 +975,12 @@ Style/RedundantRegexpCharacterClass:
- 'spec/features/merge_request/user_views_open_merge_request_spec.rb' - 'spec/features/merge_request/user_views_open_merge_request_spec.rb'
- 'spec/tasks/gitlab/usage_data_rake_spec.rb' - 'spec/tasks/gitlab/usage_data_rake_spec.rb'
# Offense count: 270 # Offense count: 279
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantRegexpEscape: Style/RedundantRegexpEscape:
Enabled: false Enabled: false
# Offense count: 920 # Offense count: 968
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RedundantSelf: Style/RedundantSelf:
Enabled: false Enabled: false
@ -988,26 +992,26 @@ Style/RedundantSelfAssignment:
- 'app/models/concerns/issuable.rb' - 'app/models/concerns/issuable.rb'
- 'spec/db/schema_spec.rb' - 'spec/db/schema_spec.rb'
# Offense count: 196 # Offense count: 213
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle, AllowInnerSlashes. # Configuration parameters: EnforcedStyle, AllowInnerSlashes.
# SupportedStyles: slashes, percent_r, mixed # SupportedStyles: slashes, percent_r, mixed
Style/RegexpLiteral: Style/RegexpLiteral:
Enabled: false Enabled: false
# Offense count: 50 # Offense count: 53
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/RescueModifier: Style/RescueModifier:
Enabled: false Enabled: false
# Offense count: 346 # Offense count: 359
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: implicit, explicit # SupportedStyles: implicit, explicit
Style/RescueStandardError: Style/RescueStandardError:
Enabled: false Enabled: false
# Offense count: 115 # Offense count: 123
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/SingleArgumentDig: Style/SingleArgumentDig:
Enabled: false Enabled: false
@ -1017,34 +1021,33 @@ Style/SingleArgumentDig:
Style/SlicingWithRange: Style/SlicingWithRange:
Enabled: false Enabled: false
# Offense count: 61 # Offense count: 63
# Configuration parameters: AllowModifier. # Configuration parameters: AllowModifier.
Style/SoleNestedConditional: Style/SoleNestedConditional:
Enabled: false Enabled: false
# Offense count: 121 # Offense count: 120
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: . # Configuration parameters: .
# SupportedStyles: use_perl_names, use_english_names # SupportedStyles: use_perl_names, use_english_names
Style/SpecialGlobalVars: Style/SpecialGlobalVars:
EnforcedStyle: use_perl_names EnforcedStyle: use_perl_names
# Offense count: 545 # Offense count: 562
# Cop supports --auto-correct. # Cop supports --auto-correct.
Style/StringConcatenation: Style/StringConcatenation:
Enabled: false Enabled: false
# Offense count: 108 # Offense count: 109
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: EnforcedStyle. # Configuration parameters: EnforcedStyle.
# SupportedStyles: single_quotes, double_quotes # SupportedStyles: single_quotes, double_quotes
Style/StringLiteralsInInterpolation: Style/StringLiteralsInInterpolation:
Enabled: false Enabled: false
# Offense count: 292 # Offense count: 293
# Cop supports --auto-correct. # Cop supports --auto-correct.
# Configuration parameters: IgnoredMethods. # Configuration parameters: IgnoredMethods.
# IgnoredMethods: respond_to, define_method # IgnoredMethods: respond_to, define_method
Style/SymbolProc: Style/SymbolProc:
Enabled: false Enabled: false

View file

@ -1,277 +0,0 @@
# Linter Documentation:
# https://github.com/brigade/scss-lint/blob/master/lib/scss_lint/linter/README.md
scss_files:
- 'app/assets/stylesheets/**/*.scss'
- 'ee/app/assets/stylesheets/**/*.scss'
exclude:
- 'app/assets/stylesheets/pages/emojis.scss'
- 'app/assets/stylesheets/startup/startup-*.scss'
- 'app/assets/stylesheets/lazy_bundles/select2.scss'
linters:
# Reports when you use improper spacing around ! (the "bang") in !default,
# !global, !important, and !optional flags.
BangFormat:
enabled: true
# Whether or not to prefer `border: 0` over `border: none`.
BorderZero:
enabled: true
# Reports when you define a rule set using a selector with chained classes
# (a.k.a. adjoining classes).
ChainedClasses:
enabled: false
# Prefer hexadecimal color codes over color keywords.
# (e.g. `color: green` is a color keyword)
ColorKeyword:
enabled: false
# Prefer color literals (keywords or hexadecimal codes) to be used only in
# variable declarations. They should be referred to via variables everywhere
# else.
ColorVariable:
enabled: true
# Which form of comments to prefer in CSS.
Comment:
enabled: false
# Reports @debug statements (which you probably left behind accidentally).
DebugStatement:
enabled: false
# Rule sets should be ordered as follows:
# - @extend declarations
# - @include declarations without inner @content
# - properties
# - @include declarations with inner @content
# - nested rule sets.
# Disabled to minimize Bootstrap migration footprint
DeclarationOrder:
enabled: false
# `scss-lint:disable` control comments should be preceded by a comment
# explaining why these linters are being disabled for this file.
# See https://github.com/brigade/scss-lint#disabling-linters-via-source for
# more information.
DisableLinterReason:
enabled: true
# Reports when you define the same property twice in a single rule set.
DuplicateProperty:
enabled: true
ignore_consecutive:
- cursor
# Separate rule, function, and mixin declarations with empty lines.
EmptyLineBetweenBlocks:
enabled: true
# Reports when you have an empty rule set.
EmptyRule:
enabled: true
# Reports when you have an @extend directive.
ExtendDirective:
enabled: false
# Files should always have a final newline. This results in better diffs
# when adding lines to the file, since SCM systems such as git won't
# think that you touched the last line.
FinalNewline:
enabled: true
# HEX colors should use three-character values where possible.
HexLength:
enabled: false
# HEX color values should use lower-case colors to differentiate between
# letters and numbers, e.g. `#E3E3E3` vs. `#e3e3e3`.
HexNotation:
enabled: true
# Avoid using ID selectors.
IdSelector:
enabled: false
# The basenames of @imported SCSS partials should not begin with an
# underscore and should not include the filename extension.
ImportPath:
enabled: true
# Avoid using !important in properties. It is usually indicative of a
# misunderstanding of CSS specificity and can lead to brittle code.
ImportantRule:
enabled: false
# Indentation should always be done in increments of 2 spaces.
Indentation:
enabled: true
width: 2
# Don't write leading zeros for numeric values with a decimal point.
LeadingZero:
enabled: false
# Reports when you define the same selector twice in a single sheet.
MergeableSelector:
enabled: true
# Functions, mixins, variables, and placeholders should be declared
# with all lowercase letters and hyphens instead of underscores.
NameFormat:
enabled: false
# Avoid nesting selectors too deeply.
NestingDepth:
enabled: true
max_depth: 6
# Always use placeholder selectors in @extend.
PlaceholderInExtend:
enabled: false
# Sort properties in a strict order.
PropertySortOrder:
enabled: false
# Reports when you use an unknown or disabled CSS property
# (ignoring vendor-prefixed properties).
PropertySpelling:
enabled: true
# Configure which units are allowed for property values.
PropertyUnits:
enabled: false
# Pseudo-elements, like ::before, and ::first-letter, should be declared
# with two colons. Pseudo-classes, like :hover and :first-child, should
# be declared with one colon.
PseudoElement:
enabled: true
# Avoid qualifying elements in selectors (also known as "tag-qualifying").
QualifyingElement:
enabled: false
# Don't write selectors with a depth of applicability greater than 3.
SelectorDepth:
enabled: false
# Selectors should always use hyphenated-lowercase, rather than camelCase or
# snake_case.
SelectorFormat:
enabled: false
convention: hyphenated_lowercase
# Prefer the shortest shorthand form possible for properties that support it.
Shorthand:
enabled: true
# Each property should have its own line, except in the special case of
# single line rulesets.
SingleLinePerProperty:
enabled: true
allow_single_line_rule_sets: true
# Split selectors onto separate lines after each comma, and have each
# individual selector occupy a single line.
SingleLinePerSelector:
enabled: true
# Commas in lists should be followed by a space.
SpaceAfterComma:
enabled: true
# Comment literals should be followed by a space.
SpaceAfterComment:
enabled: false
# Properties should be formatted with a single space separating the colon
# from the property's value.
SpaceAfterPropertyColon:
enabled: true
# Properties should be formatted with no space between the name and the
# colon.
SpaceAfterPropertyName:
enabled: true
# Variables should be formatted with a single space separating the colon
# from the variable's value.
SpaceAfterVariableColon:
enabled: true
# Variables should be formatted with no space between the name and the
# colon.
SpaceAfterVariableName:
enabled: false
# Operators should be formatted with a single space on both sides of an
# infix operator.
SpaceAroundOperator:
enabled: true
# Opening braces should be preceded by a single space.
SpaceBeforeBrace:
enabled: true
# Parentheses should not be padded with spaces.
SpaceBetweenParens:
enabled: false
# Enforces that string literals should be written with a consistent form
# of quotes (single or double).
StringQuotes:
enabled: false
# Property values, @extend, @include, and @import directives, and variable
# declarations should always end with a semicolon.
TrailingSemicolon:
enabled: true
# Reports lines containing trailing whitespace.
TrailingWhitespace:
enabled: true
# Don't write trailing zeros for numeric values with a decimal point.
TrailingZero:
enabled: false
# Don't use the `all` keyword to specify transition properties.
TransitionAll:
enabled: false
# Numeric values should not contain unnecessary fractional portions.
UnnecessaryMantissa:
enabled: true
# Do not use parent selector references (&) when they would otherwise
# be unnecessary.
UnnecessaryParentReference:
enabled: true
# URLs should be valid and not contain protocols or domain names.
UrlFormat:
enabled: true
# URLs should always be enclosed within quotes.
UrlQuotes:
enabled: true
# Properties, like color and font, are easier to read and maintain
# when defined using variables rather than literals.
VariableForProperty:
enabled: false
# Avoid vendor prefixes. Or rather: don't write them yourself.
VendorPrefix:
enabled: false
# Omit length units on zero values, e.g. `0px` vs. `0`.
ZeroUnit:
enabled: true

View file

@ -1,59 +1,19 @@
{ {
"extends": ["@gitlab/stylelint-config"],
"ignoreFiles": [ "ignoreFiles": [
"app/assets/stylesheets/pages/emojis.scss", "app/assets/stylesheets/pages/emojis.scss",
"app/assets/stylesheets/startup/startup-*.scss", "app/assets/stylesheets/startup/startup-*.scss",
"app/assets/stylesheets/lazy_bundles/select2.scss", "app/assets/stylesheets/lazy_bundles/select2.scss",
"app/assets/stylesheets/highlight/themes/*.scss" "app/assets/stylesheets/highlight/themes/*.scss",
"app/assets/stylesheets/lazy_bundles/cropper.css"
], ],
"plugins":[ "plugins":[
"./scripts/frontend/stylelint/stylelint-duplicate-selectors.js", "./scripts/frontend/stylelint/stylelint-duplicate-selectors.js",
"./scripts/frontend/stylelint/stylelint-utility-classes.js", "./scripts/frontend/stylelint/stylelint-utility-classes.js",
"stylelint-scss"
], ],
"rules":{ "rules":{
"at-rule-blacklist":[ "max-nesting-depth": [
"debug" 3,
],
"at-rule-no-unknown":null,
"at-rule-no-vendor-prefix":true,
"block-no-empty":true,
"block-opening-brace-space-before":"always",
"color-hex-case":"lower",
"color-hex-length":"short",
"color-named":"never",
"color-no-invalid-hex":true,
"declaration-bang-space-after":"never",
"declaration-bang-space-before":"always",
"declaration-block-semicolon-newline-after":"always",
"declaration-block-semicolon-space-before":"never",
"declaration-block-single-line-max-declarations":1,
"declaration-block-trailing-semicolon":"always",
"declaration-colon-space-after":"always-single-line",
"declaration-colon-space-before":"never",
"declaration-property-value-blacklist":{
"border":[
"none"
],
"border-top":[
"none"
],
"border-right":[
"none"
],
"border-bottom":[
"none"
],
"border-left":[
"none"
]
},
"function-comma-space-after":"always-single-line",
"function-parentheses-space-inside":"never",
"function-url-quotes":"always",
"indentation":2,
"length-zero-no-unit":true,
"max-nesting-depth":[
6,
{ {
"ignoreAtRules":[ "ignoreAtRules":[
"each", "each",
@ -64,54 +24,7 @@
"severity":"warning" "severity":"warning"
} }
], ],
"media-feature-name-no-vendor-prefix":true, "selector-max-compound-selectors":[3, { "severity": "warning" }],
"media-feature-parentheses-space-inside":"never",
"no-missing-end-of-source-newline":true,
"number-leading-zero":"always",
"number-no-trailing-zeros":true,
"property-no-unknown":true,
"property-no-vendor-prefix": [true, { "ignoreProperties": ["user-select"] }],
"rule-empty-line-before":[
"always-multi-line",
{
"except":[
"first-nested"
],
"ignore":[
"after-comment"
]
}
],
"scss/at-extend-no-missing-placeholder":[true,{ "severity": "warning" }],
"scss/at-function-pattern":"^[a-z]+([a-z0-9-]+[a-z0-9]+)?$",
"scss/at-import-no-partial-leading-underscore":true,
"scss/at-import-partial-extension-blacklist":[
"scss"
],
"scss/at-mixin-pattern":"^[a-z]+([a-z0-9-]+[a-z0-9]+)?$",
"scss/at-rule-no-unknown":true,
"scss/dollar-variable-colon-space-after":"always",
"scss/dollar-variable-colon-space-before":"never",
"scss/dollar-variable-pattern":"^[_]?[a-z]+([a-z0-9-]+[a-z0-9]+)?$",
"scss/percent-placeholder-pattern":"^[a-z]+([a-z0-9-]+[a-z0-9]+)?$",
"scss/selector-no-redundant-nesting-selector":true,
"selector-class-pattern":[
"^[a-z0-9\\-]+$",
{
"message":"Selector should be written in lowercase with hyphens (selector-class-pattern)",
"severity": "warning"
}
],
"selector-list-comma-newline-after":"always",
"selector-max-compound-selectors":[6, { "severity": "warning" }],
"selector-max-id":1,
"selector-no-vendor-prefix":true,
"selector-pseudo-element-colon-notation":"double",
"selector-pseudo-element-no-unknown":true,
"shorthand-property-no-redundant-values":true,
"string-quotes":"single",
"value-no-vendor-prefix": [true, { "ignoreValues": ["sticky"] }],
"stylelint-gitlab/duplicate-selectors":[true,{ "severity": "warning" }],
"stylelint-gitlab/utility-classes":[true,{ "severity": "warning" }], "stylelint-gitlab/utility-classes":[true,{ "severity": "warning" }],
"declaration-block-no-duplicate-properties": [ "declaration-block-no-duplicate-properties": [
true, true,

View file

@ -2,15 +2,27 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 13.9.6 (2021-04-13) ## 13.10.3 (2021-04-13)
### Security (2 changes) ### Security (3 changes)
- Check image content type before running exiftool in workhorse.
- Clean only legitimate JPG and TIFF files. - Clean only legitimate JPG and TIFF files.
- Update ruby-saml and rexml gems. - Update ruby-saml and rexml gems.
## 13.9.5 (2021-03-31) ## 13.10.2 (2021-04-01)
### Fixed (1 change)
- Fixed rendering of the image blobs. !57479
### Added (1 change)
- Improve performance for composer v2 clients. !55169
## 13.10.1 (2021-03-31)
### Security (6 changes) ### Security (6 changes)
@ -32,12 +44,532 @@ entry.
- Switch to using a fake mimemagic gem. !57443 - Switch to using a fake mimemagic gem. !57443
## 13.9.4 (2021-03-17) ## 13.10.0 (2021-03-22)
### Security (1 change) ### Security (3 changes)
- Workhorse: prevent escaped router path traversal.
- Workhorse: Stop logging when path is excluded.
- Patch Kramdown syntax highlighter gem. - Patch Kramdown syntax highlighter gem.
### Removed (2 changes)
- Remove Remove from board button from board sidebar. !53946
- Remove workaround for icon loading in Chrome 84. !56114
### Fixed (99 changes, 23 of them are from the community)
- Fix button alignment in design management header. !48003
- Updated UI text to match style guidelines. !50383
- Don't close auto suggest select boxes on click if only the mouseup (but not the mousedown) event happened outside the box. !51139 (Simon Stieger @sim0)
- Fix Auto DevOps deploys that use a default branch that's not named 'master'. !53280 (Mitchell Cash @MitchellCash)
- Correct job artifacts API download for expired and locked files. !53567 (Fabio Huser)
- Fix project import error occurring due to default visibility. !53827 (Jonas Wälter @wwwjon)
- Fix relative URL with composer package. !53918
- Cleanup incorrect data in projects.has_external_issue_tracker. !53936
- Fix not skipped manual and delayed DAG jobs. !54073
- Skip orphaned pool repositories on restore. !54112
- Add space next to icons in epic issue list. !54138 (Yogi (@yo))
- Render version dropdowns in MR changes view above tab navbar. !54159 (Simon Stieger @sim0)
- Do not show button to resolve discussion opening an issue when issues are disabled. !54263
- Hide issue count and link in project list for projects with disabled issues. !54275 (Simon Stieger @sim0)
- Handle GlobalIDs with invalid resource names. !54290
- Fix overflowing width - at mention container. !54377
- Update k8s version for EKS cluster. !54389 (Vincent Firmin @winkies)
- React to new DOM nodes being added to the page to bind the user information popover to them. !54411
- move create_release_evidence sidekiq queue out of the cronjob namespace. !54432
- Fix copy to clipboard tooltip button. !54472
- Fix bold text mismatch in MR ⚙ menu. !54531
- Wrap long code lines in markdown. !54540
- Hide repeated trial offers on self-hosted instances. !54550
- Fix bug when snippet blobs array contain a nil value. !54552
- Fix the npm instance level API to exclude subgroups. !54554
- Fix the value of `$CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX` when used in group with a name containing uppercase letters. !54559 (Eric Engestrom @1ace)
- Fixed typo on Two-Factor Authentication page. !54565 (Jani Uusitalo @uusijani)
- Forcibly load OpenSSL::X509::DEFAULT_CERT_FILE. !54569
- Stop scrollbar stretching filtered search box. !54574
- Correctly style Dark Mode application header in profile preferences. !54575 (Simon Stieger @sim0)
- Prevent removal of the last group owner if the last group owner is a blocked user. !54587 (Jonas Wälter @wwwjon)
- Fix style issue with "reply" placeholder textarea in firefox. !54592
- Update batch_loader gem to v2.0.0. !54639
- Fix rendering of projects when the last pipeline changes during rendering. !54651
- Search: Log search.scope for the default scope. !54684
- Fix double scrollbar in ref selector dropdown. !54719
- Fix double scrollbar issue in milestone selector dropdown. !54734
- Skip two factor setup for help pages. !54739
- Fixed diff notes GraphQL mutation not allowing comments on deleted lines. !54801
- Expand left sidebar `Issues` when viewing project iterations. !54815
- Added a missing class to reply placeholder. !54817
- Renamed the second project panel to group. !54834 (Niklas van Schrick @Taucher2003)
- Fix double scrollbars in some dropdowns. !54837
- Fix pipeline notifications for Webex Teams / Unify Circuit integrations. !54852
- Github Importer: Import Pull request "merged_at" attribute. !54862
- Fix UTF-8 characters not working with Azure Blob storage. !54875
- Upgrade gitlab-sidekiq-fetcher for correctly detecting interrupted jobs when Sidekiq pods are restarted. !54881
- Include shared with groups in list of authorized groups. !54894
- Fix `@` autocomplete selecting the loading icon. !54925
- Fix status cache for upstream pipelines. !54937
- Update gitlab-sidekiq-fetcher to 0.5.5 to handle namespaced queues. !55013
- Use gitlab_web_url (if it exists) for issue title links in Issue lists. !55021
- Fix issue with loading the repository compare page. !55058
- Fix argument type for background migration. !55097
- reconcile source installation and upgrade docs. !55170 (Jörg Behrmann @behrmann)
- Sync the maven metadata file upon package deletion through the UI. !55207
- Fix empty field in custom notification events modal. !55313 (Kev @KevSlashNull)
- Fix 500 error for long commit messages. !55320
- Include MRs for merge commits for changelogs. !55371
- GithubImporter: Add Merge request approval only if it does not exists yet. !55376
- Fix assignees search to show only project members. !55396
- Do not break word in the code blocks under Safari. !55405
- Fix typo in pipeline status email. !55412 (Gabriel Berke-Williams)
- Fix inconsistent heading style in email diffs. !55420
- Ensure Project Approvals API casts to boolean. !55492
- Update fog-aws to v3.9.0. !55528
- Handle relative position on issue move or clone. !55555
- Fix horizontal alignment of MR Changes cog menu dropdown checkboxes. !55591
- checks: Skip LFS checks when deleting refs. !55609
- Fix edited timestamp updated when transforming / resolving comments. !55671 (Mycroft Kang @TaehyeokKang)
- Allow saving repository weights after a storage has been removed. !55689
- Resolve project from branch in commit resolver. !55694
- Update validate_url gem. !55706
- Fixes: No such file or directory lib/pager_duty/validator/schemas/message.json. !55725
- Fix fork thumbnail overflow. !55764
- Change terraform_states.locked_by_user_id foreign key to SET NULL. !55813
- Fix invite member modal dropdown checkbox styling. !55832 (Kev @KevSlashNull)
- Reenable OAuth password grants without client credentials. !55873
- Fixed vestigial Anchor links in doc/development/usage_ping/dictionary.md. !55874 (Raimund Hook)
- Fix 'viewed' checkbox in single-file view mode. !55922
- Fix Web Project Export rate limiting scope. !55975
- Remove merge manually message. !56016
- fix stringify empty position object. !56037
- Fix diff comment hidden dropdown. !56072
- Handle RestClient errors in Discord integration. !56112
- Turn off native autocomplete for ref selector components. !56128
- Handle commits without descriptions for changelogs. !56224
- Support maven plugins packaging in the maven metadata sync worker. !56229
- Use gitlab-fog-google instead of upstream fog-google gem. !56245
- Fix styling of "Enabled OAuth sign-in sources" checkboxes. !56254
- Sanitize issue description in search result. !56256
- Fix bug in wiki page destroy API endpoint when an error is raised. !56285
- Correct generated maven repository instruction for Gradle Groovy DSL. !56318 (Cromefire_ (@cromefire_))
- Add labels to GlToggles. !56387
- Fixed error handling GraphQL API when issue board creation fails. !56467
- Hide fork count and link in project list where forks are disabled. !56520 (Simon Stieger @sim0)
- Fix upgrade banner for Jira issues showing on group / instance level integrations. !56628
- Fix tooltips failing to hide in commit graph on Firefox. !56631 (Jonathan Duncan)
- Hide MR count and link in project list where MRs are disabled. (Simon Stieger @sim0)
### Changed (202 changes, 88 of them are from the community)
- Mark `startDate` and `endDate` arguments as deprecated in the GraphQL schema for `Project.milestones` and `Group.milestones` (FOSS and EE), and `Project.iterations`, `Project.milestones`, `Group.epic`, `Group.epics`, `Group.iterations`, `Group.milestones`, `BoardEpic.children`, and `Epic.children` fields (EE-only). Previously these arguments were marked as deprecated only in their descriptions. !45229
- Improve Linked Issues Usability. !50879 (Andrew Minion)
- Make new issue title look like wiki. !50940 (Jacopo Beschi @jacopo-beschi)
- Introduce WebIDE as an extension for Editor Lite. !51527
- Update LaTeX Docker image in CI Templates to TexLive 2020. !52043 (Michael Schmitt @schmitmd)
- Allow creation of iterations in the past. !52403
- Allow overlapping iteration dates with ancestor group iterations and restrict dates overlapping for iterations within same group. !52403
- Send gitlab_standard context with events from the frontend. !52959
- Prefill first multiline commit message for new MRs. !52984 (Max Coplan @vegerot)
- Auto-enable admin mode on privileged environments. !53015 (Diego Louzán)
- Add loading indicator to "Update username" button in account settings. !53142 (Kev @KevSlashNull)
- Replace btn-primary with btn-confirm in Start your free trial button. !53215 (Yogi (@yo))
- Update project page buttons to conform to design system. !53260
- Lift the NPM package naming convention for the project level API. !53266
- Adds ability to have multiple cache per job. !53410
- Improve Jira connect app styling and i18n. !53441
- Restyle the repository compare show page. !53523
- API: include external users in user search for non-admins. !53584 (Jonas Wälter @wwwjon)
- Record onboarding action for issue creation. !53611
- Merge Sentry's contexts into Gitlab::ApplicationContext. !53691
- Add divergedFromTargetBranch field to MergeRequestType to indicate the target branch has diverged from the source branch. !53759
- Provide name of expiring token in personal access token expiration mail. !53766
- Convert merge request widget state to use GraphQL. !53846
- Sidebar confidentiality component updates in real-time. !53858
- Add creator to custom emoji. !53879
- Migrate namespaces delayed_project_removal to namespace_settings. !53916
- Add name field to cluster agent token. !53920
- Apply new GitLab UI for request email button. !53966 (Yogi (@yo))
- Add support for ETag caching when using GraphQL. !53978
- Allow anonymous access to public Conan packages. !54047 (Steve Mokris @smokris)
- Make the Geo OAuth application trusted by default. !54079
- Add description field to cluster agent token. !54091
- Project Settings CI/CD headers expand/collapse on click / tap. !54114 (Daniel Schömer)
- Project Settings CI/CD Variables header expands/collapses on click / tap. !54117 (Daniel Schömer)
- Add Role and Rolebinding for CiliumNetworkPolicies. !54130
- Add btn-default and remove extra right margin. !54134 (Yogi (@yo))
- Update user avatar in sidebar realtime. !54135 (Yogi (@yo))
- Remove illustration in export/import CSV modal. !54136 (Yogi (@yo))
- Update to btn-confirm and align subscription banner. !54137 (Yogi (@yo))
- Remove service desk issue prefix. !54140 (Lee Tickett @leetickett)
- Apply new GitLab UI for learn more button in time tracking. !54142 (Yogi (@yo))
- Apply new GitLab UI for apply template button in new issue. !54143 (Yogi (@yo))
- Remove gl-overflow-scroll in merge instructions modal. !54144 (Yogi (@yo))
- Align merge conflict warning text to center. !54145 (Yogi (@yo))
- Deprecate instanceStatisticsMeasurements in favor of usageTrendsMeasurements GraphQL field. !54153
- Web IDE disallow commit when project has 'reject unsigned commits' rule. !54166
- Add space next to download icon in download artifacts button. !54228 (Yogi (@yo))
- Convert IDE nav form tab to GlTab. !54274
- Add btn-icon class for commit action buttons. !54286 (Yogi (@yo))
- Convert Threat Monitoring environment picker to GlDropdown. !54309
- Allow importing groups as new top-level groups. !54323
- Show user follow button first instead of center. !54326 (Yogi (@yo))
- Update 'Get Started with CI/CD' button with latest URL. !54344
- Log individual user usage of Slack service. !54347
- Add duration and finishedAt GraphQL fields to jobType in the CI namespace. !54358
- Show icon next to reviewers who have approved. !54365
- Add btn-icon for buttons in pipeline schedules. !54426 (Yogi (@yo))
- Restore Sentry functionaly to the frontend. !54441
- Github Importer: Validate repository size before importing. !54449
- Allow search for pipeline by SHA as well as IID via GraphQL. !54471
- Change default API content_type to JSON. !54479
- Added environment details to Job Hook and Pipeline Hook. !54480 (AdrianLC)
- GraphQL: Expose Label "created_at" and "updated_at". !54487
- Move CI_CONFIG_PATH as project variable and deprecate CI_PROJECT_CONFIG_PATH. !54498
- Registry: make delete icon buttons secondary. !54545
- Add GlToggle label in edit feature flag. !54546 (Yogi (@yo))
- Add GlToggle label in sidebar subscription toggle. !54548 (Yogi (@yo))
- Refine Registry Lists and Search Bar UI. !54549
- Remove outdated ci db columns. !54564
- BulkImports: Avoid import ProjectLabels in the Group import level. !54580
- Update default title of alerts to New: Alert. !54621
- Clear Environment Search in CI/CD Variables. !54626
- Only show 2FA badge to project maintainers and group owners. !54646
- Enable pages_serve_with_zip_file_protocol by default. !54650
- Auto-scroll to top of page upon committing in pipeline editor. !54657
- Remove Expiration Policy text from container registry header. !54665
- Reduce elements in Pipeline page dropdowns with lazy. !54674
- BulkImports: Import Label timestamps. !54678
- Improve at.js members autocomplete matching. !54681
- Use Root Image for images with missing name. !54693
- Change the order of action buttons in the configure feature flags modal. !54731
- Remove deprecated button variant in groups, projects and snippets. !54747 (Yogi (@yo))
- Add selected state for ellipsis button in a commit. !54754 (Yogi (@yo))
- Apply new GitLab UI for button in promotion link. !54755 (Yogi (@yo))
- Apply new GitLab UI for buttons in empty label placeholder. !54760 (Yogi (@yo))
- Add selected state for diff view in commit page. !54762 (Yogi (@yo))
- Add selected state for chart button in vulnerabilities dashboard. !54763 (Yogi (@yo))
- Add btn-default class for settings toggle button. !54764 (Yogi (@yo))
- Apply new GitLab UI for badge in runners list. !54766 (Yogi (@yo))
- Better error message when import fails due to backend validation. !54827
- Moved CODEOWNERS tip into approvals Vue app. !54830
- Add a new project feature called container_registry. !54831
- Relax tag requirements when generating changelogs. !54832
- Regroup alerts integration form into tabs. !54842
- Reverts default sort order for Explore Projects to Last updated. !54879
- Fix DOS on Math blocks. !54898
- Added non-null constraint to terraform state name. !54940
- Remove MergeRequestAssigneesMigrationProgressCheck background migration. !54943
- Adjust text explaining content of Operations menu from visibility section of project settings. !54963
- Use info colour for merged search results instead of primary. !55008
- Update button variant to confirm on integration settings page. !55017
- Allow `$CI_JOB_TOKEN` to access the "Download a single artifact file" endpoints of the Jobs Artifacts API. !55042 (Eric Engestrom @1ace)
- Ignore prerelease tags when generating changelogs. !55065
- Rename comment form textarea label to `Comment`. !55088
- Add runners api context metadata. !55089
- Reschedule artifact expiry backfill. !55093
- Small visual updates to Git ref selector dropdown on New/Edit Release page. !55121
- Group integration settings buttons to the left. !55139
- Optimize Metrics Dictionary. !55145
- Show nested environments when change tab, page. !55167
- Move to btn-confirm in app/views/devise directory. !55200 (Yogi (@yo))
- Move to btn-confirm in app/views/shared/empty_states directory. !55203 (Yogi (@yo))
- Change the button to Primary Blue. !55204 (Yogi (@yo))
- Update button to btn-confirm on merge requests page. !55218
- Add empty state to pipeline editor section. !55227
- Project Settings Repository Default branch header expand/collaps on click. !55228 (Daniel Schömer)
- Project Settings Repository Mirroring repositories header expands/collapses on click / tap. !55229 (Daniel Schömer)
- Project Settings CI/CD Variables header expands/collapses on click / tap. !55230 (Daniel Schömer)
- Project Settings Repository Protected tags header expands/collapses on click / tap. !55231 (Daniel Schömer)
- Project Settings Repository Cleanup header expands/collapses on click / tap. !55232 (Daniel Schömer)
- Project Settings Repository Deploy tokens header expands/collapses on click / tap. !55233 (Daniel Schömer)
- Project Settings Repository Deploy keys header expands/collapses on click / tap. !55234 (Daniel Schömer)
- Collapse deployments in merge request if many. !55239
- Move to btn-confirm from btn-success in abuse_reports folder. !55262 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin application_settings directory. !55263 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/appearances directory. !55264 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/applications directory. !55265 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/broadcast_messages directory. !55266 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/deploy_keys directory. !55267 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/groups directory. !55268 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/hooks directory. !55272 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/labels directory. !55273 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/projects directory. !55274 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/serverless directory. !55275 (Yogi (@yo))
- Move to btn-confirm from btn-success in admin/users directory. !55276 (Yogi (@yo))
- Move to btn-confirm from btn-success in views/doorkeeper directory. !55277 (Yogi (@yo))
- Move to btn-confirm from btn-success in groups/milestones directory. !55278 (Yogi (@yo))
- Move to btn-confirm from btn-success in groups/settings directory. !55281 (Yogi (@yo))
- Move to btn-confirm from btn-success in groups directory. !55282 (Yogi (@yo))
- Move to btn-confirm from btn-success in views/import directory. !55291 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/access_token directory. !55298 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/deploy_keys directory. !55299 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/deploy_tokens directory. !55300 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/gitpod directory. !55301 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/groups directory. !55302 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/issuable directory. !55303 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/labels directory. !55304 (Yogi (@yo))
- Bump swagger-ui-dist to 3.44.1. !55310 (Roger Meier)
- Move from btn-success to btn-confirm in shared/members directory. !55315 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared/wikis directory. !55316 (Yogi (@yo))
- Move from btn-success to btn-confirm in shared directory. !55317 (Yogi (@yo))
- Remove suggestions custom commit feature flag. !55344
- Use policies for group access rights as admin. !55349 (Diego Louzán)
- Increase contrast of Solarized Light in Web IDE. !55361
- Enable `trace_memory_allocations` by default. !55369
- Expose project access token value with create API. !55408
- Allow alert to link to incidents. !55426
- Send notifications to subscribers when merge request draft status removed. !55444
- Show number of files in snippet lists. !55452
- Use CodeQuality packaged with CodeClimate 0.85.23 by default in CI template. !55508
- Simplify notifications dropdown. !55522
- Improve Marginalia comments for API. !55564
- Clarify epic delete warning. !55574
- Exclude duplicates from emails on push recipients. !55588
- Move IDE routes to Rails. !55597
- Update cluster agent tokens with null names. !55673
- Expand nested stopped environments. !55676
- Add fields to BulkImports::Tracker for concurrent work. !55686
- Move to confirm variant from success in 2fa codes component. !55729 (Yogi (@yo))
- Move to confirm variant from success in badges component. !55730 (Yogi (@yo))
- Add Gradle instructions and instruction selector to package details. !55738
- Update text for email config under Incidents in Settings > Operations. !55753
- Display suite errors on test summary page. !55770
- Alert integrations UX cleanup. !55786
- Remove project_transactionless_destroy feature flag. !55795
- Update code owner approval tooltip message. !55842
- Sort milestones within autocomplete dropdown. !55850
- Adjust debug button icon size in job detail page. !55886
- Link fields to types in GraphQL reference documentation. !55901
- Remove `vue_project_members_list` feature flag. !55902
- Public generic packages can now be accessed by developer, guest and anonymous users. !55978 (Mathieu Parent)
- Port essential database metrics to Sidekiq. !56005
- Add API Fuzzing to Security Configuration page, and re-order scanners. !56022
- Add last_used_at field to cluster agent token. !56023
- Change the default batch_class_name for batched_background_migrations to the unqualified class name. !56036
- Improve styling of user access role badges. !56061
- Temporary make `GC.compact` no-op. !56079
- Move to btn-default and selected class in toggle comment button. !56090 (Yogi (@yo))
- Apply new GitLab UI for buttons in GitLab Import page. !56095 (Yogi (@yo))
- Apply new GitLab UI for buttons on GitHub Import page. !56096 (Yogi (@yo))
- Move to confirm variant from success in environments directory. !56203 (Yogi (@yo))
- Move from btn-success to btn-confirm in clusters directory. !56205 (Yogi (@yo))
- Remove security & compliance config page feature flag. !56219
- Display in progress for pipeline duration cell when pipeline has not finished running. !56266
- Add project_id to pipeline api. !56339
- Move from btn-success to btn-confirm in milestones directory. !56342 (Yogi (@yo))
- Move from btn-success to btn-confirm in mirrors directory. !56343 (Yogi (@yo))
- Move from btn-success to btn-confirm in pages directory. !56348 (Yogi (@yo))
- Move from btn-success to btn-confirm in pages_domains directory. !56349 (Yogi (@yo))
- Consume check if user is bot from Users API. !56362
- Hide archived projects from group boards project select dropdown. !56452
- Update mailroom to v0.0.9. !56592
### Performance (32 changes)
- Limit Project Authorizations refresh for shared groups only to direct members of the group being shared with. !51869
- Remove unneeded transitions on MR for mark_as_unchecked event. !53537
- Preload certain data used in the updating of a merge request. !53802
- Enable codequality report comparison with backend. !54241
- Add preload attribute to markdown videos. !54350
- Improve pull mirroring performance. !54353
- Remove coverage_data_new_finder feature flag. !54486
- Improve performance of builds queuing by introducing a limit on the queue depth. !54579
- Added composite index to epic_issues table and improved performance of loading bigger epic roadmaps. !54677
- Consider only distinct user ids for project authorizations refresh jobs for group members. !54697
- Improve performance of validations when a group has a lot of runners. !54774
- Hardened "add" arithmetic for usage data. !54794
- Harden added metrics. !54805
- Cache /search/count requests in the browser. !55036
- Use recursive approach to query all projects for a namespace. !55043
- Fix N+1s related to per-build metadata lookups. !55053
- Fetch build one-by-one. !55194
- Improve build contention. !55202
- Move branch deletion on merge to async worker. !55390
- Improve performance of manual pipeline form by limiting the refs loaded on page load. !55394
- Fix N+1 queries in api/v3/repos/:namespace/:project/events endpoint. !55442
- Refactor blame view. !55488
- Reduce queries when ticking runner queue. !55496
- Shortcircuit expensive queries in Runner#can_pick?. !55518
- Preload runner tags for `UpdateBuildQueueService`. !55543
- Batch-load vulnerability findings by UUID. !55642
- Improve a11y of the new project form by marking required fields. !55682
- Reduce DB load when resetting CI minute notifications. !55765
- Remove latest_builds_report_results preloading in pipeline serializer. !56181
- Optimize branch commit resolution. !56204
- Use `Namespace#all_projects` for NPM package finder. !56415
- Project sharing to use specialized worker to calculate project authorizations. !56606
### Added (91 changes, 11 of them are from the community)
- Add setting to control merge when pipeline succeeds notification. !37880 (Ravishankar)
- Adds Request CVE ID button to issue sidebar. !41203
- convert to GlTabs in app/assets/javascripts/ide/components/repo_tabs.vue. !42162 (Brandon Everett)
- Add invite_email Quick Action. !49264 (Lee Tickett)
- Add API endpoint for fetching a single job by CI_JOB_TOKEN. !51727 (ahmet2mir)
- Add API endpoint for deleting stale review envs. !52224
- Add active period columns to on-call rotations. !52998
- Add user preference to turn off selected text keystroke formatting. !53079
- Display success message after successfully adding a namespace in Jira Connect. !53332
- Add groups endpoint for Projects API. !53642
- Add suppport for an end time on on-call rotations. !53675
- Replace scss with stylelint in documentation. !53700
- Add composer cache rake task. !53772
- Limit the payload size of Sidekiq jobs before scheduling. !53829
- Expose `failure_reasons` in `Build#features`. !53964
- Create ExternalApprovalRule table and associations. !54002
- Jira Connect app: add ability to select namespace from list of available namespaces. !54037
- Expose container_registry_image_prefix to project API. !54090 (Mathieu Parent)
- Default confidentiality of replies. !54122 (Lee Tickett @leetickett)
- Add environment to custom CI_JOB_JWT claims. !54168
- Make `to` in the changelog API optional. !54229
- Add API endpoint /application/plan_limits for package file size limits. !54232 (Jonas Wälter @wwwjon)
- Add pagination of file diffs when viewing a large commit. !54236
- Add internal and external URL config for KAS. !54260
- Add Azure ActiveDirectory v2 OmniAuth provider. !54265
- Add application setting for enabling in-product marketing emails. !54324
- Enable customize homepage banner by default. !54357
- Expose epic board list collapsed value via GraphQL. !54541
- Implement passing trigger payload into pipeline variable. !54544
- Support "view_diffs_file_by_file" param in the Users create and update API. !54595
- Add GraphQL mutation to create release asset link. !54605
- Create tables to track auto-batched background migrations. !54628
- Create system note on alert when its auto-resolved via alert integration. !54645
- Add package list to group graphql type. !54672
- Add Import options to projects and groups dropdown. !54749
- Add mutation to accept merge requests. !54758
- Add Operating System details to usage ping. !54778
- Add is_removed column on Oncall Participant model. !54779
- Add reviewers detail to new merge request email. !54781
- Add wiki_size and storage_size to NamespaceStatistics. !54786
- Add branch_name to dast_profiles table. !54891
- Support composer v2 metadata-url. !54906
- Bump auto-deploy-image tag in Deploy.latest.gitlab-ci.yml to v2.6.0, which includes changes to ciliumnetworkpolicies. !54983
- Add CI_JOB_STARTED_AT and CI_PIPELINE_CREATED_AT variables. !54989 (Vincent Firmin @winkies)
- Add styling to de-emphasize nested test reports in merge requests. !55001
- Display parsing errors in test reports MR widget. !55037
- Add user callouts to GraphQL. !55099
- Add 'Followed User Activity' as dashboard user choices. !55165 (Benj Fassbind @randombenj)
- Improve Vulnerability Tracking: Store Fingerprints. !55173
- Cleanup invite_members_version_a experiment. !55178
- Incident management: add issue state to alerts table. !55185
- Document propagate_correlation_id configuration for GitLab Pages. !55205 (Ercan Ucan @ercan.ucan)
- Add Allow force push option to Protected branches. !55261 (Mycroft Kang @TaehyeokKang)
- Add a background migration to copy projects.container_registry_enabled to project_features.container_registry_access_level. !55327
- Add trigger support for matrix jobs. !55348
- Add more explanation about the presented data and show the last updated time on the DevOps Score page. !55357
- Query group projects by ids with GraphQL. !55383
- Allow users to work on non-default branch in pipeline editor. !55413
- Add reviewers detail to merge when pipeline succeeds email. !55463
- Implement needs:job:optional for CI pipelines. !55468
- Add tier column to the environments table. !55471
- Add DORA daily metrics modeling. !55473
- Add setting to control Rails.application.config.hosts. !55491
- Ignore reverted commits when generating changelogs. !55537
- Add reviewers detail to merge request unmergeable email. !55582
- Add reviewers detail to merge request status email. !55584
- Add reviewers detail to merged merge request email. !55589
- Add reviewers detail to text version of closed merge request email. !55594
- Add client_id to application context. !55683
- Allow release to be created on existing tag through the UI. !55697
- Add index for pages migration. !55757
- Remove improved_merge_diff_highlighting feature flag. !55771
- Usage ping: Histogram for enabled integrations per project. !55782
- Add Pages cache configuration settings. !55812
- Add package and quickaction metrics to Metrics Dictionary. !55846
- Enable serving GitLab Pages sites migrated to zip storage. !55847
- Log large multipart messages from Rack. !55933
- Add update GraphQL mutation for Oncall Rotations. !55955
- Cache open issues count in group sidebar. !55968
- Add the ability to cherry pick accross forks. !55970
- Migrate group milestones when using Bulk Import. !55981
- Introduce `info` column for the `security_scans` table. !55983
- Support environment deployment tier. !56081
- Add Prometheus metrics for ActionCable subscription events. !56157
- Add reviewers detail to new mention in merge request email. !56184
- Add more settings to group MR approval settings. !56215
- Automatically retarget merge requests upon merge (default on). !56233
- Add section headers for the test report widget on the merge request page. !56252
- Add GraphQL mutation to update existing release asset link. !56265
- Upgrade Pages to v1.36.0. !56295
- Add plan limit for Terraform Module package file size. !56414
### Other (74 changes, 9 of them are from the community)
- Add a confirmation prompt to lock and unlock path locks. !44849
- Recalculate UUID for all Vulnerability::Findings. !47529
- Use Created instead of opened when describing issue creation. !49478
- Removes collect_package_events_redis feature flag. !49897
- Fix a crash when logging in using SAML for the first time when sign-ups are disabled. !50216
- Add iterations_cadences table and respective model. !50707
- Migrated Bootstrap dropdown to GitLab UI GlDropdown used for comment submit button. !50933
- Rename indexes to remove inconsistencies. !51011
- Notify issue email participants instead of external author. !51023 (Lee Tickett @leetickett)
- Remove usage_data_i_source_code_code_intelligence flag. !51765
- Apply GitLab UI button styles to buttons in ee/app/views/subscriptions/groups directory. !51784 (Yogi (@yo))
- Updated UI text to match style guidelines. !53179
- Update the Sign In button to use the new confirm button variant, migrate OAuth buttons to use the default variant of GlButton. !53254
- Apply new GitLab UI for button is project settings/repository page. !53346 (Yogi (@yo))
- Add btn-default class for edit buttons in admin projects and groups. !53453
- Add btn-default for cancel button in issueable form. !53458 (Yogi (@yo))
- Set MobSF version to 3.2.9 in SAST template. !53545
- Move add reaction button of note to gl-button. !53565 (Yogi (@yo))
- Improve Service Desk empty states. !54006
- Spell "npm" with lowercase letters in Package Registry UI. !54163 (Simon Stieger @sim0)
- Replace import/export CSV modal with Vue component. !54214
- Add quick action data to usage ping. !54293
- Add documentation for graphQL queries. !54302
- Add NOT NULL constraint to gitlab_subscriptions namespace_id. !54319
- Update accessibility of the "Reply to discussion" UX. !54380
- Remove temporary index on issues. !54387 (Lee Tickett @leetickett)
- Add Vue notifications dropdown component. !54422
- Move wiki helper alert to Vue. !54517
- Composer cache update worker. !54551
- Fix setting default cadences migration. !54598
- Update protected branches buttons to pajamas style. !54612
- Dry up notes build service spec. !54632 (Lee Tickett @leetickett)
- Updating general Chef .gitlab-ci.yml template. !54676
- Enable `nakayoshi_fork` by default. !54688
- Remove backup_labels table. !54856
- Update GitLab Runner Helm Chart to 0.26.0. !54863
- Add notification templates for merge request draft/WIP status change events. !54870
- Remove pipeline editor feature flag. !54971
- Remove graphql_logging feature flag. !54984
- Add tracking to merge request time estimate/spent changes. !55046
- Track usage pings when MR gets locked/unlocked. !55069
- Deemphasize comment and close button. !55075
- Log Optimistic Locks with retries. !55187
- Add environment_scope column to ci_group_variables. !55256
- Align heading style with subheadings in markdown. !55284
- Restore accidental changes to structure.sql. !55352
- Show API errors when a command-only comment fails. !55457
- Remove dashboard_pipeline_status feature flag. !55472
- Add tracking to merge request labels/milestone changes. !55484
- Add tracking to merge request assignees/reviewers changes. !55486
- Remove unique index and add composite key index to Security Orchestration. !55521
- Fix Sidekiq system check for cluster mode. !55530 (Horst Prote)
- Rename vulnerability fingerprints indexes. !55552
- Refactor docs and UI for embedding Grafana panels. !55567
- Remove the optimized_merge_request_count_with_merged_at_filter feature flag. !55600
- Add histogram for optimistic lock retries. !55614
- Replace Bootstrap popover with GitLab UI popover for merge conflict. !55652
- Use more common help icon in security report MR widget. !55741
- Schedule removal of duplicate Findings. !55749
- Update spacing between Notifications dropdown, New Subgroup button, and New Project buttons while using the new confirm variant instead of the deprecated success variant for the New Project button. Better left alignment of Notifications dropdown at smaller breakpoints. variant. !55819
- Update buttons on a job page to conform to the Pajamas design system. !55858
- Add web_hook_logs partitioning migration. !55938
- Updating usage dictionary generator. !55956
- Reorder user profile actions and use the confirm variant for the follow button. !55999
- Link to the merge request in its creation email notification. !56064
- Update UI text to CI/CD from CI / CD. !56070
- Harden Prometheus client usage data wrapper. !56210
- Update Pages template examples to default branch. !56298
- Update CI template examples to default branch. !56301
- Update templates to refer to default branch. !56304
- Remove bottom border from header. !56315
- Remove merge_request_rebase_nowait_lock flag. !56406
- Update mobsf version in the SAST template. !56413
- Convert mattermost alert to pajamas. !56556
## 13.9.3 (2021-03-08) ## 13.9.3 (2021-03-08)
@ -647,6 +1179,18 @@ entry.
- Apply new GitLab UI for buttons in pipeline schedules. - Apply new GitLab UI for buttons in pipeline schedules.
## 13.8.5 (2021-03-04)
### Security (6 changes)
- Fix XSS in wiki author email and name.
- Bump thrift gem to 0.14.0.
- Allow only owners to manage group variables.
- Do not store marshalled sessions ids in Redis.
- Workhorse: prevent escaped router path traversal.
- Fix XSS vulnerability for swagger file viewer.
## 13.8.4 (2021-02-11) ## 13.8.4 (2021-02-11)
### Security (9 changes) ### Security (9 changes)
@ -1047,6 +1591,17 @@ entry.
- Add verbiage + link sast to show it's in core. !51935 - Add verbiage + link sast to show it's in core. !51935
## 13.7.8 (2021-03-04)
### Security (5 changes)
- Bump thrift gem to 0.14.0.
- Allow only owners to manage group variables.
- Do not store marshalled sessions ids in Redis.
- Workhorse: prevent escaped router path traversal.
- Fix XSS vulnerability for swagger file viewer.
## 13.7.7 (2021-02-11) ## 13.7.7 (2021-02-11)
### Security (9 changes) ### Security (9 changes)

View file

@ -1,20 +1,18 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'tooling/gitlab_danger' require 'gitlab-dangerfiles'
require_relative 'tooling/danger/request_helper'
Dir["danger/plugins/*.rb"].sort.each { |f| danger.import_plugin(f) } Gitlab::Dangerfiles.import_plugins(danger)
danger.import_plugin('danger/plugins/*.rb')
return if helper.release_automation? return if helper.release_automation?
gitlab_danger = GitlabDanger.new(helper.gitlab_helper) project_helper.rule_names.each do |rule|
danger.import_dangerfile(path: File.join('danger', rule))
gitlab_danger.rule_names.each do |file|
danger.import_dangerfile(path: File.join('danger', file))
end end
anything_to_post = status_report.values.any? { |data| data.any? } anything_to_post = status_report.values.any? { |data| data.any? }
if gitlab_danger.ci? && anything_to_post if helper.ci? && anything_to_post
markdown("**If needed, you can retry the [`danger-review` job](#{ENV['CI_JOB_URL']}) that generated this comment.**") markdown("**If needed, you can retry the [`danger-review` job](#{ENV['CI_JOB_URL']}) that generated this comment.**")
end end

View file

@ -1 +1 @@
13.9.6 13.10.3

View file

@ -1 +1 @@
1.35.0 1.36.0

View file

@ -1 +0,0 @@
8.63.3

1
GITLAB_WORKHORSE_VERSION Symbolic link
View file

@ -0,0 +1 @@
VERSION

40
Gemfile
View file

@ -17,7 +17,7 @@ gem 'default_value_for', '~> 3.4.0'
# Supported DBs # Supported DBs
gem 'pg', '~> 1.1' gem 'pg', '~> 1.1'
gem 'rugged', '~> 1.0.1' gem 'rugged', '~> 1.1'
gem 'grape-path-helpers', '~> 1.6.1' gem 'grape-path-helpers', '~> 1.6.1'
gem 'faraday', '~> 1.0' gem 'faraday', '~> 1.0'
@ -25,15 +25,15 @@ gem 'marginalia', '~> 1.10.0'
# Authentication libraries # Authentication libraries
gem 'devise', '~> 4.7.2' gem 'devise', '~> 4.7.2'
# TODO: verify ARM compile issue on 3.1.13+ version (see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/18828) gem 'bcrypt', '~> 3.1', '>= 3.1.14'
gem 'bcrypt', '3.1.12'
gem 'doorkeeper', '~> 5.5.0.rc2' gem 'doorkeeper', '~> 5.5.0.rc2'
gem 'doorkeeper-openid_connect', '~> 1.7.5' gem 'doorkeeper-openid_connect', '~> 1.7.5'
gem 'rexml', '~> 3.2.5' gem 'rexml', '~> 3.2.5'
gem 'ruby-saml', '~> 1.12.1' gem 'ruby-saml', '~> 1.12.1'
gem 'omniauth', '~> 1.8' gem 'omniauth', '~> 1.8'
gem 'omniauth-auth0', '~> 2.0.0' gem 'omniauth-auth0', '~> 2.0.0'
gem 'omniauth-azure-oauth2', '~> 0.0.9' gem 'omniauth-azure-activedirectory-v2', '~> 0.1'
gem 'omniauth-azure-oauth2', '~> 0.0.9' # Deprecated v1 version
gem 'omniauth-cas3', '~> 1.1.4' gem 'omniauth-cas3', '~> 1.1.4'
gem 'omniauth-facebook', '~> 4.0.0' gem 'omniauth-facebook', '~> 4.0.0'
gem 'omniauth-github', '~> 1.4' gem 'omniauth-github', '~> 1.4'
@ -75,6 +75,9 @@ gem 'acme-client', '~> 2.0', '>= 2.0.6'
# Browser detection # Browser detection
gem 'browser', '~> 4.2' gem 'browser', '~> 4.2'
# OS detection for usage ping
gem 'ohai', '~> 16.10'
# GPG # GPG
gem 'gpgme', '~> 2.0.19' gem 'gpgme', '~> 2.0.19'
@ -90,7 +93,7 @@ gem 'grape-entity', '~> 0.7.1'
gem 'rack-cors', '~> 1.0.6', require: 'rack/cors' gem 'rack-cors', '~> 1.0.6', require: 'rack/cors'
# GraphQL API # GraphQL API
gem 'graphql', '~> 1.11.4' gem 'graphql', '~> 1.11.8'
# NOTE: graphiql-rails v1.5+ doesn't work: https://gitlab.com/gitlab-org/gitlab/issues/31771 # NOTE: graphiql-rails v1.5+ doesn't work: https://gitlab.com/gitlab-org/gitlab/issues/31771
# TODO: remove app/views/graphiql/rails/editors/show.html.erb when https://github.com/rmosolgo/graphiql-rails/pull/71 is released: # TODO: remove app/views/graphiql/rails/editors/show.html.erb when https://github.com/rmosolgo/graphiql-rails/pull/71 is released:
# https://gitlab.com/gitlab-org/gitlab/issues/31747 # https://gitlab.com/gitlab-org/gitlab/issues/31747
@ -114,16 +117,16 @@ gem 'carrierwave', '~> 1.3'
gem 'mini_magick', '~> 4.10.1' gem 'mini_magick', '~> 4.10.1'
# for backups # for backups
gem 'fog-aws', '~> 3.8' gem 'fog-aws', '~> 3.9'
# Locked until fog-google resolves https://github.com/fog/fog-google/issues/421. # Locked until fog-google resolves https://github.com/fog/fog-google/issues/421.
# Also see config/initializers/fog_core_patch.rb. # Also see config/initializers/fog_core_patch.rb.
gem 'fog-core', '= 2.1.0' gem 'fog-core', '= 2.1.0'
gem 'fog-google', '~> 1.12' gem 'gitlab-fog-google', '~> 1.13', require: 'fog/google'
gem 'fog-local', '~> 0.6' gem 'fog-local', '~> 0.6'
gem 'fog-openstack', '~> 1.0' gem 'fog-openstack', '~> 1.0'
gem 'fog-rackspace', '~> 0.1.1' gem 'fog-rackspace', '~> 0.1.1'
gem 'fog-aliyun', '~> 0.3' gem 'fog-aliyun', '~> 0.3'
gem 'gitlab-fog-azure-rm', '~> 1.0', require: false gem 'gitlab-fog-azure-rm', '~> 1.0.1', require: false
# for Google storage # for Google storage
gem 'google-api-client', '~> 0.33' gem 'google-api-client', '~> 0.33'
@ -197,7 +200,7 @@ gem 'acts-as-taggable-on', '~> 7.0'
gem 'sidekiq', '~> 5.2.7' gem 'sidekiq', '~> 5.2.7'
gem 'sidekiq-cron', '~> 1.0' gem 'sidekiq-cron', '~> 1.0'
gem 'redis-namespace', '~> 1.7.0' gem 'redis-namespace', '~> 1.7.0'
gem 'gitlab-sidekiq-fetcher', '0.5.2', require: 'sidekiq-reliable-fetch' gem 'gitlab-sidekiq-fetcher', '0.5.5', require: 'sidekiq-reliable-fetch'
# Cron Parser # Cron Parser
gem 'fugit', '~> 1.2.1' gem 'fugit', '~> 1.2.1'
@ -235,7 +238,7 @@ gem 'connection_pool', '~> 2.0'
gem 'redis-rails', '~> 5.0.2' gem 'redis-rails', '~> 5.0.2'
# Discord integration # Discord integration
gem 'discordrb-webhooks-blackst0ne', '~> 3.3', require: false gem 'discordrb-webhooks', '~> 3.4', require: false
# Jira integration # Jira integration
gem 'jira-ruby', '~> 2.1.4' gem 'jira-ruby', '~> 2.1.4'
@ -311,7 +314,7 @@ gem 'pg_query', '~> 1.3.0'
gem 'premailer-rails', '~> 1.10.3' gem 'premailer-rails', '~> 1.10.3'
# LabKit: Tracing and Correlation # LabKit: Tracing and Correlation
gem 'gitlab-labkit', '0.14.0' gem 'gitlab-labkit', '~> 0.16.1'
# Thrift is a dependency of gitlab-labkit, we want a version higher than 0.14.0 # Thrift is a dependency of gitlab-labkit, we want a version higher than 0.14.0
# because of https://gitlab.com/gitlab-org/gitlab/-/issues/321900 # because of https://gitlab.com/gitlab-org/gitlab/-/issues/321900
gem 'thrift', '>= 0.14.0' gem 'thrift', '>= 0.14.0'
@ -323,7 +326,7 @@ gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.3' gem 'gettext_i18n_rails_js', '~> 1.3'
gem 'gettext', '~> 3.3', require: false, group: :development gem 'gettext', '~> 3.3', require: false, group: :development
gem 'batch-loader', '~> 1.4.0' gem 'batch-loader', '~> 2.0.1'
# Perf bar # Perf bar
gem 'peek', '~> 1.1' gem 'peek', '~> 1.1'
@ -343,7 +346,6 @@ end
group :development do group :development do
gem 'brakeman', '~> 4.2', require: false gem 'brakeman', '~> 4.2', require: false
gem 'danger', '~> 8.0.6', require: false
gem 'lefthook', '~> 0.7', require: false gem 'lefthook', '~> 0.7', require: false
gem 'letter_opener_web', '~> 1.3.4' gem 'letter_opener_web', '~> 1.3.4'
@ -377,9 +379,8 @@ group :development, :test do
gem 'spring', '~> 2.1.0' gem 'spring', '~> 2.1.0'
gem 'spring-commands-rspec', '~> 1.0.4' gem 'spring-commands-rspec', '~> 1.0.4'
gem 'gitlab-styles', '~> 6.0.0', require: false gem 'gitlab-styles', '~> 6.1.0', require: false
gem 'scss_lint', '~> 0.59.0', require: false
gem 'haml_lint', '~> 0.36.0', require: false gem 'haml_lint', '~> 0.36.0', require: false
gem 'bundler-audit', '~> 0.7.0.1', require: false gem 'bundler-audit', '~> 0.7.0.1', require: false
@ -399,6 +400,11 @@ group :development, :test do
gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false gem 'rblineprof', '~> 0.3.6', platform: :mri, require: false
end end
group :development, :test, :danger do
gem 'danger-gitlab', '~> 8.0', require: false
gem 'gitlab-dangerfiles', '~> 0.8.0', require: false
end
group :development, :test, :coverage do group :development, :test, :coverage do
gem 'simplecov', '~> 0.18.5', require: false gem 'simplecov', '~> 0.18.5', require: false
gem 'simplecov-cobertura', '~> 1.3.1', require: false gem 'simplecov-cobertura', '~> 1.3.1', require: false
@ -435,7 +441,7 @@ end
gem 'octokit', '~> 4.15' gem 'octokit', '~> 4.15'
# https://gitlab.com/gitlab-org/gitlab/issues/207207 # https://gitlab.com/gitlab-org/gitlab/issues/207207
gem 'gitlab-mail_room', '~> 0.0.8', require: 'mail_room' gem 'gitlab-mail_room', '~> 0.0.9', require: 'mail_room'
gem 'email_reply_trimmer', '~> 0.1' gem 'email_reply_trimmer', '~> 0.1'
gem 'html2text' gem 'html2text'
@ -484,7 +490,7 @@ gem 'flipper', '~> 0.17.1'
gem 'flipper-active_record', '~> 0.17.1' gem 'flipper-active_record', '~> 0.17.1'
gem 'flipper-active_support_cache_store', '~> 0.17.1' gem 'flipper-active_support_cache_store', '~> 0.17.1'
gem 'unleash', '~> 0.1.5' gem 'unleash', '~> 0.1.5'
gem 'gitlab-experiment', '~> 0.4.9' gem 'gitlab-experiment', '~> 0.5.0'
# Structured logging # Structured logging
gem 'lograge', '~> 0.5' gem 'lograge', '~> 0.5'

View file

@ -93,7 +93,7 @@ GEM
asciidoctor (~> 2.0) asciidoctor (~> 2.0)
asciidoctor-plantuml (0.0.12) asciidoctor-plantuml (0.0.12)
asciidoctor (>= 1.5.6, < 3.0.0) asciidoctor (>= 1.5.6, < 3.0.0)
ast (2.4.1) ast (2.4.2)
atlassian-jwt (0.2.0) atlassian-jwt (0.2.0)
jwt (~> 2.1.0) jwt (~> 2.1.0)
attr_encrypted (3.1.0) attr_encrypted (3.1.0)
@ -132,8 +132,8 @@ GEM
nokogiri (~> 1.11.0.rc2) nokogiri (~> 1.11.0.rc2)
babosa (1.0.2) babosa (1.0.2)
base32 (0.3.2) base32 (0.3.2)
batch-loader (1.4.0) batch-loader (2.0.1)
bcrypt (3.1.12) bcrypt (3.1.16)
bcrypt_pbkdf (1.0.0) bcrypt_pbkdf (1.0.0)
benchmark-ips (2.3.0) benchmark-ips (2.3.0)
benchmark-memory (0.1.2) benchmark-memory (0.1.2)
@ -177,6 +177,14 @@ GEM
cbor (0.5.9.6) cbor (0.5.9.6)
character_set (1.4.0) character_set (1.4.0)
charlock_holmes (0.7.7) charlock_holmes (0.7.7)
chef-config (16.10.17)
addressable
chef-utils (= 16.10.17)
fuzzyurl
mixlib-config (>= 2.2.12, < 4.0)
mixlib-shellout (>= 2.0, < 4.0)
tomlrb (~> 1.2)
chef-utils (16.10.17)
childprocess (3.0.0) childprocess (3.0.0)
chunky_png (1.3.5) chunky_png (1.3.5)
citrus (3.0.2) citrus (3.0.2)
@ -192,7 +200,7 @@ GEM
concord (0.1.5) concord (0.1.5)
adamantium (~> 0.2.0) adamantium (~> 0.2.0)
equalizer (~> 0.0.9) equalizer (~> 0.0.9)
concurrent-ruby (1.1.7) concurrent-ruby (1.1.8)
connection_pool (2.2.2) connection_pool (2.2.2)
contracts (0.11.0) contracts (0.11.0)
cork (0.3.0) cork (0.3.0)
@ -213,7 +221,7 @@ GEM
css_parser (1.7.0) css_parser (1.7.0)
addressable addressable
daemons (1.3.1) daemons (1.3.1)
danger (8.0.6) danger (8.2.3)
claide (~> 1.0) claide (~> 1.0)
claide-plugins (>= 0.9.2) claide-plugins (>= 0.9.2)
colored2 (~> 3.1) colored2 (~> 3.1)
@ -225,7 +233,10 @@ GEM
kramdown-parser-gfm (~> 1.0) kramdown-parser-gfm (~> 1.0)
no_proxy_fix no_proxy_fix
octokit (~> 4.7) octokit (~> 4.7)
terminal-table (~> 1) terminal-table (>= 1, < 4)
danger-gitlab (8.0.0)
danger
gitlab (~> 4.2, >= 4.2.0)
database_cleaner (1.7.0) database_cleaner (1.7.0)
debugger-ruby_core_source (1.3.8) debugger-ruby_core_source (1.3.8)
deckar01-task_list (2.3.1) deckar01-task_list (2.3.1)
@ -262,8 +273,8 @@ GEM
diff-lcs (1.4.4) diff-lcs (1.4.4)
diff_match_patch (0.1.0) diff_match_patch (0.1.0)
diffy (3.3.0) diffy (3.3.0)
discordrb-webhooks-blackst0ne (3.3.0) discordrb-webhooks (3.4.2)
rest-client (~> 2.0) rest-client (>= 2.0.0)
docile (1.3.2) docile (1.3.2)
domain_name (0.5.20190701) domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0) unf (>= 0.0.5, < 1.0.0)
@ -353,6 +364,8 @@ GEM
ffi-compiler (1.0.1) ffi-compiler (1.0.1)
ffi (>= 1.0.0) ffi (>= 1.0.0)
rake rake
ffi-yajl (2.3.4)
libyajl2 (~> 1.2)
flipper (0.17.1) flipper (0.17.1)
flipper-active_record (0.17.1) flipper-active_record (0.17.1)
activerecord (>= 4.2, < 7) activerecord (>= 4.2, < 7)
@ -368,7 +381,7 @@ GEM
fog-json fog-json
ipaddress (~> 0.8) ipaddress (~> 0.8)
xml-simple (~> 1.1) xml-simple (~> 1.1)
fog-aws (3.8.0) fog-aws (3.9.0)
fog-core (~> 2.1) fog-core (~> 2.1)
fog-json (~> 1.1) fog-json (~> 1.1)
fog-xml (~> 0.1) fog-xml (~> 0.1)
@ -378,12 +391,6 @@ GEM
excon (~> 0.58) excon (~> 0.58)
formatador (~> 0.2) formatador (~> 0.2)
mime-types mime-types
fog-google (1.12.0)
fog-core (<= 2.1.0)
fog-json (~> 1.2)
fog-xml (~> 0.1.0)
google-api-client (>= 0.44.2, < 0.51)
google-cloud-env (~> 1.2)
fog-json (1.2.0) fog-json (1.2.0)
fog-core fog-core
multi_json (~> 1.10) multi_json (~> 1.10)
@ -408,6 +415,7 @@ GEM
fuubar (2.2.0) fuubar (2.2.0)
rspec-core (~> 3.0) rspec-core (~> 3.0)
ruby-progressbar (~> 1.4) ruby-progressbar (~> 1.4)
fuzzyurl (0.9.0)
gemoji (3.0.1) gemoji (3.0.1)
gemojione (3.3.0) gemojione (3.3.0)
json json
@ -428,38 +436,49 @@ GEM
gitaly (13.9.0.pre.rc1) gitaly (13.9.0.pre.rc1)
grpc (~> 1.0) grpc (~> 1.0)
github-markup (1.7.0) github-markup (1.7.0)
gitlab (4.16.1)
httparty (~> 0.14, >= 0.14.0)
terminal-table (~> 1.5, >= 1.5.1)
gitlab-chronic (0.10.5) gitlab-chronic (0.10.5)
numerizer (~> 0.2) numerizer (~> 0.2)
gitlab-experiment (0.4.9) gitlab-dangerfiles (0.8.0)
danger
gitlab-experiment (0.5.0)
activesupport (>= 3.0) activesupport (>= 3.0)
scientist (~> 1.5, >= 1.5.0) scientist (~> 1.5, >= 1.5.0)
gitlab-fog-azure-rm (1.0.0) gitlab-fog-azure-rm (1.0.1)
azure-storage-blob (~> 2.0) azure-storage-blob (~> 2.0)
azure-storage-common (~> 2.0) azure-storage-common (~> 2.0)
fog-core (= 2.1.0) fog-core (= 2.1.0)
fog-json (~> 1.2.0) fog-json (~> 1.2.0)
mime-types mime-types
ms_rest_azure (~> 0.12.0) ms_rest_azure (~> 0.12.0)
gitlab-labkit (0.14.0) gitlab-fog-google (1.13.0)
addressable (>= 2.7.0)
fog-core (<= 2.1.0)
fog-json (~> 1.2)
fog-xml (~> 0.1.0)
google-api-client (>= 0.44.2, < 0.51)
google-cloud-env (~> 1.2)
gitlab-labkit (0.16.1)
actionpack (>= 5.0.0, < 7.0.0) actionpack (>= 5.0.0, < 7.0.0)
activesupport (>= 5.0.0, < 7.0.0) activesupport (>= 5.0.0, < 7.0.0)
gitlab-pg_query (~> 1.3)
grpc (~> 1.19) grpc (~> 1.19)
jaeger-client (~> 1.1) jaeger-client (~> 1.1)
opentracing (~> 0.4) opentracing (~> 0.4)
pg_query (~> 1.3)
redis (> 3.0.0, < 5.0.0) redis (> 3.0.0, < 5.0.0)
gitlab-license (1.3.0) gitlab-license (1.3.1)
gitlab-mail_room (0.0.8) gitlab-mail_room (0.0.9)
gitlab-markup (1.7.1) gitlab-markup (1.7.1)
gitlab-net-dns (0.9.1) gitlab-net-dns (0.9.1)
gitlab-pg_query (1.3.1)
gitlab-pry-byebug (3.9.0) gitlab-pry-byebug (3.9.0)
byebug (~> 11.0) byebug (~> 11.0)
pry (~> 0.13.0) pry (~> 0.13.0)
gitlab-sidekiq-fetcher (0.5.2) gitlab-sidekiq-fetcher (0.5.5)
sidekiq (~> 5) sidekiq (~> 5)
gitlab-styles (6.0.0) gitlab-styles (6.1.0)
rubocop (~> 0.91.1) rubocop (~> 0.91, >= 0.91.1)
rubocop-gitlab-security (~> 0.1.1) rubocop-gitlab-security (~> 0.1.1)
rubocop-performance (~> 1.9.2) rubocop-performance (~> 1.9.2)
rubocop-rails (~> 2.9) rubocop-rails (~> 2.9)
@ -525,7 +544,7 @@ GEM
faraday (>= 1.0) faraday (>= 1.0)
faraday_middleware faraday_middleware
graphql-client graphql-client
graphql (1.11.4) graphql (1.11.8)
graphql-client (0.16.0) graphql-client (0.16.0)
activesupport (>= 3.0) activesupport (>= 3.0)
graphql (~> 1.8) graphql (~> 1.8)
@ -600,7 +619,7 @@ GEM
mime-types (~> 3.0) mime-types (~> 3.0)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
httpclient (2.8.3) httpclient (2.8.3)
i18n (1.8.7) i18n (1.8.9)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
i18n_data (0.8.0) i18n_data (0.8.0)
icalendar (2.4.1) icalendar (2.4.1)
@ -670,6 +689,7 @@ GEM
actionmailer (>= 3.2) actionmailer (>= 3.2)
letter_opener (~> 1.0) letter_opener (~> 1.0)
railties (>= 3.2) railties (>= 3.2)
libyajl2 (1.2.0)
license_finder (6.0.0) license_finder (6.0.0)
bundler bundler
rubyzip (>= 1, < 3) rubyzip (>= 1, < 3)
@ -718,6 +738,12 @@ GEM
mini_mime (1.0.2) mini_mime (1.0.2)
mini_portile2 (2.5.0) mini_portile2 (2.5.0)
minitest (5.11.3) minitest (5.11.3)
mixlib-cli (2.1.8)
mixlib-config (3.0.9)
tomlrb
mixlib-log (3.0.9)
mixlib-shellout (3.2.5)
chef-utils
ms_rest (0.7.6) ms_rest (0.7.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
faraday (>= 0.9, < 2.0.0) faraday (>= 0.9, < 2.0.0)
@ -738,10 +764,12 @@ GEM
mustermann (>= 1.0.0) mustermann (>= 1.0.0)
nap (1.1.0) nap (1.1.0)
nenv (0.3.0) nenv (0.3.0)
net-http-persistent (4.0.0) net-http-persistent (4.0.1)
connection_pool (~> 2.2) connection_pool (~> 2.2)
net-ldap (0.16.3) net-ldap (0.16.3)
net-ntp (2.1.3) net-ntp (2.1.3)
net-scp (3.0.0)
net-ssh (>= 2.6.5, < 7.0.0)
net-ssh (6.0.0) net-ssh (6.0.0)
netrc (0.11.0) netrc (0.11.0)
nio4r (2.5.4) nio4r (2.5.4)
@ -765,6 +793,19 @@ GEM
octokit (4.20.0) octokit (4.20.0)
faraday (>= 0.9) faraday (>= 0.9)
sawyer (~> 0.8.0, >= 0.5.3) sawyer (~> 0.8.0, >= 0.5.3)
ohai (16.10.6)
chef-config (>= 12.8, < 17)
chef-utils (>= 16.0, < 17)
ffi (~> 1.9)
ffi-yajl (~> 2.2)
ipaddress
mixlib-cli (>= 1.7.0)
mixlib-config (>= 2.0, < 4.0)
mixlib-log (>= 2.0.1, < 4.0)
mixlib-shellout (>= 2.0, < 4.0)
plist (~> 3.1)
train-core
wmi-lite (~> 1.0)
oj (3.10.6) oj (3.10.6)
omniauth (1.9.0) omniauth (1.9.0)
hashie (>= 3.4.6, < 3.7.0) hashie (>= 3.4.6, < 3.7.0)
@ -777,6 +818,8 @@ GEM
omniauth-authentiq (0.3.3) omniauth-authentiq (0.3.3)
jwt (>= 1.5) jwt (>= 1.5)
omniauth-oauth2 (>= 1.5) omniauth-oauth2 (>= 1.5)
omniauth-azure-activedirectory-v2 (0.1.1)
omniauth-oauth2
omniauth-azure-oauth2 (0.0.10) omniauth-azure-oauth2 (0.0.10)
jwt (>= 1.0, < 3.0) jwt (>= 1.0, < 3.0)
omniauth (~> 1.0) omniauth (~> 1.0)
@ -856,6 +899,7 @@ GEM
railties (>= 4.0.0) railties (>= 4.0.0)
pg (1.2.3) pg (1.2.3)
pg_query (1.3.0) pg_query (1.3.0)
plist (3.6.0)
png_quantizator (0.2.1) png_quantizator (0.2.1)
po_to_json (1.0.1) po_to_json (1.0.1)
json (>= 1.6.0) json (>= 1.6.0)
@ -1042,16 +1086,16 @@ GEM
pg pg
rails rails
sqlite3 sqlite3
rubocop (0.91.1) rubocop (0.93.1)
parallel (~> 1.10) parallel (~> 1.10)
parser (>= 2.7.1.1) parser (>= 2.7.1.5)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.7) regexp_parser (>= 1.8)
rexml rexml
rubocop-ast (>= 0.4.0, < 1.0) rubocop-ast (>= 0.6.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0) unicode-display_width (>= 1.4.0, < 2.0)
rubocop-ast (0.8.0) rubocop-ast (1.4.1)
parser (>= 2.7.1.5) parser (>= 2.7.1.5)
rubocop-gitlab-security (0.1.1) rubocop-gitlab-security (0.1.1)
rubocop (>= 0.51) rubocop (>= 0.51)
@ -1082,7 +1126,7 @@ GEM
rubyntlm (0.6.2) rubyntlm (0.6.2)
rubypants (0.2.0) rubypants (0.2.0)
rubyzip (2.0.0) rubyzip (2.0.0)
rugged (1.0.1) rugged (1.1.0)
safe_yaml (1.0.4) safe_yaml (1.0.4)
safety_net_attestation (0.4.0) safety_net_attestation (0.4.0)
jwt (~> 2.0) jwt (~> 2.0)
@ -1107,9 +1151,7 @@ GEM
sawyer (0.8.2) sawyer (0.8.2)
addressable (>= 2.3.5) addressable (>= 2.3.5)
faraday (> 0.8, < 2.0) faraday (> 0.8, < 2.0)
scientist (1.5.0) scientist (1.6.0)
scss_lint (0.59.0)
sass (~> 3.5, >= 3.5.5)
securecompare (1.0.0) securecompare (1.0.0)
seed-fu (2.3.7) seed-fu (2.3.7)
activerecord (>= 3.1) activerecord (>= 3.1)
@ -1199,9 +1241,17 @@ GEM
parslet (~> 1.8.0) parslet (~> 1.8.0)
toml-rb (1.0.0) toml-rb (1.0.0)
citrus (~> 3.0, > 3.0) citrus (~> 3.0, > 3.0)
tomlrb (1.3.0)
tpm-key_attestation (0.9.0) tpm-key_attestation (0.9.0)
bindata (~> 2.4) bindata (~> 2.4)
openssl-signature_algorithm (~> 0.4.0) openssl-signature_algorithm (~> 0.4.0)
train-core (3.4.9)
addressable (~> 2.5)
ffi (!= 1.13.0)
json (>= 1.8, < 3.0)
mixlib-shellout (>= 2.0, < 4.0)
net-scp (>= 1.2, < 4.0)
net-ssh (>= 2.9, < 7.0)
truncato (0.7.11) truncato (0.7.11)
htmlentities (~> 4.3.1) htmlentities (~> 4.3.1)
nokogiri (>= 1.7.0, <= 2.0) nokogiri (>= 1.7.0, <= 2.0)
@ -1238,7 +1288,7 @@ GEM
validate_email (0.1.6) validate_email (0.1.6)
activemodel (>= 3.0) activemodel (>= 3.0)
mail (>= 2.2.5) mail (>= 2.2.5)
validate_url (1.0.8) validate_url (1.0.13)
activemodel (>= 3.0.0) activemodel (>= 3.0.0)
public_suffix public_suffix
validates_hostname (1.0.11) validates_hostname (1.0.11)
@ -1274,6 +1324,7 @@ GEM
expression_parser expression_parser
rinku rinku
with_env (1.1.0) with_env (1.1.0)
wmi-lite (1.0.5)
xml-simple (1.1.5) xml-simple (1.1.5)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
@ -1305,8 +1356,8 @@ DEPENDENCIES
aws-sdk-s3 (~> 1) aws-sdk-s3 (~> 1)
babosa (~> 1.0.2) babosa (~> 1.0.2)
base32 (~> 0.3.0) base32 (~> 0.3.0)
batch-loader (~> 1.4.0) batch-loader (~> 2.0.1)
bcrypt (= 3.1.12) bcrypt (~> 3.1, >= 3.1.14)
bcrypt_pbkdf (~> 1.0) bcrypt_pbkdf (~> 1.0)
benchmark-ips (~> 2.3.0) benchmark-ips (~> 2.3.0)
benchmark-memory (~> 0.1) benchmark-memory (~> 0.1)
@ -1327,7 +1378,7 @@ DEPENDENCIES
countries (~> 3.0) countries (~> 3.0)
creole (~> 0.5.0) creole (~> 0.5.0)
crystalball (~> 0.7.0) crystalball (~> 0.7.0)
danger (~> 8.0.6) danger-gitlab (~> 8.0)
database_cleaner (~> 1.7.0) database_cleaner (~> 1.7.0)
deckar01-task_list (= 2.3.1) deckar01-task_list (= 2.3.1)
default_value_for (~> 3.4.0) default_value_for (~> 3.4.0)
@ -1338,7 +1389,7 @@ DEPENDENCIES
devise-two-factor (~> 3.1.0) devise-two-factor (~> 3.1.0)
diff_match_patch (~> 0.1.0) diff_match_patch (~> 0.1.0)
diffy (~> 3.3) diffy (~> 3.3)
discordrb-webhooks-blackst0ne (~> 3.3) discordrb-webhooks (~> 3.4)
doorkeeper (~> 5.5.0.rc2) doorkeeper (~> 5.5.0.rc2)
doorkeeper-openid_connect (~> 1.7.5) doorkeeper-openid_connect (~> 1.7.5)
ed25519 (~> 1.2) ed25519 (~> 1.2)
@ -1359,9 +1410,8 @@ DEPENDENCIES
flipper-active_support_cache_store (~> 0.17.1) flipper-active_support_cache_store (~> 0.17.1)
flowdock (~> 0.7) flowdock (~> 0.7)
fog-aliyun (~> 0.3) fog-aliyun (~> 0.3)
fog-aws (~> 3.8) fog-aws (~> 3.9)
fog-core (= 2.1.0) fog-core (= 2.1.0)
fog-google (~> 1.12)
fog-local (~> 0.6) fog-local (~> 0.6)
fog-openstack (~> 1.0) fog-openstack (~> 1.0)
fog-rackspace (~> 0.1.1) fog-rackspace (~> 0.1.1)
@ -1374,16 +1424,18 @@ DEPENDENCIES
gitaly (~> 13.9.0.pre.rc1) gitaly (~> 13.9.0.pre.rc1)
github-markup (~> 1.7.0) github-markup (~> 1.7.0)
gitlab-chronic (~> 0.10.5) gitlab-chronic (~> 0.10.5)
gitlab-experiment (~> 0.4.9) gitlab-dangerfiles (~> 0.8.0)
gitlab-fog-azure-rm (~> 1.0) gitlab-experiment (~> 0.5.0)
gitlab-labkit (= 0.14.0) gitlab-fog-azure-rm (~> 1.0.1)
gitlab-fog-google (~> 1.13)
gitlab-labkit (~> 0.16.1)
gitlab-license (~> 1.3) gitlab-license (~> 1.3)
gitlab-mail_room (~> 0.0.8) gitlab-mail_room (~> 0.0.9)
gitlab-markup (~> 1.7.1) gitlab-markup (~> 1.7.1)
gitlab-net-dns (~> 0.9.1) gitlab-net-dns (~> 0.9.1)
gitlab-pry-byebug gitlab-pry-byebug
gitlab-sidekiq-fetcher (= 0.5.2) gitlab-sidekiq-fetcher (= 0.5.5)
gitlab-styles (~> 6.0.0) gitlab-styles (~> 6.1.0)
gitlab_chronic_duration (~> 0.10.6.2) gitlab_chronic_duration (~> 0.10.6.2)
gitlab_omniauth-ldap (~> 2.1.1) gitlab_omniauth-ldap (~> 2.1.1)
gon (~> 6.2) gon (~> 6.2)
@ -1396,7 +1448,7 @@ DEPENDENCIES
grape_logging (~> 1.7) grape_logging (~> 1.7)
graphiql-rails (~> 1.4.10) graphiql-rails (~> 1.4.10)
graphlient (~> 0.4.0) graphlient (~> 0.4.0)
graphql (~> 1.11.4) graphql (~> 1.11.8)
graphql-docs (~> 1.6.0) graphql-docs (~> 1.6.0)
grpc (~> 1.30.2) grpc (~> 1.30.2)
gssapi gssapi
@ -1445,11 +1497,13 @@ DEPENDENCIES
nokogiri (~> 1.11.1) nokogiri (~> 1.11.1)
oauth2 (~> 1.4) oauth2 (~> 1.4)
octokit (~> 4.15) octokit (~> 4.15)
ohai (~> 16.10)
oj (~> 3.10.6) oj (~> 3.10.6)
omniauth (~> 1.8) omniauth (~> 1.8)
omniauth-atlassian-oauth2 (~> 0.2.0) omniauth-atlassian-oauth2 (~> 0.2.0)
omniauth-auth0 (~> 2.0.0) omniauth-auth0 (~> 2.0.0)
omniauth-authentiq (~> 0.3.3) omniauth-authentiq (~> 0.3.3)
omniauth-azure-activedirectory-v2 (~> 0.1)
omniauth-azure-oauth2 (~> 0.0.9) omniauth-azure-oauth2 (~> 0.0.9)
omniauth-cas3 (~> 1.1.4) omniauth-cas3 (~> 1.1.4)
omniauth-facebook (~> 4.0.0) omniauth-facebook (~> 4.0.0)
@ -1514,10 +1568,9 @@ DEPENDENCIES
ruby-saml (~> 1.12.1) ruby-saml (~> 1.12.1)
ruby_parser (~> 3.15) ruby_parser (~> 3.15)
rubyzip (~> 2.0.0) rubyzip (~> 2.0.0)
rugged (~> 1.0.1) rugged (~> 1.1)
sanitize (~> 5.2.1) sanitize (~> 5.2.1)
sassc-rails (~> 2.1.0) sassc-rails (~> 2.1.0)
scss_lint (~> 0.59.0)
seed-fu (~> 2.3.7) seed-fu (~> 2.3.7)
selenium-webdriver (~> 3.142) selenium-webdriver (~> 3.142)
sentry-raven (~> 3.0) sentry-raven (~> 3.0)

View file

@ -77,9 +77,9 @@ star, smile, etc.). Some good tips about code reviews can be found in our
## Feature flags ## Feature flags
Overview and details of feature flag processes in development of GitLab itself is described in [feature flags process documentation](https://docs.gitlab.com/ee/development/feature_flags/process.html). Overview and details of feature flag processes in development of GitLab itself is described in [feature flags process documentation](https://about.gitlab.com/handbook/product-development-flow/feature-flag-lifecycle/).
Guides on how to include feature flags in your backend/frontend code while developing GitLab are described in [developing with feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/development.html). Guides on how to include feature flags in your backend/frontend code while developing GitLab are described in [developing with feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags).
Getting access and how to expose the feature to users is detailed in [controlling feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/controls.html). Getting access and how to expose the feature to users is detailed in [controlling feature flags documentation](https://docs.gitlab.com/ee/development/feature_flags/controls.html).

View file

@ -1 +1 @@
13.9.6 13.10.3

View file

@ -0,0 +1,5 @@
<svg width="26" height="26" viewBox="0 0 26 26" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M13 25C19.6274 25 25 19.6274 25 13C25 6.37258 19.6274 1 13 1C6.37258 1 1 6.37258 1 13C1 19.6274 6.37258 25 13 25Z" fill="white" stroke="#C2B7E6" stroke-width="2"/>
<path d="M1.16748 12.3359C2.88075 11.7701 4.4618 10.8635 5.81545 9.67055C7.16911 8.47763 8.26738 7.02313 9.04415 5.39461M6.94481 2.60461C9.28681 6.43995 13.5115 8.99995 18.3335 8.99995C20.2715 8.99995 22.1135 8.58661 23.7748 7.84261L6.94481 2.60461Z" stroke="#C2B7E6"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.1176 15.8941H15.7647C15.7647 17.447 14.4941 18.7176 12.9412 18.7176C11.3882 18.7176 10.1176 17.447 10.1176 15.8941ZM9.05882 15.1882C8.47294 15.1882 8 14.7153 8 14.1294C8 13.5435 8.47294 13.0706 9.05882 13.0706C9.64471 13.0706 10.1176 13.5435 10.1176 14.1294C10.1176 14.7153 9.64471 15.1882 9.05882 15.1882ZM16.8235 15.1882C16.2376 15.1882 15.7647 14.7153 15.7647 14.1294C15.7647 13.5435 16.2376 13.0706 16.8235 13.0706C17.4094 13.0706 17.8824 13.5435 17.8824 14.1294C17.8824 14.7153 17.4094 15.1882 16.8235 15.1882Z" fill="#6B4FBB"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,16 @@
<svg width="40" height="39" viewBox="0 0 40 39" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path d="M32.2886 3.99573H37.8624C38.1834 3.99573 38.4435 4.25587 38.4435 4.57679V33.9598C38.4435 34.2808 38.1834 34.5409 37.8624 34.5409H32.2886V3.99573Z" fill="#F0F0F0" stroke="#DBDBDB" stroke-width="2"/>
<path d="M10.757 9.4011L10.7363 4.92686C10.7337 4.35386 11.1491 3.86447 11.7148 3.77395L30.908 0.703095C31.614 0.590124 32.2537 1.13556 32.2537 1.85062V37.0106C32.2537 37.723 31.6184 38.2678 30.9143 38.1591L11.8555 35.2171C11.2908 35.13 10.8733 34.6453 10.8707 34.074L10.8502 29.6368" stroke="#DBDBDB" stroke-width="2"/>
<path d="M11.2195 29.7561C16.877 29.7561 21.4634 25.1698 21.4634 19.5122C21.4634 13.8547 16.877 9.26831 11.2195 9.26831C5.56194 9.26831 0.975586 13.8547 0.975586 19.5122C0.975586 25.1698 5.56194 29.7561 11.2195 29.7561Z" stroke="#6E49CB"/>
<path d="M11.2194 27.8048C15.7994 27.8048 19.5121 24.0921 19.5121 19.5122C19.5121 14.9322 15.7994 11.2195 11.2194 11.2195C6.63952 11.2195 2.92676 14.9322 2.92676 19.5122C2.92676 24.0921 6.63952 27.8048 11.2194 27.8048Z" fill="#6E49CB"/>
<path d="M11.2194 27.8048C15.7994 27.8048 19.5121 24.0921 19.5121 19.5122C19.5121 14.9322 15.7994 11.2195 11.2194 11.2195C6.63952 11.2195 2.92676 14.9322 2.92676 19.5122C2.92676 24.0921 6.63952 27.8048 11.2194 27.8048Z" fill="white" fill-opacity="0.9"/>
<path d="M10.8843 23.4146V16.276" stroke="#6E49CB" stroke-linecap="round"/>
<path d="M7.31689 19.6609H14.634" stroke="#6E49CB" stroke-linecap="round"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="40" height="39.0244" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,107 @@
<svg width="79" height="47" viewBox="0 0 79 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0)">
<path d="M27.0655 1.96289H5.80354C4.48549 1.96289 3.41699 3.03139 3.41699 4.34944C3.41699 5.6675 4.48549 6.73599 5.80354 6.73599H27.0655C28.3836 6.73599 29.4521 5.6675 29.4521 4.34944C29.4521 3.03139 28.3836 1.96289 27.0655 1.96289Z" fill="#F9F9F9"/>
<path d="M23.1603 11.5092H-0.705247C-2.0233 11.5092 -3.0918 12.5776 -3.0918 13.8957C-3.0918 15.2138 -2.0233 16.2823 -0.705247 16.2823H23.1603C24.4783 16.2823 25.5468 15.2138 25.5468 13.8957C25.5468 12.5776 24.4783 11.5092 23.1603 11.5092Z" fill="#F9F9F9"/>
<path d="M80.8713 16.2822H44.4222C43.1041 16.2822 42.0356 17.3507 42.0356 18.6688C42.0356 19.9868 43.1041 21.0553 44.4222 21.0553H80.8713C82.1894 21.0553 83.2579 19.9868 83.2579 18.6688C83.2579 17.3507 82.1894 16.2822 80.8713 16.2822Z" fill="#F9F9F9"/>
<path d="M56.789 44.7039H27.2825C25.9645 44.7039 24.896 45.7724 24.896 47.0904C24.896 48.4085 25.9645 49.477 27.2825 49.477H56.789C58.107 49.477 59.1755 48.4085 59.1755 47.0904C59.1755 45.7724 58.107 44.7039 56.789 44.7039Z" fill="#F9F9F9"/>
<path d="M43.1205 35.3746H13.6141C12.296 35.3746 11.2275 36.4431 11.2275 37.7612C11.2275 39.0792 12.296 40.1477 13.6141 40.1477H43.1205C44.4386 40.1477 45.5071 39.0792 45.5071 37.7612C45.5071 36.4431 44.4386 35.3746 43.1205 35.3746Z" fill="#F9F9F9"/>
<path d="M77.1829 25.8284H6.02034C4.70228 25.8284 3.63379 26.8969 3.63379 28.2149C3.63379 29.533 4.70228 30.6015 6.02034 30.6015H77.1829C78.501 30.6015 79.5695 29.533 79.5695 28.2149C79.5695 26.8969 78.501 25.8284 77.1829 25.8284Z" fill="#F9F9F9"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.103 6.73596H1.46436H6.12898C7.43073 6.73596 8.51553 7.82076 8.51553 9.12251C8.51553 10.4243 7.43073 11.5091 6.12898 11.5091H1.46436H30.103H22.1839C20.8822 11.5091 19.7974 10.4243 19.7974 9.12251C19.7974 7.82076 20.8822 6.73596 22.1839 6.73596H30.103ZM84.7766 21.0553H59.3924H67.3114C68.6132 21.0553 69.698 22.1401 69.698 23.4418C69.698 24.7436 68.6132 25.8284 67.3114 25.8284H59.3924H84.7766H76.8576C75.5559 25.8284 74.4711 24.7436 74.4711 23.4418C74.4711 22.1401 75.5559 21.0553 76.8576 21.0553H84.7766ZM31.8386 30.6015H6.45441H14.3734C15.6752 30.6015 16.76 31.6862 16.76 32.988C16.76 34.2898 15.6752 35.3746 14.3734 35.3746H6.45441H31.8386H23.9196C22.6179 35.3746 21.5331 34.2898 21.5331 32.988C21.5331 31.6862 22.6179 30.6015 23.9196 30.6015H31.8386ZM48.1106 40.1477H22.7263H27.391C28.6927 40.1477 29.7775 41.2324 29.7775 42.5342C29.7775 43.836 28.6927 44.9207 27.391 44.9207H22.7263H48.1106H36.9372C35.6354 44.9207 34.5506 43.836 34.5506 42.5342C34.5506 41.2324 35.6354 40.1477 36.9372 40.1477H48.1106Z" fill="#F9F9F9"/>
<path d="M68.0708 4.78333H12.0954C10.8971 4.78333 9.92578 5.75468 9.92578 6.95292V41.4494C9.92578 42.6476 10.8971 43.619 12.0954 43.619H68.0708C69.269 43.619 70.2404 42.6476 70.2404 41.4494V6.95292C70.2404 5.75468 69.269 4.78333 68.0708 4.78333Z" fill="white" stroke="#EEEEEE" stroke-width="2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M10.7935 11.0751H69.5894V11.9429H10.7935V11.0751Z" fill="#EEEEEE"/>
<path d="M18.387 18.0178H17.5192C17.3994 18.0178 17.3022 18.115 17.3022 18.2348C17.3022 18.3546 17.3994 18.4517 17.5192 18.4517H18.387C18.5069 18.4517 18.604 18.3546 18.604 18.2348C18.604 18.115 18.5069 18.0178 18.387 18.0178Z" fill="#B5A7DD"/>
<path d="M23.3771 17.8009H20.9906C20.7509 17.8009 20.5566 17.9952 20.5566 18.2348C20.5566 18.4745 20.7509 18.6687 20.9906 18.6687H23.3771C23.6167 18.6687 23.811 18.4745 23.811 18.2348C23.811 17.9952 23.6167 17.8009 23.3771 17.8009Z" fill="#EEEEEE"/>
<path d="M35.7438 17.8009H33.3573C33.1176 17.8009 32.9233 17.9952 32.9233 18.2348C32.9233 18.4745 33.1176 18.6687 33.3573 18.6687H35.7438C35.9835 18.6687 36.1777 18.4745 36.1777 18.2348C36.1777 17.9952 35.9835 17.8009 35.7438 17.8009Z" fill="#EEEEEE"/>
<path d="M28.5841 22.574H26.1976C25.9579 22.574 25.7637 22.7682 25.7637 23.0079C25.7637 23.2475 25.9579 23.4418 26.1976 23.4418H28.5841C28.8238 23.4418 29.0181 23.2475 29.0181 23.0079C29.0181 22.7682 28.8238 22.574 28.5841 22.574Z" fill="#EEEEEE"/>
<path d="M31.6217 20.1875H29.2352C28.9955 20.1875 28.8013 20.3818 28.8013 20.6214C28.8013 20.8611 28.9955 21.0553 29.2352 21.0553H31.6217C31.8614 21.0553 32.0557 20.8611 32.0557 20.6214C32.0557 20.3818 31.8614 20.1875 31.6217 20.1875Z" fill="#FC6D26"/>
<path opacity="0.5" d="M31.6216 17.8009H28.1502C27.9106 17.8009 27.7163 17.9952 27.7163 18.2348C27.7163 18.4745 27.9106 18.6687 28.1502 18.6687H31.6216C31.8612 18.6687 32.0555 18.4745 32.0555 18.2348C32.0555 17.9952 31.8612 17.8009 31.6216 17.8009Z" fill="#FC6D26"/>
<path d="M24.4619 22.574H20.9906C20.7509 22.574 20.5566 22.7682 20.5566 23.0079C20.5566 23.2475 20.7509 23.4418 20.9906 23.4418H24.4619C24.7016 23.4418 24.8958 23.2475 24.8958 23.0079C24.8958 22.7682 24.7016 22.574 24.4619 22.574Z" fill="#EEEEEE"/>
<path d="M27.4995 20.1875H24.0282C23.7885 20.1875 23.5942 20.3818 23.5942 20.6214C23.5942 20.8611 23.7885 21.0553 24.0282 21.0553H27.4995C27.7392 21.0553 27.9334 20.8611 27.9334 20.6214C27.9334 20.3818 27.7392 20.1875 27.4995 20.1875Z" fill="#EEEEEE"/>
<path d="M26.4144 17.8009H25.1126C24.873 17.8009 24.6787 17.9952 24.6787 18.2348C24.6787 18.4745 24.873 18.6687 25.1126 18.6687H26.4144C26.654 18.6687 26.8483 18.4745 26.8483 18.2348C26.8483 17.9952 26.654 17.8009 26.4144 17.8009Z" fill="#FC6D26"/>
<path d="M22.2923 20.1875H20.9906C20.7509 20.1875 20.5566 20.3818 20.5566 20.6214C20.5566 20.8611 20.7509 21.0553 20.9906 21.0553H22.2923C22.532 21.0553 22.7262 20.8611 22.7262 20.6214C22.7262 20.3818 22.532 20.1875 22.2923 20.1875Z" fill="#EEEEEE"/>
<path d="M18.387 20.4044H17.5192C17.3994 20.4044 17.3022 20.5016 17.3022 20.6214C17.3022 20.7412 17.3994 20.8383 17.5192 20.8383H18.387C18.5069 20.8383 18.604 20.7412 18.604 20.6214C18.604 20.5016 18.5069 20.4044 18.387 20.4044Z" fill="#B5A7DD"/>
<path d="M18.387 22.791H17.5192C17.3994 22.791 17.3022 22.8882 17.3022 23.008C17.3022 23.1278 17.3994 23.2249 17.5192 23.2249H18.387C18.5069 23.2249 18.604 23.1278 18.604 23.008C18.604 22.8882 18.5069 22.791 18.387 22.791Z" fill="#B5A7DD"/>
<path d="M18.387 25.1774H17.5192C17.3994 25.1774 17.3022 25.2745 17.3022 25.3943C17.3022 25.5142 17.3994 25.6113 17.5192 25.6113H18.387C18.5069 25.6113 18.604 25.5142 18.604 25.3943C18.604 25.2745 18.5069 25.1774 18.387 25.1774Z" fill="#B5A7DD"/>
<path d="M23.3771 24.9604H20.9906C20.7509 24.9604 20.5566 25.1547 20.5566 25.3944C20.5566 25.634 20.7509 25.8283 20.9906 25.8283H23.3771C23.6167 25.8283 23.811 25.634 23.811 25.3944C23.811 25.1547 23.6167 24.9604 23.3771 24.9604Z" fill="#FC6D26"/>
<path d="M35.7438 24.9604H33.3573C33.1176 24.9604 32.9233 25.1547 32.9233 25.3944C32.9233 25.634 33.1176 25.8283 33.3573 25.8283H35.7438C35.9835 25.8283 36.1777 25.634 36.1777 25.3944C36.1777 25.1547 35.9835 24.9604 35.7438 24.9604Z" fill="#EEEEEE"/>
<path opacity="0.5" d="M28.5841 29.7335H26.1976C25.9579 29.7335 25.7637 29.9278 25.7637 30.1674C25.7637 30.4071 25.9579 30.6014 26.1976 30.6014H28.5841C28.8238 30.6014 29.0181 30.4071 29.0181 30.1674C29.0181 29.9278 28.8238 29.7335 28.5841 29.7335Z" fill="#FC6D26"/>
<path d="M31.6217 27.347H29.2352C28.9955 27.347 28.8013 27.5413 28.8013 27.781C28.8013 28.0206 28.9955 28.2149 29.2352 28.2149H31.6217C31.8614 28.2149 32.0557 28.0206 32.0557 27.781C32.0557 27.5413 31.8614 27.347 31.6217 27.347Z" fill="#EEEEEE"/>
<path d="M31.6216 24.9604H28.1502C27.9106 24.9604 27.7163 25.1547 27.7163 25.3944C27.7163 25.634 27.9106 25.8283 28.1502 25.8283H31.6216C31.8612 25.8283 32.0555 25.634 32.0555 25.3944C32.0555 25.1547 31.8612 24.9604 31.6216 24.9604Z" fill="#FC6D26"/>
<path d="M24.4619 29.7335H20.9906C20.7509 29.7335 20.5566 29.9278 20.5566 30.1674C20.5566 30.4071 20.7509 30.6014 20.9906 30.6014H24.4619C24.7016 30.6014 24.8958 30.4071 24.8958 30.1674C24.8958 29.9278 24.7016 29.7335 24.4619 29.7335Z" fill="#FC6D26"/>
<path d="M27.4995 27.347H24.0282C23.7885 27.347 23.5942 27.5413 23.5942 27.781C23.5942 28.0206 23.7885 28.2149 24.0282 28.2149H27.4995C27.7392 28.2149 27.9334 28.0206 27.9334 27.781C27.9334 27.5413 27.7392 27.347 27.4995 27.347Z" fill="#EEEEEE"/>
<path opacity="0.5" d="M26.4144 24.9604H25.1126C24.873 24.9604 24.6787 25.1547 24.6787 25.3944C24.6787 25.634 24.873 25.8283 25.1126 25.8283H26.4144C26.654 25.8283 26.8483 25.634 26.8483 25.3944C26.8483 25.1547 26.654 24.9604 26.4144 24.9604Z" fill="#FC6D26"/>
<path d="M22.2923 27.347H20.9906C20.7509 27.347 20.5566 27.5413 20.5566 27.781C20.5566 28.0206 20.7509 28.2149 20.9906 28.2149H22.2923C22.532 28.2149 22.7262 28.0206 22.7262 27.781C22.7262 27.5413 22.532 27.347 22.2923 27.347Z" fill="#EEEEEE"/>
<path d="M18.387 27.564H17.5192C17.3994 27.564 17.3022 27.6611 17.3022 27.7809C17.3022 27.9007 17.3994 27.9979 17.5192 27.9979H18.387C18.5069 27.9979 18.604 27.9007 18.604 27.7809C18.604 27.6611 18.5069 27.564 18.387 27.564Z" fill="#B5A7DD"/>
<path d="M18.387 29.9506H17.5192C17.3994 29.9506 17.3022 30.0477 17.3022 30.1675C17.3022 30.2873 17.3994 30.3845 17.5192 30.3845H18.387C18.5069 30.3845 18.604 30.2873 18.604 30.1675C18.604 30.0477 18.5069 29.9506 18.387 29.9506Z" fill="#B5A7DD"/>
<path d="M18.387 32.337H17.5192C17.3994 32.337 17.3022 32.4342 17.3022 32.554C17.3022 32.6738 17.3994 32.771 17.5192 32.771H18.387C18.5069 32.771 18.604 32.6738 18.604 32.554C18.604 32.4342 18.5069 32.337 18.387 32.337Z" fill="#B5A7DD"/>
<path d="M23.3771 32.1201H20.9906C20.7509 32.1201 20.5566 32.3144 20.5566 32.554C20.5566 32.7937 20.7509 32.988 20.9906 32.988H23.3771C23.6167 32.988 23.811 32.7937 23.811 32.554C23.811 32.3144 23.6167 32.1201 23.3771 32.1201Z" fill="#EEEEEE"/>
<path d="M35.7438 32.1201H33.3573C33.1176 32.1201 32.9233 32.3144 32.9233 32.554C32.9233 32.7937 33.1176 32.988 33.3573 32.988H35.7438C35.9835 32.988 36.1777 32.7937 36.1777 32.554C36.1777 32.3144 35.9835 32.1201 35.7438 32.1201Z" fill="#EEEEEE"/>
<path d="M28.5841 36.8932H26.1976C25.9579 36.8932 25.7637 37.0875 25.7637 37.3271C25.7637 37.5668 25.9579 37.761 26.1976 37.761H28.5841C28.8238 37.761 29.0181 37.5668 29.0181 37.3271C29.0181 37.0875 28.8238 36.8932 28.5841 36.8932Z" fill="#EEEEEE"/>
<path d="M31.6217 34.5067H29.2352C28.9955 34.5067 28.8013 34.701 28.8013 34.9406C28.8013 35.1803 28.9955 35.3745 29.2352 35.3745H31.6217C31.8614 35.3745 32.0557 35.1803 32.0557 34.9406C32.0557 34.701 31.8614 34.5067 31.6217 34.5067Z" fill="#EEEEEE"/>
<path d="M31.6216 32.1201H28.1502C27.9106 32.1201 27.7163 32.3144 27.7163 32.554C27.7163 32.7937 27.9106 32.988 28.1502 32.988H31.6216C31.8612 32.988 32.0555 32.7937 32.0555 32.554C32.0555 32.3144 31.8612 32.1201 31.6216 32.1201Z" fill="#FC6D26"/>
<path d="M24.4619 36.8932H20.9906C20.7509 36.8932 20.5566 37.0875 20.5566 37.3271C20.5566 37.5668 20.7509 37.761 20.9906 37.761H24.4619C24.7016 37.761 24.8958 37.5668 24.8958 37.3271C24.8958 37.0875 24.7016 36.8932 24.4619 36.8932Z" fill="#EEEEEE"/>
<path d="M27.4995 34.5067H24.0282C23.7885 34.5067 23.5942 34.701 23.5942 34.9406C23.5942 35.1803 23.7885 35.3745 24.0282 35.3745H27.4995C27.7392 35.3745 27.9334 35.1803 27.9334 34.9406C27.9334 34.701 27.7392 34.5067 27.4995 34.5067Z" fill="#EEEEEE"/>
<path opacity="0.5" d="M26.4144 32.1201H25.1126C24.873 32.1201 24.6787 32.3144 24.6787 32.554C24.6787 32.7937 24.873 32.988 25.1126 32.988H26.4144C26.654 32.988 26.8483 32.7937 26.8483 32.554C26.8483 32.3144 26.654 32.1201 26.4144 32.1201Z" fill="#FC6D26"/>
<path d="M22.2923 34.5067H20.9906C20.7509 34.5067 20.5566 34.701 20.5566 34.9406C20.5566 35.1803 20.7509 35.3745 20.9906 35.3745H22.2923C22.532 35.3745 22.7262 35.1803 22.7262 34.9406C22.7262 34.701 22.532 34.5067 22.2923 34.5067Z" fill="#EEEEEE"/>
<path d="M18.387 34.7236H17.5192C17.3994 34.7236 17.3022 34.8208 17.3022 34.9406C17.3022 35.0604 17.3994 35.1575 17.5192 35.1575H18.387C18.5069 35.1575 18.604 35.0604 18.604 34.9406C18.604 34.8208 18.5069 34.7236 18.387 34.7236Z" fill="#B5A7DD"/>
<path d="M18.387 37.1102H17.5192C17.3994 37.1102 17.3022 37.2074 17.3022 37.3272C17.3022 37.447 17.3994 37.5442 17.5192 37.5442H18.387C18.5069 37.5442 18.604 37.447 18.604 37.3272C18.604 37.2074 18.5069 37.1102 18.387 37.1102Z" fill="#B5A7DD"/>
<path d="M45.073 17.8008H44.2052C44.0854 17.8008 43.9883 17.8979 43.9883 18.0177C43.9883 18.1376 44.0854 18.2347 44.2052 18.2347H45.073C45.1929 18.2347 45.29 18.1376 45.29 18.0177C45.29 17.8979 45.1929 17.8008 45.073 17.8008Z" fill="#FDE5D8"/>
<path d="M50.0631 17.5839H47.6766C47.4369 17.5839 47.2427 17.7781 47.2427 18.0178C47.2427 18.2574 47.4369 18.4517 47.6766 18.4517H50.0631C50.3028 18.4517 50.4971 18.2574 50.4971 18.0178C50.4971 17.7781 50.3028 17.5839 50.0631 17.5839Z" fill="#EEEEEE"/>
<path d="M62.4299 17.5839H60.0433C59.8036 17.5839 59.6094 17.7781 59.6094 18.0178C59.6094 18.2574 59.8036 18.4517 60.0433 18.4517H62.4299C62.6695 18.4517 62.8638 18.2574 62.8638 18.0178C62.8638 17.7781 62.6695 17.5839 62.4299 17.5839Z" fill="#EEEEEE"/>
<path opacity="0.5" d="M55.2702 22.3569H52.8836C52.644 22.3569 52.4497 22.5512 52.4497 22.7909C52.4497 23.0305 52.644 23.2248 52.8836 23.2248H55.2702C55.5098 23.2248 55.7041 23.0305 55.7041 22.7909C55.7041 22.5512 55.5098 22.3569 55.2702 22.3569Z" fill="#6B4FBB"/>
<path d="M58.3078 19.9705H55.9212C55.6816 19.9705 55.4873 20.1647 55.4873 20.4044C55.4873 20.644 55.6816 20.8383 55.9212 20.8383H58.3078C58.5474 20.8383 58.7417 20.644 58.7417 20.4044C58.7417 20.1647 58.5474 19.9705 58.3078 19.9705Z" fill="#6B4FBB"/>
<path opacity="0.5" d="M58.3076 17.5839H54.8363C54.5966 17.5839 54.4023 17.7781 54.4023 18.0178C54.4023 18.2574 54.5966 18.4517 54.8363 18.4517H58.3076C58.5473 18.4517 58.7415 18.2574 58.7415 18.0178C58.7415 17.7781 58.5473 17.5839 58.3076 17.5839Z" fill="#6B4FBB"/>
<path d="M51.1479 22.3569H47.6766C47.4369 22.3569 47.2427 22.5512 47.2427 22.7909C47.2427 23.0305 47.4369 23.2248 47.6766 23.2248H51.1479C51.3876 23.2248 51.5819 23.0305 51.5819 22.7909C51.5819 22.5512 51.3876 22.3569 51.1479 22.3569Z" fill="#6B4FBB"/>
<path d="M54.1855 19.9705H50.7142C50.4745 19.9705 50.2803 20.1647 50.2803 20.4044C50.2803 20.644 50.4745 20.8383 50.7142 20.8383H54.1855C54.4252 20.8383 54.6195 20.644 54.6195 20.4044C54.6195 20.1647 54.4252 19.9705 54.1855 19.9705Z" fill="#EEEEEE"/>
<path d="M53.1004 17.5839H51.7987C51.559 17.5839 51.3647 17.7781 51.3647 18.0178C51.3647 18.2574 51.559 18.4517 51.7987 18.4517H53.1004C53.3401 18.4517 53.5343 18.2574 53.5343 18.0178C53.5343 17.7781 53.3401 17.5839 53.1004 17.5839Z" fill="#6B4FBB"/>
<path d="M48.9783 19.9705H47.6766C47.4369 19.9705 47.2427 20.1647 47.2427 20.4044C47.2427 20.644 47.4369 20.8383 47.6766 20.8383H48.9783C49.218 20.8383 49.4123 20.644 49.4123 20.4044C49.4123 20.1647 49.218 19.9705 48.9783 19.9705Z" fill="#EEEEEE"/>
<path d="M45.073 20.1874H44.2052C44.0854 20.1874 43.9883 20.2845 43.9883 20.4043C43.9883 20.5242 44.0854 20.6213 44.2052 20.6213H45.073C45.1929 20.6213 45.29 20.5242 45.29 20.4043C45.29 20.2845 45.1929 20.1874 45.073 20.1874Z" fill="#FDE5D8"/>
<path d="M45.073 22.574H44.2052C44.0854 22.574 43.9883 22.6711 43.9883 22.7909C43.9883 22.9108 44.0854 23.0079 44.2052 23.0079H45.073C45.1929 23.0079 45.29 22.9108 45.29 22.7909C45.29 22.6711 45.1929 22.574 45.073 22.574Z" fill="#FDE5D8"/>
<path d="M45.073 24.9604H44.2052C44.0854 24.9604 43.9883 25.0576 43.9883 25.1774C43.9883 25.2972 44.0854 25.3944 44.2052 25.3944H45.073C45.1929 25.3944 45.29 25.2972 45.29 25.1774C45.29 25.0576 45.1929 24.9604 45.073 24.9604Z" fill="#FDE5D8"/>
<path d="M50.0631 24.7435H47.6766C47.4369 24.7435 47.2427 24.9378 47.2427 25.1774C47.2427 25.4171 47.4369 25.6114 47.6766 25.6114H50.0631C50.3028 25.6114 50.4971 25.4171 50.4971 25.1774C50.4971 24.9378 50.3028 24.7435 50.0631 24.7435Z" fill="#EEEEEE"/>
<path d="M59.3922 22.3569H57.0057C56.766 22.3569 56.5718 22.5512 56.5718 22.7909C56.5718 23.0305 56.766 23.2248 57.0057 23.2248H59.3922C59.6319 23.2248 59.8262 23.0305 59.8262 22.7909C59.8262 22.5512 59.6319 22.3569 59.3922 22.3569Z" fill="#EEEEEE"/>
<path opacity="0.5" d="M55.2702 29.5166H52.8836C52.644 29.5166 52.4497 29.7109 52.4497 29.9505C52.4497 30.1902 52.644 30.3844 52.8836 30.3844H55.2702C55.5098 30.3844 55.7041 30.1902 55.7041 29.9505C55.7041 29.7109 55.5098 29.5166 55.2702 29.5166Z" fill="#6B4FBB"/>
<path d="M53.1007 27.1301H50.7142C50.4745 27.1301 50.2803 27.3244 50.2803 27.564C50.2803 27.8037 50.4745 27.998 50.7142 27.998H53.1007C53.3404 27.998 53.5347 27.8037 53.5347 27.564C53.5347 27.3244 53.3404 27.1301 53.1007 27.1301Z" fill="#6B4FBB"/>
<path d="M58.3076 24.7435H54.8363C54.5966 24.7435 54.4023 24.9378 54.4023 25.1774C54.4023 25.4171 54.5966 25.6114 54.8363 25.6114H58.3076C58.5473 25.6114 58.7415 25.4171 58.7415 25.1774C58.7415 24.9378 58.5473 24.7435 58.3076 24.7435Z" fill="#6B4FBB"/>
<path d="M51.1479 29.5166H47.6766C47.4369 29.5166 47.2427 29.7109 47.2427 29.9505C47.2427 30.1902 47.4369 30.3844 47.6766 30.3844H51.1479C51.3876 30.3844 51.5819 30.1902 51.5819 29.9505C51.5819 29.7109 51.3876 29.5166 51.1479 29.5166Z" fill="#EEEEEE"/>
<path d="M53.1004 24.7435H51.7987C51.559 24.7435 51.3647 24.9378 51.3647 25.1774C51.3647 25.4171 51.559 25.6114 51.7987 25.6114H53.1004C53.3401 25.6114 53.5343 25.4171 53.5343 25.1774C53.5343 24.9378 53.3401 24.7435 53.1004 24.7435Z" fill="#EEEEEE"/>
<path d="M48.9783 27.1301H47.6766C47.4369 27.1301 47.2427 27.3244 47.2427 27.564C47.2427 27.8037 47.4369 27.998 47.6766 27.998H48.9783C49.218 27.998 49.4123 27.8037 49.4123 27.564C49.4123 27.3244 49.218 27.1301 48.9783 27.1301Z" fill="#EEEEEE"/>
<path d="M56.138 27.1301H54.8363C54.5966 27.1301 54.4023 27.3244 54.4023 27.564C54.4023 27.8037 54.5966 27.998 54.8363 27.998H56.138C56.3777 27.998 56.5719 27.8037 56.5719 27.564C56.5719 27.3244 56.3777 27.1301 56.138 27.1301Z" fill="#EEEEEE"/>
<path d="M59.1756 27.1301H57.8739C57.6342 27.1301 57.4399 27.3244 57.4399 27.564C57.4399 27.8037 57.6342 27.998 57.8739 27.998H59.1756C59.4153 27.998 59.6095 27.8037 59.6095 27.564C59.6095 27.3244 59.4153 27.1301 59.1756 27.1301Z" fill="#EEEEEE"/>
<path d="M62.43 22.3569H61.1283C60.8886 22.3569 60.6943 22.5512 60.6943 22.7909C60.6943 23.0305 60.8886 23.2248 61.1283 23.2248H62.43C62.6697 23.2248 62.8639 23.0305 62.8639 22.7909C62.8639 22.5512 62.6697 22.3569 62.43 22.3569Z" fill="#EEEEEE"/>
<path d="M45.073 27.347H44.2052C44.0854 27.347 43.9883 27.4442 43.9883 27.564C43.9883 27.6838 44.0854 27.781 44.2052 27.781H45.073C45.1929 27.781 45.29 27.6838 45.29 27.564C45.29 27.4442 45.1929 27.347 45.073 27.347Z" fill="#FDE5D8"/>
<path d="M45.073 29.7335H44.2052C44.0854 29.7335 43.9883 29.8307 43.9883 29.9505C43.9883 30.0703 44.0854 30.1674 44.2052 30.1674H45.073C45.1929 30.1674 45.29 30.0703 45.29 29.9505C45.29 29.8307 45.1929 29.7335 45.073 29.7335Z" fill="#FDE5D8"/>
<path d="M45.073 32.1201H44.2052C44.0854 32.1201 43.9883 32.2173 43.9883 32.3371C43.9883 32.4569 44.0854 32.554 44.2052 32.554H45.073C45.1929 32.554 45.29 32.4569 45.29 32.3371C45.29 32.2173 45.1929 32.1201 45.073 32.1201Z" fill="#FDE5D8"/>
<path d="M50.0631 31.9032H47.6766C47.4369 31.9032 47.2427 32.0975 47.2427 32.3371C47.2427 32.5768 47.4369 32.771 47.6766 32.771H50.0631C50.3028 32.771 50.4971 32.5768 50.4971 32.3371C50.4971 32.0975 50.3028 31.9032 50.0631 31.9032Z" fill="#6B4FBB"/>
<path d="M55.2702 36.6763H52.8836C52.644 36.6763 52.4497 36.8705 52.4497 37.1102C52.4497 37.3498 52.644 37.5441 52.8836 37.5441H55.2702C55.5098 37.5441 55.7041 37.3498 55.7041 37.1102C55.7041 36.8705 55.5098 36.6763 55.2702 36.6763Z" fill="#EEEEEE"/>
<path opacity="0.5" d="M58.3078 34.2897H55.9212C55.6816 34.2897 55.4873 34.4839 55.4873 34.7236C55.4873 34.9632 55.6816 35.1575 55.9212 35.1575H58.3078C58.5474 35.1575 58.7417 34.9632 58.7417 34.7236C58.7417 34.4839 58.5474 34.2897 58.3078 34.2897Z" fill="#6B4FBB"/>
<path d="M51.1479 36.6763H47.6766C47.4369 36.6763 47.2427 36.8705 47.2427 37.1102C47.2427 37.3498 47.4369 37.5441 47.6766 37.5441H51.1479C51.3876 37.5441 51.5819 37.3498 51.5819 37.1102C51.5819 36.8705 51.3876 36.6763 51.1479 36.6763Z" fill="#EEEEEE"/>
<path d="M54.1855 34.2897H50.7142C50.4745 34.2897 50.2803 34.4839 50.2803 34.7236C50.2803 34.9632 50.4745 35.1575 50.7142 35.1575H54.1855C54.4252 35.1575 54.6195 34.9632 54.6195 34.7236C54.6195 34.4839 54.4252 34.2897 54.1855 34.2897Z" fill="#6B4FBB"/>
<path d="M53.1004 31.9032H51.7987C51.559 31.9032 51.3647 32.0975 51.3647 32.3371C51.3647 32.5768 51.559 32.771 51.7987 32.771H53.1004C53.3401 32.771 53.5343 32.5768 53.5343 32.3371C53.5343 32.0975 53.3401 31.9032 53.1004 31.9032Z" fill="#EEEEEE"/>
<path d="M61.3451 34.2897H60.0433C59.8036 34.2897 59.6094 34.4839 59.6094 34.7236C59.6094 34.9632 59.8036 35.1575 60.0433 35.1575H61.3451C61.5847 35.1575 61.779 34.9632 61.779 34.7236C61.779 34.4839 61.5847 34.2897 61.3451 34.2897Z" fill="#EEEEEE"/>
<path d="M48.9783 34.2897H47.6766C47.4369 34.2897 47.2427 34.4839 47.2427 34.7236C47.2427 34.9632 47.4369 35.1575 47.6766 35.1575H48.9783C49.218 35.1575 49.4123 34.9632 49.4123 34.7236C49.4123 34.4839 49.218 34.2897 48.9783 34.2897Z" fill="#EEEEEE"/>
<path d="M45.073 34.5067H44.2052C44.0854 34.5067 43.9883 34.6039 43.9883 34.7237C43.9883 34.8435 44.0854 34.9406 44.2052 34.9406H45.073C45.1929 34.9406 45.29 34.8435 45.29 34.7237C45.29 34.6039 45.1929 34.5067 45.073 34.5067Z" fill="#FDE5D8"/>
<path d="M45.073 36.8932H44.2052C44.0854 36.8932 43.9883 36.9903 43.9883 37.1101C43.9883 37.23 44.0854 37.3271 44.2052 37.3271H45.073C45.1929 37.3271 45.29 37.23 45.29 37.1101C45.29 36.9903 45.1929 36.8932 45.073 36.8932Z" fill="#FDE5D8"/>
<path d="M66.0312 11.2921H75.4472C76.6405 11.2921 77.6168 10.3158 77.6168 9.12254V2.83072C77.6168 1.63745 76.6405 0.661133 75.4472 0.661133H65.2502C64.0569 0.661133 63.0806 1.63745 63.0806 2.83072V11.943C63.0806 13.1363 63.7748 13.4617 64.6427 12.5939L66.0312 11.2921Z" fill="white" stroke="#FDE5D8" stroke-width="2"/>
<path d="M72.0845 3.69861H66.4436C66.2639 3.69861 66.1182 3.84431 66.1182 4.02405C66.1182 4.20378 66.2639 4.34949 66.4436 4.34949H72.0845C72.2643 4.34949 72.41 4.20378 72.41 4.02405C72.41 3.84431 72.2643 3.69861 72.0845 3.69861Z" fill="#FDB692"/>
<path d="M74.2541 5.65125H66.4436C66.2639 5.65125 66.1182 5.79695 66.1182 5.97668C66.1182 6.15642 66.2639 6.30212 66.4436 6.30212H74.2541C74.4339 6.30212 74.5796 6.15642 74.5796 5.97668C74.5796 5.79695 74.4339 5.65125 74.2541 5.65125Z" fill="#FDB692"/>
<path d="M72.0845 7.60388H66.4436C66.2639 7.60388 66.1182 7.74959 66.1182 7.92932C66.1182 8.10906 66.2639 8.25476 66.4436 8.25476H72.0845C72.2643 8.25476 72.41 8.10906 72.41 7.92932C72.41 7.74959 72.2643 7.60388 72.0845 7.60388Z" fill="#FDB692"/>
<path d="M64.1655 21.0553C65.9629 21.0553 67.4199 19.5982 67.4199 17.8009C67.4199 16.0035 65.9629 14.5465 64.1655 14.5465C62.3682 14.5465 60.9111 16.0035 60.9111 17.8009C60.9111 19.5982 62.3682 21.0553 64.1655 21.0553Z" fill="#FFF7F4" stroke="#FC6D26"/>
<path d="M62.3867 15.1974C63.0376 16.1303 64.079 16.7161 65.2506 16.7161C65.9665 16.7161 66.6174 16.4991 67.2032 16.1303" stroke="#FC6D26" stroke-width="0.5"/>
<path d="M62.9724 18.6687C63.1521 18.6687 63.2979 18.523 63.2979 18.3433C63.2979 18.1635 63.1521 18.0178 62.9724 18.0178C62.7927 18.0178 62.647 18.1635 62.647 18.3433C62.647 18.523 62.7927 18.6687 62.9724 18.6687Z" fill="#FC6D26"/>
<path d="M65.3591 18.6687C65.5389 18.6687 65.6846 18.523 65.6846 18.3433C65.6846 18.1635 65.5389 18.0178 65.3591 18.0178C65.1794 18.0178 65.0337 18.1635 65.0337 18.3433C65.0337 18.523 65.1794 18.6687 65.3591 18.6687Z" fill="#FC6D26"/>
<path d="M16.0005 39.7137C17.7978 39.7137 19.2549 38.2567 19.2549 36.4593C19.2549 34.662 17.7978 33.205 16.0005 33.205C14.2031 33.205 12.7461 34.662 12.7461 36.4593C12.7461 38.2567 14.2031 39.7137 16.0005 39.7137Z" fill="#F4F1FA" stroke="#6B4FBB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M18.1701 34.5068H18.7559C18.1701 33.5955 17.1721 32.988 16.0005 32.988C14.8289 32.988 13.8309 33.5955 13.2451 34.5068H13.8309L14.3733 33.8559L14.9157 34.5068L15.4581 33.8559L16.0005 34.5068L16.5429 33.8559L17.0853 34.5068L17.6277 33.8559L18.1701 34.5068Z" fill="#6B4FBB"/>
<path d="M14.8074 37.1102C14.9871 37.1102 15.1328 36.9645 15.1328 36.7848C15.1328 36.6051 14.9871 36.4594 14.8074 36.4594C14.6276 36.4594 14.4819 36.6051 14.4819 36.7848C14.4819 36.9645 14.6276 37.1102 14.8074 37.1102Z" fill="#6B4FBB"/>
<path d="M17.1936 37.1102C17.3733 37.1102 17.519 36.9645 17.519 36.7848C17.519 36.6051 17.3733 36.4594 17.1936 36.4594C17.0139 36.4594 16.8682 36.6051 16.8682 36.7848C16.8682 36.9645 17.0139 37.1102 17.1936 37.1102Z" fill="#6B4FBB"/>
<path d="M13.0498 29.7336H3.63382C2.44055 29.7336 1.46423 28.7573 1.46423 27.5641V21.2722C1.46423 20.079 2.44055 19.1027 3.63382 19.1027H13.8309C15.0242 19.1027 16.0005 20.079 16.0005 21.2722V30.3845C16.0005 31.5778 15.3062 31.9032 14.4384 31.0354L13.0498 29.7336Z" fill="white" stroke="#E2DCF2" stroke-width="2"/>
<path opacity="0.5" d="M4.82708 22.1401H10.468C10.6478 22.1401 10.7935 22.2858 10.7935 22.4656C10.7935 22.6453 10.6478 22.791 10.468 22.791H4.82708C4.64735 22.791 4.50164 22.6453 4.50164 22.4656C4.50164 22.2858 4.64735 22.1401 4.82708 22.1401Z" fill="#6B4FBB"/>
<path opacity="0.5" d="M4.82724 24.0928H8.29859C8.47832 24.0928 8.62402 24.2385 8.62402 24.4182C8.62402 24.5979 8.47832 24.7437 8.29859 24.7437H4.82724C4.64751 24.7437 4.50181 24.5979 4.50181 24.4182C4.50181 24.2385 4.64751 24.0928 4.82724 24.0928Z" fill="#6B4FBB"/>
<path opacity="0.5" d="M4.82724 26.0454H8.29859C8.47832 26.0454 8.62402 26.1911 8.62402 26.3708C8.62402 26.5506 8.47832 26.6963 8.29859 26.6963H4.82724C4.64751 26.6963 4.50181 26.5506 4.50181 26.3708C4.50181 26.1911 4.64751 26.0454 4.82724 26.0454Z" fill="#6B4FBB"/>
</g>
<defs>
<clipPath id="clip0">
<rect width="83.5292" height="48.8158" fill="white" transform="translate(-2.44092 0.661133)"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 25 KiB

View file

@ -0,0 +1,38 @@
<svg width="52" height="48" viewBox="0 0 52 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M32.1404 11.789L45.6109 14.1173C47.0988 14.3744 48.0923 15.7653 47.8299 17.2237L44.9797 33.0687C44.7173 34.5272 43.2985 35.5011 41.8106 35.2439L28.34 32.9157C26.8521 32.6585 25.8586 31.2677 26.121 29.8092L28.9712 13.9642C29.2336 12.5057 30.6525 11.5318 32.1404 11.789Z" fill="white"/>
<path d="M31.9504 12.8453C31.0576 12.691 30.2063 13.2754 30.0489 14.1505L27.1986 29.9955C27.0412 30.8705 27.6373 31.705 28.5301 31.8593L42.0006 34.1876C42.8933 34.3419 43.7446 33.7576 43.9021 32.8825L46.7523 17.0375C46.9097 16.1624 46.3136 15.3279 45.4209 15.1736L31.9504 12.8453ZM32.1404 11.789L45.6109 14.1173C47.0988 14.3744 48.0923 15.7653 47.8299 17.2237L44.9797 33.0687C44.7173 34.5272 43.2985 35.5011 41.8106 35.2439L28.34 32.9157C26.8521 32.6585 25.8586 31.2677 26.121 29.8092L28.9712 13.9642C29.2336 12.5057 30.6525 11.5318 32.1404 11.789Z" fill="#E1D8F9"/>
<path d="M39.2265 9.7425L25.6003 8.57392C24.0951 8.44485 22.7683 9.53622 22.6366 11.0116L21.206 27.0398C21.0743 28.5151 22.1877 29.8158 23.6928 29.9449L37.3191 31.1134C38.8242 31.2425 40.1511 30.1511 40.2828 28.6758L41.7133 12.6476C41.845 11.1722 40.7316 9.87157 39.2265 9.7425Z" fill="black" fill-opacity="0.03"/>
<path d="M34.477 47.7322H41.0349C46.4986 47.5866 50.8833 43.2004 50.8833 37.8104C50.8833 32.3306 46.3517 27.8886 40.7614 27.8886C40.4897 27.8886 40.2205 27.8993 39.9544 27.9197C38.6002 24.003 34.8187 21.1847 30.3659 21.1847C28.9201 21.1826 27.4908 21.4853 26.1748 22.0723C24.3556 19.4336 21.2753 17.6986 17.7818 17.6986C12.1915 17.6986 7.65986 22.1406 7.65986 27.6204C7.65986 27.8081 7.66533 27.995 7.67572 28.1803C3.26748 29.253 0 33.1573 0 37.8104C0 43.2902 4.53163 47.7322 10.122 47.7322C10.2106 47.7322 10.2987 47.7311 10.3868 47.729L34.477 47.7322Z" fill="#F4F0FF"/>
<path d="M40.1486 9.42187L26.547 8.27441C25.0446 8.14767 23.718 9.24259 23.5839 10.72L22.1275 26.7704C21.9934 28.2478 23.1027 29.5482 24.6051 29.6749L38.2068 30.8224C39.7092 30.9491 41.0358 29.8542 41.1698 28.3768L42.6262 12.3264C42.7603 10.849 41.651 9.54862 40.1486 9.42187Z" fill="white"/>
<path d="M26.4499 9.34444C25.5485 9.26839 24.7525 9.92534 24.6721 10.8118L23.2156 26.8622C23.1352 27.7486 23.8007 28.5288 24.7022 28.6049L38.3038 29.7523C39.2053 29.8284 40.0013 29.1714 40.0817 28.285L41.5381 12.2346C41.6185 11.3482 40.953 10.5679 40.0516 10.4919L26.4499 9.34444ZM26.547 8.27441L40.1486 9.42187C41.651 9.54862 42.7603 10.849 42.6262 12.3264L41.1698 28.3768C41.0358 29.8542 39.7092 30.9491 38.2068 30.8224L24.6051 29.6749C23.1027 29.5482 21.9934 28.2478 22.1275 26.7704L23.5839 10.72C23.718 9.24259 25.0446 8.14767 26.547 8.27441Z" fill="#E1D8F9"/>
<path d="M28.8145 13.3182L27.7253 13.2263C27.4245 13.2009 27.1589 13.4202 27.1321 13.7161C27.1052 14.012 27.3273 14.2725 27.6281 14.2979L28.7173 14.3898C29.018 14.4152 29.2836 14.1959 29.3105 13.9C29.3373 13.6041 29.1152 13.3436 28.8145 13.3182Z" fill="#FC6D26"/>
<path d="M33.2417 19.0816L32.1525 18.9897C31.8517 18.9643 31.5862 19.1836 31.5593 19.4795C31.5325 19.7755 31.7545 20.0359 32.0553 20.0613L33.1445 20.1533C33.4453 20.1787 33.7109 19.9593 33.7377 19.6634C33.7645 19.3675 33.5425 19.107 33.2417 19.0816Z" fill="#E1DBF1"/>
<path d="M36.5464 22.0571L35.4572 21.9652C35.1564 21.9398 34.8908 22.1591 34.864 22.455C34.8372 22.7509 35.0592 23.0114 35.36 23.0368L36.4492 23.1287C36.75 23.1541 37.0155 22.9348 37.0424 22.6389C37.0692 22.343 36.8472 22.0825 36.5464 22.0571Z" fill="#FEE1D3"/>
<path d="M36.5127 19.3624L35.4235 19.2705C35.1227 19.2451 34.8571 19.4644 34.8303 19.7603C34.8035 20.0562 35.0255 20.3167 35.3263 20.3421L36.4155 20.434C36.7163 20.4594 36.9819 20.2401 37.0087 19.9442C37.0355 19.6483 36.8135 19.3878 36.5127 19.3624Z" fill="#FEF0E8"/>
<path d="M33.1744 13.6912L30.9954 13.5071C30.6946 13.4817 30.4289 13.7012 30.4021 13.9975C30.3752 14.2938 30.5974 14.5545 30.8982 14.58L33.0772 14.764C33.378 14.7895 33.6437 14.5699 33.6705 14.2736C33.6974 13.9774 33.4752 13.7166 33.1744 13.6912Z" fill="#EFEDF8"/>
<path d="M27.8257 21.3098L27.2813 21.2638C26.9806 21.2385 26.7151 21.4576 26.6882 21.7534C26.6614 22.0491 26.8834 22.3094 27.1841 22.3348L27.7286 22.3807C28.0293 22.4061 28.2948 22.1869 28.3216 21.8912C28.3484 21.5955 28.1264 21.3351 27.8257 21.3098Z" fill="#FEF0E8"/>
<path d="M30.5513 21.5437L30.0069 21.4977C29.7062 21.4723 29.4407 21.6915 29.4138 21.9873C29.387 22.283 29.609 22.5433 29.9097 22.5687L30.4541 22.6146C30.7548 22.64 31.0203 22.4208 31.0472 22.1251C31.074 21.8293 30.852 21.569 30.5513 21.5437Z" fill="#FC6D26"/>
<path d="M33.2764 21.7772L32.732 21.7312C32.4313 21.7059 32.1657 21.925 32.1389 22.2208C32.1121 22.5165 32.3341 22.7768 32.6348 22.8022L33.1792 22.8481C33.4799 22.8735 33.7455 22.6543 33.7723 22.3586C33.7991 22.0629 33.5771 21.8025 33.2764 21.7772Z" fill="#E1D8F9"/>
<path d="M29.6651 16.0818L27.4861 15.8977C27.1853 15.8723 26.9196 16.0919 26.8928 16.3881C26.866 16.6844 27.0881 16.9452 27.3889 16.9706L29.5679 17.1547C29.8688 17.1801 30.1344 16.9605 30.1613 16.6643C30.1881 16.368 29.966 16.1072 29.6651 16.0818Z" fill="#E1D8F9"/>
<path d="M37.126 24.7972L34.9471 24.6132C34.6462 24.5877 34.3806 24.8073 34.3537 25.1036C34.3269 25.3998 34.549 25.6606 34.8499 25.686L37.0288 25.8701C37.3297 25.8955 37.5953 25.676 37.6222 25.3797C37.649 25.0834 37.4269 24.8227 37.126 24.7972Z" fill="#6B4FBB"/>
<path d="M37.8406 16.7796L31.8467 16.2719C31.5457 16.2464 31.28 16.4666 31.2531 16.7638C31.2263 17.0609 31.4485 17.3225 31.7494 17.348L37.7434 17.8558C38.0443 17.8812 38.3101 17.661 38.3369 17.3638C38.3638 17.0667 38.1416 16.8051 37.8406 16.7796Z" fill="#C3B8E3"/>
<path d="M33.0379 24.4431L27.0439 23.9353C26.743 23.9098 26.4773 24.1301 26.4504 24.4272C26.4235 24.7244 26.6457 24.986 26.9467 25.0114L32.9407 25.5192C33.2416 25.5447 33.5073 25.3245 33.5342 25.0273C33.5611 24.7301 33.3389 24.4686 33.0379 24.4431Z" fill="#FEE1D3"/>
<path d="M38.0793 14.1112L35.3553 13.881C35.0545 13.8556 34.7888 14.0753 34.7619 14.3717C34.7351 14.6681 34.9572 14.929 35.2581 14.9544L37.982 15.1847C38.2829 15.2101 38.5486 14.9904 38.5754 14.694C38.6023 14.3976 38.3801 14.1367 38.0793 14.1112Z" fill="#E1DBF1"/>
<path d="M29.9723 18.7993L27.2484 18.5691C26.9475 18.5437 26.6818 18.7634 26.655 19.0598C26.6282 19.3562 26.8503 19.6171 27.1512 19.6426L29.8751 19.8728C30.176 19.8982 30.4417 19.6785 30.4685 19.3821C30.4953 19.0857 30.2732 18.8248 29.9723 18.7993Z" fill="#6B4FBB"/>
<path d="M35.2983 48H41.8562C47.3199 47.8544 51.7046 43.4682 51.7046 38.0782C51.7046 32.5984 47.173 28.1564 41.5827 28.1564C41.311 28.1564 41.0418 28.1671 40.7757 28.1875C39.4215 24.2708 35.64 21.4525 31.1871 21.4525C29.7414 21.4504 28.3121 21.7532 26.9961 22.3401C25.1769 19.7014 22.0965 17.9664 18.6031 17.9664C13.0128 17.9664 8.48115 22.4085 8.48115 27.8882C8.48115 28.076 8.48662 28.2629 8.49701 28.4482C4.08877 29.5208 0.821289 33.4252 0.821289 38.0782C0.821289 43.558 5.35292 48 10.9432 48C11.0319 48 11.12 47.999 11.2081 47.9968L35.2983 48Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M35.2976 47.4637H41.8407C47.0193 47.3258 51.1567 43.1667 51.1567 38.0782C51.1567 32.8947 46.87 28.6927 41.5819 28.6927C41.3259 28.6927 41.0712 28.7026 40.8179 28.7222L40.3936 28.7549L40.2568 28.3596C38.9505 24.5818 35.3216 21.9887 31.1864 21.9887C29.8189 21.9868 28.4669 22.2731 27.2222 22.8283L26.8009 23.0163L26.5418 22.6406C24.7718 20.0727 21.8233 18.5027 18.6024 18.5027C13.3143 18.5027 9.02753 22.7047 9.02753 27.8882C9.02753 28.0654 9.03246 28.2422 9.04258 28.4183L9.06775 28.8616L8.62813 28.9686C4.39332 29.9986 1.36768 33.7413 1.36768 38.0782C1.36768 43.2616 5.65446 47.4637 10.9425 47.4637C11.0262 47.4637 11.1099 47.4626 11.2073 47.4604L35.2976 47.4637Z" fill="white"/>
<path d="M41.5827 28.1564C47.1729 28.1564 51.7046 32.5985 51.7046 38.0782C51.7046 43.4542 47.3344 47.854 41.8415 48H35.2983L11.2203 47.9967C11.1169 47.999 11.0296 48 10.9432 48C5.35303 48 0.821289 43.5579 0.821289 38.0782C0.821289 33.5134 3.99981 29.542 8.49703 28.4481C8.48641 28.2631 8.48115 28.0765 8.48115 27.8882C8.48115 22.4086 13.0129 17.9664 18.6031 17.9664C21.9832 17.9664 25.1114 19.6064 26.9958 22.3403C28.3124 21.7532 29.742 21.4504 31.1871 21.4525C35.535 21.4525 39.3871 24.1716 40.7757 28.1874C41.0441 28.1668 41.3131 28.1564 41.5827 28.1564ZM41.8266 46.9276C46.7122 46.7976 50.6104 42.873 50.6104 38.0782C50.6104 33.1909 46.5685 29.229 41.5827 29.229C41.3418 29.229 41.1015 29.2383 40.8615 29.2569L40.4372 29.2896C40.1876 29.3088 39.9566 29.1596 39.8762 28.9272L39.7393 28.5318C38.501 24.9504 35.0651 22.5251 31.1863 22.5251C29.8973 22.5232 28.6228 22.7932 27.4496 23.3165L27.0283 23.5045C26.7852 23.6129 26.4979 23.5336 26.3483 23.3167L26.0892 22.9409C24.4075 20.5012 21.6186 19.0391 18.6031 19.0391C13.6172 19.0391 9.57541 23.001 9.57541 27.8882C9.57541 28.0567 9.58012 28.2233 9.58961 28.3886L9.61478 28.8319C9.62938 29.089 9.45538 29.3201 9.20034 29.3822L8.76063 29.4892C4.75075 30.4645 1.91555 34.007 1.91555 38.0782C1.91555 42.9655 5.95738 46.9274 10.9432 46.9274C11.0209 46.9274 11.1001 46.9264 11.2081 46.9242L35.2984 46.9274L41.8266 46.9276Z" fill="#E1D8F9"/>
<path d="M19.2501 27.9907C19.8019 27.7404 20.3915 27.5821 20.9945 27.5223L21.1208 27.0649C21.3387 26.2755 22.1656 25.8045 22.9613 26.0114L23.7546 26.2177C24.1383 26.3176 24.4646 26.564 24.6618 26.9026C24.8589 27.2412 24.9107 27.6443 24.8057 28.0231L24.6794 28.4806C25.1755 28.8277 25.6031 29.2528 25.9488 29.7327L26.4143 29.6081C27.2149 29.3942 28.0346 29.8574 28.2469 30.6437L28.4563 31.4252C28.5574 31.8033 28.5015 32.2068 28.3009 32.5468C28.1003 32.8869 27.7714 33.1356 27.3867 33.2383L26.9221 33.3629C26.892 33.6548 26.8373 33.9481 26.7564 34.241C26.6755 34.5339 26.5718 34.8144 26.4475 35.0819L26.7857 35.4149C27.3682 35.9895 27.3647 36.9241 26.7779 37.5044L26.1939 38.0796C25.9113 38.3577 25.5291 38.5148 25.1313 38.5162C24.7336 38.5176 24.3529 38.3633 24.0732 38.0871L23.7343 37.7533C23.1824 38.0036 22.5929 38.1619 21.9899 38.2217L21.8636 38.6791C21.6457 39.4685 20.8188 39.9395 20.0231 39.7326L19.2298 39.5263C18.8461 39.4264 18.5198 39.18 18.3226 38.8414C18.1255 38.5028 18.0737 38.0997 18.1787 37.7209L18.3049 37.2634C17.8136 36.919 17.3846 36.4958 17.0356 36.0113L16.5701 36.1359C15.7695 36.3498 14.9498 35.8866 14.7374 35.1003L14.5281 34.3188C14.427 33.9407 14.4829 33.5372 14.6835 33.1972C14.8841 32.8571 15.2129 32.6084 15.5977 32.5057L16.0623 32.3812C16.0929 32.0847 16.1484 31.791 16.228 31.503C16.3089 31.2101 16.4126 30.9296 16.5369 30.6622L16.1986 30.3291C15.6162 29.7545 15.6197 28.8199 16.2065 28.2397L16.7905 27.6645C17.073 27.3863 17.4553 27.2292 17.853 27.2278C18.2508 27.2264 18.6314 27.3807 18.9112 27.6569L19.2501 27.9907Z" fill="white"/>
<path d="M20.9944 27.5222L21.121 27.0643C21.3393 26.2769 22.1613 25.806 22.9613 26.0114L23.7546 26.2177C24.5536 26.4255 25.0238 27.2335 24.8057 28.0232L24.6796 28.4802C25.1712 28.8248 25.6002 29.2481 25.9491 29.7327L26.4148 29.6079C27.2147 29.3945 28.0336 29.8569 28.247 30.6437L28.4564 31.4256C28.5575 31.8038 28.5014 32.2073 28.3006 32.5474C28.0999 32.8874 27.7708 33.136 27.3868 33.2383L26.9221 33.3628C26.8918 33.6578 26.8364 33.9512 26.7564 34.241C26.6764 34.5306 26.5733 34.8113 26.4475 35.0819L26.7861 35.4156C27.3676 35.9897 27.3645 36.9229 26.7779 37.5044L26.1937 38.0798C25.911 38.358 25.5287 38.515 25.1308 38.5163C24.733 38.5175 24.3523 38.363 24.0733 38.0872L23.7342 37.7533C23.1825 38.0036 22.593 38.1619 21.99 38.2218L21.8635 38.6797C21.6451 39.4672 20.8231 39.938 20.0231 39.7326L19.2298 39.5263C18.4308 39.3185 17.9606 38.5106 18.1787 37.7209L18.3049 37.2638C17.8132 36.9192 17.3842 36.496 17.0353 36.0114L16.5696 36.1361C15.7697 36.3495 14.9509 35.8871 14.7374 35.1003L14.528 34.3184C14.4269 33.9403 14.483 33.5367 14.6838 33.1967C14.8846 32.8566 15.2136 32.608 15.5977 32.5057L16.0623 32.3813C16.0926 32.0862 16.148 31.7928 16.2279 31.5033C16.3073 31.2153 16.4106 30.9341 16.537 30.6621L16.1983 30.3284C15.6168 29.7543 15.62 28.8211 16.2065 28.2396L16.7907 27.6643C17.0734 27.3861 17.4558 27.229 17.8536 27.2278C18.2515 27.2265 18.6321 27.3811 18.9111 27.6568L19.2501 27.9906C19.8125 27.7376 20.3968 27.5816 20.9944 27.5222ZM19.3541 29.1231C19.1465 29.2172 18.9024 29.1749 18.742 29.0169L18.1356 28.4197C18.0595 28.3445 17.956 28.3025 17.8477 28.3028C17.7395 28.3032 17.6354 28.3459 17.5587 28.4214L16.976 28.9953C16.8161 29.1539 16.8152 29.4089 16.9737 29.5654L17.5783 30.1611C17.7385 30.3189 17.7816 30.5589 17.6864 30.7633L17.5285 31.1027C17.4273 31.3204 17.3445 31.5458 17.2808 31.7768C17.2166 32.0096 17.1723 32.2446 17.148 32.4805L17.1099 32.8514C17.087 33.0746 16.926 33.2615 16.706 33.3205L15.8747 33.5432C15.77 33.5711 15.6805 33.6387 15.6258 33.7312C15.5712 33.8237 15.556 33.9335 15.5834 34.0361L15.7923 34.816C15.8505 35.0306 16.0743 35.1569 16.2923 35.0987L17.124 34.876C17.3443 34.817 17.5775 34.8987 17.7088 35.0811L17.927 35.3841C18.2062 35.7718 18.5493 36.1104 18.942 36.3857L19.2494 36.6007C19.4343 36.7301 19.5173 36.9598 19.4573 37.1768L19.2315 37.9947C19.1719 38.2106 19.2997 38.4302 19.5168 38.4867L20.3085 38.6926C20.5267 38.7486 20.7513 38.6199 20.8108 38.4054L21.0366 37.5874C21.0965 37.3706 21.2864 37.212 21.5131 37.1895L21.89 37.1522C22.3723 37.1043 22.8438 36.9776 23.2856 36.7771L23.6306 36.6208C23.8382 36.5268 24.082 36.5692 24.2424 36.7271L24.8488 37.3243C24.9249 37.3995 25.0285 37.4416 25.1367 37.4412C25.2449 37.4409 25.349 37.3981 25.4257 37.3226L26.0084 36.7487C26.1683 36.5901 26.1692 36.3351 26.0107 36.1786L25.4061 35.5829C25.2459 35.4251 25.2028 35.1851 25.298 34.9807L25.456 34.6412C25.5567 34.4246 25.6393 34.1998 25.7036 33.9672C25.7678 33.7345 25.8122 33.4995 25.8364 33.2636L25.8745 32.8927C25.8974 32.6695 26.0584 32.4825 26.2784 32.4236L27.1097 32.2009C27.2144 32.173 27.3039 32.1053 27.3586 32.0128C27.4132 31.9203 27.4284 31.8105 27.401 31.708L27.1921 30.928C27.1339 30.7135 26.9101 30.5871 26.6921 30.6453L25.8604 30.868C25.6401 30.9271 25.4069 30.8453 25.2756 30.663L25.0574 30.3599C24.7783 29.9722 24.4351 29.6336 24.0427 29.3586L23.7353 29.1438C23.5501 29.0145 23.4671 28.7847 23.527 28.5675L23.7529 27.7494C23.8125 27.5334 23.6847 27.3138 23.4676 27.2573L22.6759 27.0514C22.4578 26.9954 22.2332 27.1241 22.1736 27.3387L21.9478 28.1566C21.8879 28.3735 21.698 28.5321 21.4713 28.5545L21.0944 28.5918C20.6121 28.6397 20.1406 28.7665 19.6992 28.9668C19.696 28.9682 19.5809 29.0203 19.3541 29.1231Z" fill="#7B58CF"/>
<path d="M19.4256 36.6322C20.4661 37.2185 21.8046 36.8571 22.4152 35.825C23.0258 34.7929 22.6774 33.4808 21.6369 32.8945C20.5964 32.3082 19.2579 32.6696 18.6473 33.7017C18.0367 34.7339 18.3851 36.0459 19.4256 36.6322Z" fill="white"/>
<path d="M20.2669 34.8677C19.2265 34.2814 18.878 32.9693 19.4886 31.9372C20.0992 30.9051 21.4377 30.5437 22.4782 31.13C23.5187 31.7163 23.8671 33.0283 23.2565 34.0605C22.6459 35.0926 21.3074 35.454 20.2669 34.8677ZM20.8198 33.9333C21.34 34.2264 22.0092 34.0457 22.3145 33.5297C22.6199 33.0136 22.4456 32.3576 21.9254 32.0644C21.4051 31.7713 20.7359 31.952 20.4306 32.468C20.1253 32.9841 20.2995 33.6401 20.8198 33.9333Z" fill="#6B4FBB"/>
<path d="M30.889 35.0709C31.3313 34.8678 31.8035 34.7389 32.2863 34.6895L32.3883 34.3201C32.5643 33.6826 33.2272 33.3008 33.8637 33.4663L34.4983 33.6313C34.8053 33.7113 35.066 33.9096 35.2232 34.1825C35.3803 34.4555 35.421 34.7807 35.3362 35.0867L35.2342 35.4561C35.6306 35.7354 35.972 36.0777 36.2478 36.4644L36.6207 36.3629C37.262 36.1888 37.9173 36.5612 38.0857 37.1955L38.2517 37.8259C38.3319 38.1309 38.2864 38.4566 38.1251 38.7315C37.9638 39.0063 37.7001 39.2077 37.3919 39.2913L37.0198 39.3927C36.9951 39.6284 36.9507 39.8652 36.8854 40.1018C36.82 40.3384 36.7365 40.565 36.6364 40.7811L36.9065 41.0493C37.3717 41.512 37.367 42.2664 36.8961 42.7358L36.4275 43.2012C36.2007 43.4262 35.8945 43.5537 35.5761 43.5556C35.2577 43.5575 34.9532 43.4336 34.7299 43.2112L34.4592 42.9424C34.017 43.1455 33.5447 43.2744 33.0619 43.3238L32.9599 43.6932C32.7839 44.3307 32.1211 44.7125 31.4845 44.547L30.8499 44.3819C30.543 44.302 30.2822 44.1037 30.1251 43.8308C29.9679 43.5578 29.9273 43.2326 30.0121 42.9266L30.1141 42.5572C29.7214 42.2801 29.3788 41.9393 29.1004 41.5488L28.7276 41.6503C28.0863 41.8245 27.431 41.4521 27.2626 40.8178L27.0965 40.1874C27.0163 39.8824 27.0619 39.5566 27.2231 39.2818C27.3844 39.007 27.6481 38.8056 27.9563 38.722L28.3285 38.6206C28.3536 38.3812 28.3986 38.144 28.4629 37.9115C28.5282 37.6749 28.6118 37.4483 28.7118 37.2322L28.4417 36.964C27.9766 36.5013 27.9813 35.7469 28.4522 35.2775L28.9207 34.8121C29.1475 34.5871 29.4538 34.4595 29.7722 34.4577C30.0906 34.4558 30.395 34.5797 30.6184 34.802L30.889 35.0709Z" fill="white"/>
<path d="M32.1998 34.5947L32.2833 34.2923C32.4746 33.6024 33.1919 33.1869 33.8914 33.3665L34.526 33.5315C35.2246 33.7132 35.6326 34.4223 35.4416 35.1142L35.3583 35.4159C35.7153 35.6768 36.0302 35.9898 36.2925 36.3444L36.5904 36.2633C37.2909 36.0733 38.0069 36.4799 38.1913 37.1715L38.3575 37.8023C38.4444 38.133 38.3949 38.4857 38.2201 38.7834C38.045 39.0816 37.7581 39.3004 37.423 39.3911L37.1204 39.4735C37.0938 39.6938 37.0505 39.9128 36.9908 40.1294C36.931 40.3458 36.8557 40.5563 36.7651 40.7602L36.9851 40.9788C37.4903 41.4818 37.4856 42.298 36.9752 42.8081L36.5064 43.2737C36.2596 43.5186 35.9255 43.6575 35.5775 43.6595C35.2288 43.6614 34.8954 43.5256 34.6519 43.2828L34.4357 43.0682C34.026 43.2479 33.5922 43.3661 33.1486 43.4189L33.0651 43.7214C32.8738 44.4113 32.1565 44.8267 31.457 44.6472L30.8224 44.4821C30.1238 44.3005 29.7158 43.5913 29.9068 42.8994L29.9901 42.5978C29.6331 42.3368 29.3182 42.0238 29.0559 41.6693L28.758 41.7504C28.0575 41.9403 27.3415 41.5338 27.1571 40.8421L26.9909 40.2114C26.9041 39.8807 26.9535 39.5279 27.1283 39.2303C27.3034 38.9321 27.5903 38.7132 27.9254 38.6225L28.228 38.5401C28.2546 38.3199 28.2979 38.1009 28.3576 37.8845C28.417 37.6691 28.4924 37.4583 28.5833 37.2535L28.3633 37.0348C27.8581 36.5319 27.8628 35.7157 28.3732 35.2055L28.842 34.74C29.0888 34.4951 29.4229 34.3561 29.7709 34.3542C30.1196 34.3522 30.453 34.4881 30.6965 34.7308L30.9127 34.9455C31.3224 34.7658 31.7562 34.6475 32.1998 34.5947ZM31.0182 36.0782C30.8094 36.1741 30.5632 36.1315 30.4022 35.9716L29.9178 35.4906C29.878 35.4508 29.8241 35.4289 29.7676 35.4292C29.7105 35.4295 29.6548 35.4527 29.6133 35.4939L29.1459 35.958C29.057 36.0469 29.0562 36.1897 29.1419 36.275L29.6246 36.7547C29.7833 36.9124 29.8259 37.151 29.7315 37.3546L29.6044 37.6287C29.5253 37.7997 29.4605 37.9767 29.4105 38.1581C29.36 38.3408 29.3251 38.5252 29.3058 38.7103L29.2745 39.0097C29.2514 39.2318 29.0916 39.4178 28.8729 39.4774L28.2068 39.6588C28.1506 39.674 28.1018 39.7112 28.0716 39.7626C28.0411 39.8146 28.0325 39.8763 28.0474 39.9333L28.2131 40.5621C28.2441 40.6786 28.3616 40.7453 28.4764 40.7142L29.1425 40.5328C29.3644 40.4725 29.5996 40.555 29.731 40.7394L29.9051 40.9836C30.1208 41.2862 30.3862 41.5502 30.6899 41.7646L30.9355 41.9376C31.1195 42.0672 31.2018 42.2962 31.142 42.5126L30.9597 43.1732C30.9264 43.2936 30.995 43.4128 31.1094 43.4425L31.7424 43.6071C31.8578 43.6367 31.9794 43.5663 32.0125 43.447L32.1949 42.7864C32.2546 42.5701 32.4437 42.4117 32.6697 42.3887L32.9714 42.3578C33.3452 42.3195 33.711 42.2196 34.054 42.0621L34.3305 41.9353C34.5392 41.8396 34.7853 41.8823 34.9462 42.0421L35.4306 42.5231C35.4704 42.5628 35.5243 42.5848 35.5808 42.5845C35.6379 42.5841 35.6936 42.561 35.7352 42.5197L36.2025 42.0556C36.2914 41.9668 36.2922 41.8239 36.2065 41.7387L35.7238 41.259C35.5651 41.1013 35.5225 40.8626 35.6169 40.6591L35.7441 40.3847C35.8228 40.2147 35.8875 40.0382 35.9379 39.8556C35.9884 39.6728 36.0233 39.4884 36.0427 39.3034L36.0739 39.0039C36.097 38.7819 36.2568 38.5958 36.4755 38.5363L37.1416 38.3549C37.1978 38.3397 37.2466 38.3025 37.2768 38.2511C37.3073 38.1991 37.3159 38.1373 37.301 38.0803L37.1353 37.4515C37.1043 37.335 36.9868 37.2683 36.872 37.2995L36.2059 37.4808C35.9841 37.5412 35.7488 37.4586 35.6174 37.2743L35.4433 37.0301C35.2276 36.7274 34.9622 36.4634 34.6588 36.2493L34.4132 36.0765C34.2289 35.947 34.1465 35.7178 34.2063 35.5012L34.3888 34.8404C34.422 34.7201 34.3534 34.6009 34.239 34.5711L33.606 34.4065C33.4907 34.3769 33.369 34.4473 33.3359 34.5666L33.1535 35.2272C33.0938 35.4435 32.9047 35.6019 32.6788 35.625L32.377 35.6558C32.0032 35.6941 31.6374 35.794 31.2948 35.9514C31.2919 35.9528 31.1997 35.995 31.0182 36.0782Z" fill="#FC6D26"/>
<path d="M31.0067 42.0443C31.839 42.5134 32.9136 42.2178 33.4068 41.3841C33.9 40.5504 33.6251 39.4944 32.7928 39.0253C31.9604 38.5563 30.8858 38.8519 30.3926 39.6855C29.8994 40.5192 30.1743 41.5753 31.0067 42.0443Z" fill="white"/>
<path d="M31.6893 40.6162C30.8561 40.1466 30.5815 39.0919 31.073 38.2611C31.5645 37.4302 32.6378 37.135 33.471 37.6045C34.3042 38.074 34.5788 39.1288 34.0873 39.9596C33.5957 40.7905 32.5225 41.0857 31.6893 40.6162ZM32.1315 39.8686C32.5469 40.1027 33.0855 39.9546 33.3337 39.535C33.5819 39.1154 33.4441 38.5861 33.0288 38.3521C32.6134 38.118 32.0748 38.2661 31.8266 38.6857C31.5783 39.1053 31.7162 39.6346 32.1315 39.8686Z" fill="#FC6D26"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.8736 10.2573C16.9313 9.88553 16.9613 9.50478 16.9613 9.11717C16.9613 4.97039 13.5319 1.60876 9.30146 1.60876C5.07104 1.60876 1.6416 4.97039 1.6416 9.11717C1.6416 13.2639 5.07104 16.6256 9.30146 16.6256C11.7125 16.6256 13.8633 15.5337 15.2674 13.8269L17.582 13.5753C17.637 13.5693 17.6908 13.5552 17.7414 13.5334C18.0182 13.4145 18.1442 13.0982 18.0228 12.8269L16.8736 10.2573Z" fill="#F4F0FF"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.42 9.18492C17.4777 8.81314 17.5077 8.43239 17.5077 8.04478C17.5077 3.898 14.0783 0.536377 9.84784 0.536377C5.61742 0.536377 2.18799 3.898 2.18799 8.04478C2.18799 12.1916 5.61742 15.5532 9.84784 15.5532C12.2588 15.5532 14.4097 14.4613 15.8138 12.7545L18.1284 12.5029C18.1834 12.4969 18.2371 12.4828 18.2878 12.461C18.5646 12.3421 18.6905 12.0258 18.5692 11.7545L17.42 9.18492Z" fill="white"/>
<path d="M19.0711 11.5391C19.3137 12.0817 19.0617 12.7143 18.5082 12.9522C18.4069 12.9957 18.2994 13.0239 18.1895 13.0359L16.0945 13.2636C14.5478 15.0412 12.2855 16.0894 9.84859 16.0894C5.31599 16.0894 1.6416 12.4877 1.6416 8.04471C1.6416 3.60174 5.31599 0 9.84859 0C14.3812 0 18.0556 3.60174 18.0556 8.04471C18.0556 8.40289 18.0317 8.75827 17.9843 9.10926L19.0711 11.5391ZM16.8798 9.10409C16.9339 8.75583 16.9613 8.40206 16.9613 8.04471C16.9613 4.19414 13.7768 1.07263 9.84859 1.07263C5.92034 1.07263 2.73587 4.19414 2.73587 8.04471C2.73587 11.8953 5.92034 15.0168 9.84859 15.0168C12.0288 15.0168 14.0459 14.0499 15.3886 12.4178L15.5301 12.2457L18.0689 11.9698L16.9196 9.4002L16.8559 9.2578L16.8798 9.10409Z" fill="#E1D8F9"/>
<path d="M9.98471 11.9331C7.8695 11.9331 6.15479 10.2523 6.15479 8.17888C6.15479 6.1055 7.8695 4.42468 9.98471 4.42468C12.0999 4.42468 13.8146 6.1055 13.8146 8.17888C13.8146 10.2523 12.0999 11.9331 9.98471 11.9331ZM9.98471 11.1286C11.6467 11.1286 12.9939 9.80798 12.9939 8.17888C12.9939 6.54979 11.6467 5.22915 9.98471 5.22915C8.32276 5.22915 6.97548 6.54979 6.97548 8.17888C6.97548 9.80798 8.32276 11.1286 9.98471 11.1286Z" fill="#31AF64"/>
<path d="M9.62376 8.52988L9.09523 8.0118C8.93843 7.85825 8.68438 7.85825 8.52758 8.0118C8.4521 8.08542 8.40967 8.1855 8.40967 8.28987C8.40967 8.39425 8.4521 8.49433 8.52758 8.56795L9.31408 9.33864C9.31836 9.34303 9.32274 9.34732 9.32721 9.35151C9.47767 9.499 9.71841 9.49873 9.86751 9.35285L11.4564 7.79539C11.5279 7.725 11.5679 7.62964 11.5677 7.53031C11.5674 7.43098 11.5269 7.33582 11.455 7.26578C11.3837 7.19514 11.2866 7.15528 11.1851 7.15503C11.0837 7.15478 10.9864 7.19415 10.9147 7.26444L9.62376 8.52988Z" fill="#31AF64"/>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

View file

@ -0,0 +1,70 @@
<svg width="80" height="56" viewBox="0 0 80 56" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11.1567 40.6485C16.4079 40.6485 20.6649 36.3891 20.6649 31.135C20.6649 25.8808 16.4079 21.6215 11.1567 21.6215C5.9055 21.6215 1.64856 25.8808 1.64856 31.135C1.64856 36.3891 5.9055 40.6485 11.1567 40.6485Z" fill="#F9F9F9"/>
<path d="M19.0163 30.4864C19.0163 35.1888 15.2065 38.9999 10.5081 38.9999C5.80976 38.9999 2 35.1888 2 30.4864C2 25.784 5.80976 21.9729 10.5081 21.9729C15.2065 21.9729 19.0163 25.784 19.0163 30.4864Z" fill="white" stroke="#EEEEEE" stroke-width="2"/>
<path d="M10.5075 39.5674C15.52 39.5674 19.5834 35.5017 19.5834 30.4863C19.5834 25.471 15.52 21.4053 10.5075 21.4053C5.49496 21.4053 1.43152 25.471 1.43152 30.4863C1.43152 35.5017 5.49496 39.5674 10.5075 39.5674Z" stroke="#EEEEEE"/>
<path d="M8.43196 33.0239C8.57802 32.9204 8.75259 32.8648 8.93158 32.8648H13.1009C13.817 32.8648 14.3975 32.284 14.3975 31.5675V28.5405C14.3975 27.824 13.817 27.2432 13.1009 27.2432H8.34686C7.63078 27.2432 7.05029 27.824 7.05029 28.5405V34.0031L8.43196 33.0239ZM8.93158 33.7296L7.20891 34.9505C7.09937 35.0282 6.96844 35.0699 6.8342 35.0699C6.47616 35.0699 6.18591 34.7795 6.18591 34.4212V28.5405C6.18591 27.3463 7.1534 26.3783 8.34686 26.3783H13.1009C14.2944 26.3783 15.2619 27.3463 15.2619 28.5405V31.5675C15.2619 32.7616 14.2944 33.7296 13.1009 33.7296H8.93158Z" fill="#FEE1D3"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.21191 29.6217C9.4506 29.6217 9.6441 29.8153 9.6441 30.0541C9.6441 30.293 9.4506 30.4866 9.21191 30.4866C8.97322 30.4866 8.77972 30.293 8.77972 30.0541C8.77972 29.8153 8.97322 29.6217 9.21191 29.6217ZM10.7246 29.6217C10.9633 29.6217 11.1568 29.8153 11.1568 30.0541C11.1568 30.293 10.9633 30.4866 10.7246 30.4866C10.4859 30.4866 10.2924 30.293 10.2924 30.0541C10.2924 29.8153 10.4859 29.6217 10.7246 29.6217ZM12.2372 29.6217C12.4759 29.6217 12.6694 29.8153 12.6694 30.0541C12.6694 30.293 12.4759 30.4866 12.2372 30.4866C11.9985 30.4866 11.805 30.293 11.805 30.0541C11.805 29.8153 11.9985 29.6217 12.2372 29.6217Z" fill="#FC6D26"/>
<path d="M18.0716 14.0539C21.7713 14.0539 24.7705 11.0531 24.7705 7.35125C24.7705 3.64946 21.7713 0.64856 18.0716 0.64856C14.3719 0.64856 11.3727 3.64946 11.3727 7.35125C11.3727 11.0531 14.3719 14.0539 18.0716 14.0539Z" fill="#F9F9F9"/>
<path d="M17.423 13.4054C21.1228 13.4054 24.122 10.4045 24.122 6.70269C24.122 3.0009 21.1228 0 17.423 0C13.7233 0 10.7241 3.0009 10.7241 6.70269C10.7241 10.4045 13.7233 13.4054 17.423 13.4054Z" fill="white"/>
<path d="M19.1525 6.27026H15.6949C15.4563 6.27026 15.2628 6.46387 15.2628 6.7027C15.2628 6.94152 15.4563 7.13513 15.6949 7.13513H19.1525C19.3911 7.13513 19.5846 6.94152 19.5846 6.7027C19.5846 6.46387 19.3911 6.27026 19.1525 6.27026Z" fill="#6B4FBB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M49.7467 48.0001H20.8808C19.4486 48.0001 18.2877 46.8384 18.2877 45.4055V12.5406C18.2877 11.1077 19.4486 9.94604 20.8808 9.94604H65.3962C66.8284 9.94604 67.9893 11.1077 67.9893 12.5406V16.5187C69.077 15.9128 70.3297 15.5677 71.6629 15.5677C75.84 15.5677 79.2262 18.9558 79.2262 23.1352C79.2262 27.3147 75.84 30.7028 71.6629 30.7028C70.3297 30.7028 69.077 30.3576 67.9893 29.7517V45.4055C67.9893 46.8384 66.8284 48.0001 65.3962 48.0001H62.8938C62.9761 48.4198 63.0192 48.8535 63.0192 49.2974C63.0192 52.9991 60.02 56 56.3202 56C52.6205 56 49.6213 52.9991 49.6213 49.2974C49.6213 48.8535 49.6644 48.4198 49.7467 48.0001Z" fill="#F9F9F9"/>
<path d="M71.0139 30.0543C75.191 30.0543 78.5772 26.6662 78.5772 22.4868C78.5772 18.3073 75.191 14.9192 71.0139 14.9192C66.8368 14.9192 63.4506 18.3073 63.4506 22.4868C63.4506 26.6662 66.8368 30.0543 71.0139 30.0543Z" fill="white"/>
<path d="M71.0148 29.6218C74.9532 29.6218 78.1459 26.4273 78.1459 22.4867C78.1459 18.5461 74.9532 15.3516 71.0148 15.3516C67.0764 15.3516 63.8837 18.5461 63.8837 22.4867C63.8837 26.4273 67.0764 29.6218 71.0148 29.6218Z" stroke="#EEEEEE" stroke-width="2"/>
<path d="M71.014 25.7303C72.8042 25.7303 74.2554 24.2782 74.2554 22.487C74.2554 20.6958 72.8042 19.2438 71.014 19.2438C69.2238 19.2438 67.7726 20.6958 67.7726 22.487C67.7726 24.2782 69.2238 25.7303 71.014 25.7303Z" fill="#F4F1FA" stroke="#6B4FBB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M71.9682 20.5401L71.9667 20.5401L71.4366 19.8925L70.9063 20.5404L70.9051 20.5404L70.3748 19.8925L69.8443 20.5407L69.8436 20.5407L69.3131 19.8925L68.7823 20.541L68.2041 20.5411C68.7671 19.6321 69.7666 19.0276 70.9057 19.0276C72.0443 19.0276 73.0433 19.6315 73.6065 20.5397L73.0282 20.5399L72.4983 19.8925L71.9682 20.5401Z" fill="#6B4FBB"/>
<path d="M69.8258 23.1357C70.0048 23.1357 70.1499 22.9905 70.1499 22.8114C70.1499 22.6323 70.0048 22.4871 69.8258 22.4871C69.6468 22.4871 69.5016 22.6323 69.5016 22.8114C69.5016 22.9905 69.6468 23.1357 69.8258 23.1357Z" fill="#6B4FBB"/>
<path d="M72.2021 23.1357C72.3811 23.1357 72.5263 22.9905 72.5263 22.8114C72.5263 22.6323 72.3811 22.4871 72.2021 22.4871C72.0231 22.4871 71.878 22.6323 71.878 22.8114C71.878 22.9905 72.0231 23.1357 72.2021 23.1357Z" fill="#6B4FBB"/>
<path d="M65.1797 9.29712H19.7999C18.6064 9.29712 17.6389 10.2652 17.6389 11.4593V45.189C17.6389 46.3831 18.6064 47.3511 19.7999 47.3511H65.1797C66.3731 47.3511 67.3406 46.3831 67.3406 45.189V11.4593C67.3406 10.2652 66.3731 9.29712 65.1797 9.29712Z" fill="white"/>
<path d="M64.7466 9.72986H20.2311C19.0377 9.72986 18.0702 10.6979 18.0702 11.892V44.7568C18.0702 45.951 19.0377 46.919 20.2311 46.919H64.7466C65.94 46.919 66.9075 45.951 66.9075 44.7568V11.892C66.9075 10.6979 65.94 9.72986 64.7466 9.72986Z" stroke="#EEEEEE" stroke-width="2"/>
<path d="M25.6338 18.8108C25.6338 18.572 25.4403 18.3784 25.2016 18.3784C24.9629 18.3784 24.7694 18.572 24.7694 18.8108V44.3243C24.7694 44.5632 24.9629 44.7568 25.2016 44.7568C25.4403 44.7568 25.6338 44.5632 25.6338 44.3243V18.8108Z" fill="#EEEEEE"/>
<path d="M22.177 22.0541H20.8804C20.6417 22.0541 20.4482 22.2477 20.4482 22.4865C20.4482 22.7253 20.6417 22.9189 20.8804 22.9189H22.177C22.4157 22.9189 22.6092 22.7253 22.6092 22.4865C22.6092 22.2477 22.4157 22.0541 22.177 22.0541Z" fill="#FEE1D3"/>
<path d="M22.177 24.6486H20.8804C20.6417 24.6486 20.4482 24.8422 20.4482 25.081C20.4482 25.3198 20.6417 25.5134 20.8804 25.5134H22.177C22.4157 25.5134 22.6092 25.3198 22.6092 25.081C22.6092 24.8422 22.4157 24.6486 22.177 24.6486Z" fill="#F0EDF8"/>
<path d="M22.177 27.2432H20.8804C20.6417 27.2432 20.4482 27.4368 20.4482 27.6756C20.4482 27.9144 20.6417 28.108 20.8804 28.108H22.177C22.4157 28.108 22.6092 27.9144 22.6092 27.6756C22.6092 27.4368 22.4157 27.2432 22.177 27.2432Z" fill="#FEF0E9"/>
<path d="M22.177 29.8379H20.8804C20.6417 29.8379 20.4482 30.0315 20.4482 30.2703C20.4482 30.5091 20.6417 30.7028 20.8804 30.7028H22.177C22.4157 30.7028 22.6092 30.5091 22.6092 30.2703C22.6092 30.0315 22.4157 29.8379 22.177 29.8379Z" fill="#FEE1D3"/>
<path d="M22.177 32.4324H20.8804C20.6417 32.4324 20.4482 32.626 20.4482 32.8648C20.4482 33.1036 20.6417 33.2972 20.8804 33.2972H22.177C22.4157 33.2972 22.6092 33.1036 22.6092 32.8648C22.6092 32.626 22.4157 32.4324 22.177 32.4324Z" fill="#E1DBF1"/>
<path d="M22.177 35.027H20.8804C20.6417 35.027 20.4482 35.2206 20.4482 35.4594C20.4482 35.6982 20.6417 35.8918 20.8804 35.8918H22.177C22.4157 35.8918 22.6092 35.6982 22.6092 35.4594C22.6092 35.2206 22.4157 35.027 22.177 35.027Z" fill="#F0EDF8"/>
<path d="M22.177 37.6216H20.8804C20.6417 37.6216 20.4482 37.8152 20.4482 38.054C20.4482 38.2928 20.6417 38.4864 20.8804 38.4864H22.177C22.4157 38.4864 22.6092 38.2928 22.6092 38.054C22.6092 37.8152 22.4157 37.6216 22.177 37.6216Z" fill="#FEF0E9"/>
<path d="M22.177 40.2161H20.8804C20.6417 40.2161 20.4482 40.4097 20.4482 40.6485C20.4482 40.8873 20.6417 41.0809 20.8804 41.0809H22.177C22.4157 41.0809 22.6092 40.8873 22.6092 40.6485C22.6092 40.4097 22.4157 40.2161 22.177 40.2161Z" fill="#FEE1D3"/>
<path d="M32.1164 22.0538H29.9555C29.7168 22.0538 29.5233 22.2474 29.5233 22.4863C29.5233 22.7251 29.7168 22.9187 29.9555 22.9187H32.1164C32.3551 22.9187 32.5486 22.7251 32.5486 22.4863C32.5486 22.2474 32.3551 22.0538 32.1164 22.0538Z" fill="#6B4FBB"/>
<path d="M36.439 22.0537H34.278C34.0393 22.0537 33.8458 22.2473 33.8458 22.4861C33.8458 22.725 34.0393 22.9186 34.278 22.9186H36.439C36.6776 22.9186 36.8711 22.725 36.8711 22.4861C36.8711 22.2473 36.6776 22.0537 36.439 22.0537Z" fill="#F0EDF8"/>
<path d="M40.7601 22.0537H38.5992C38.3605 22.0537 38.167 22.2473 38.167 22.4861C38.167 22.725 38.3605 22.9186 38.5992 22.9186H40.7601C40.9988 22.9186 41.1923 22.725 41.1923 22.4861C41.1923 22.2473 40.9988 22.0537 40.7601 22.0537Z" fill="#FEF0E9"/>
<path d="M32.1161 24.6484H29.9551C29.7164 24.6484 29.5229 24.842 29.5229 25.0809C29.5229 25.3197 29.7164 25.5133 29.9551 25.5133H32.1161C32.3548 25.5133 32.5483 25.3197 32.5483 25.0809C32.5483 24.842 32.3548 24.6484 32.1161 24.6484Z" fill="#F0EDF8"/>
<path d="M40.7601 27.243H38.5992C38.3605 27.243 38.167 27.4366 38.167 27.6755C38.167 27.9143 38.3605 28.1079 38.5992 28.1079H40.7601C40.9988 28.1079 41.1923 27.9143 41.1923 27.6755C41.1923 27.4366 40.9988 27.243 40.7601 27.243Z" fill="#FEF0E9"/>
<path d="M32.1161 32.4323H29.9551C29.7164 32.4323 29.5229 32.6259 29.5229 32.8647C29.5229 33.1035 29.7164 33.2971 29.9551 33.2971H32.1161C32.3548 33.2971 32.5483 33.1035 32.5483 32.8647C32.5483 32.6259 32.3548 32.4323 32.1161 32.4323Z" fill="#E1DBF1"/>
<path d="M40.7601 29.8378H38.5992C38.3605 29.8378 38.167 30.0314 38.167 30.2702C38.167 30.509 38.3605 30.7026 38.5992 30.7026H40.7601C40.9988 30.7026 41.1923 30.509 41.1923 30.2702C41.1923 30.0314 40.9988 29.8378 40.7601 29.8378Z" fill="#FEF0E9"/>
<path d="M34.9263 24.6484H34.278C34.0393 24.6484 33.8458 24.842 33.8458 25.0809C33.8458 25.3197 34.0393 25.5133 34.278 25.5133H34.9263C35.165 25.5133 35.3585 25.3197 35.3585 25.0809C35.3585 24.842 35.165 24.6484 34.9263 24.6484Z" fill="#FEE1D3"/>
<path d="M36.4379 29.8378H35.7896C35.5509 29.8378 35.3574 30.0314 35.3574 30.2702C35.3574 30.509 35.5509 30.7026 35.7896 30.7026H36.4379C36.6766 30.7026 36.8701 30.509 36.8701 30.2702C36.8701 30.0314 36.6766 29.8378 36.4379 29.8378Z" fill="#6B4FBB"/>
<path d="M34.9263 32.4323H34.278C34.0393 32.4323 33.8458 32.6259 33.8458 32.8647C33.8458 33.1035 34.0393 33.2971 34.278 33.2971H34.9263C35.165 33.2971 35.3585 33.1035 35.3585 32.8647C35.3585 32.6259 35.165 32.4323 34.9263 32.4323Z" fill="#FEE1D3"/>
<path d="M30.6034 27.243H29.9551C29.7164 27.243 29.5229 27.4366 29.5229 27.6755C29.5229 27.9143 29.7164 28.1079 29.9551 28.1079H30.6034C30.8421 28.1079 31.0356 27.9143 31.0356 27.6755C31.0356 27.4366 30.8421 27.243 30.6034 27.243Z" fill="#FC6D26"/>
<path d="M36.4383 27.243H32.7647C32.526 27.243 32.3325 27.4366 32.3325 27.6755C32.3325 27.9143 32.526 28.1079 32.7647 28.1079H36.4383C36.677 28.1079 36.8705 27.9143 36.8705 27.6755C36.8705 27.4366 36.677 27.243 36.4383 27.243Z" fill="#E1DBF1"/>
<path d="M33.6287 29.8378H29.9551C29.7164 29.8378 29.5229 30.0314 29.5229 30.2702C29.5229 30.509 29.7164 30.7026 29.9551 30.7026H33.6287C33.8674 30.7026 34.0609 30.509 34.0609 30.2702C34.0609 30.0314 33.8674 29.8378 33.6287 29.8378Z" fill="#EEEEEE"/>
<path d="M37.7342 24.6484H37.0859C36.8472 24.6484 36.6537 24.842 36.6537 25.0809C36.6537 25.3197 36.8472 25.5133 37.0859 25.5133H37.7342C37.9728 25.5133 38.1663 25.3197 38.1663 25.0809C38.1663 24.842 37.9728 24.6484 37.7342 24.6484Z" fill="#6B4FBB"/>
<path d="M53.2933 22.054H51.1323C50.8936 22.054 50.7001 22.2476 50.7001 22.4864C50.7001 22.7252 50.8936 22.9188 51.1323 22.9188H53.2933C53.532 22.9188 53.7254 22.7252 53.7254 22.4864C53.7254 22.2476 53.532 22.054 53.2933 22.054Z" fill="#FEE1D3"/>
<path d="M57.6143 22.054H55.4533C55.2146 22.054 55.0211 22.2476 55.0211 22.4864C55.0211 22.7252 55.2146 22.9188 55.4533 22.9188H57.6143C57.8529 22.9188 58.0464 22.7252 58.0464 22.4864C58.0464 22.2476 57.8529 22.054 57.6143 22.054Z" fill="#F0EDF8"/>
<path d="M61.9367 22.054H59.7758C59.5371 22.054 59.3436 22.2476 59.3436 22.4864C59.3436 22.7252 59.5371 22.9188 59.7758 22.9188H61.9367C62.1754 22.9188 62.3689 22.7252 62.3689 22.4864C62.3689 22.2476 62.1754 22.054 61.9367 22.054Z" fill="#FC6D26"/>
<path d="M53.2931 24.6486H51.1321C50.8934 24.6486 50.7 24.8422 50.7 25.081C50.7 25.3198 50.8934 25.5134 51.1321 25.5134H53.2931C53.5318 25.5134 53.7253 25.3198 53.7253 25.081C53.7253 24.8422 53.5318 24.6486 53.2931 24.6486Z" fill="#FEF0E9"/>
<path d="M61.9367 27.2432H59.7758C59.5371 27.2432 59.3436 27.4368 59.3436 27.6756C59.3436 27.9144 59.5371 28.108 59.7758 28.108H61.9367C62.1754 28.108 62.3689 27.9144 62.3689 27.6756C62.3689 27.4368 62.1754 27.2432 61.9367 27.2432Z" fill="#E1DBF1"/>
<path d="M53.2931 32.4324H51.1321C50.8934 32.4324 50.7 32.626 50.7 32.8648C50.7 33.1036 50.8934 33.2972 51.1321 33.2972H53.2931C53.5318 33.2972 53.7253 33.1036 53.7253 32.8648C53.7253 32.626 53.5318 32.4324 53.2931 32.4324Z" fill="#F0EDF8"/>
<path d="M61.9367 29.8378H59.7758C59.5371 29.8378 59.3436 30.0314 59.3436 30.2702C59.3436 30.509 59.5371 30.7026 59.7758 30.7026H61.9367C62.1754 30.7026 62.3689 30.509 62.3689 30.2702C62.3689 30.0314 62.1754 29.8378 61.9367 29.8378Z" fill="#FEE1D3"/>
<path d="M56.1016 24.6486H55.4533C55.2146 24.6486 55.0211 24.8422 55.0211 25.081C55.0211 25.3198 55.2146 25.5134 55.4533 25.5134H56.1016C56.3403 25.5134 56.5338 25.3198 56.5338 25.081C56.5338 24.8422 56.3403 24.6486 56.1016 24.6486Z" fill="#FC6D26"/>
<path d="M57.6149 29.8378H56.9666C56.7279 29.8378 56.5344 30.0314 56.5344 30.2702C56.5344 30.509 56.7279 30.7026 56.9666 30.7026H57.6149C57.8536 30.7026 58.0471 30.509 58.0471 30.2702C58.0471 30.0314 57.8536 29.8378 57.6149 29.8378Z" fill="#6B4FBB"/>
<path d="M56.1016 32.4324H55.4533C55.2146 32.4324 55.0211 32.626 55.0211 32.8648C55.0211 33.1036 55.2146 33.2972 55.4533 33.2972H56.1016C56.3403 33.2972 56.5338 33.1036 56.5338 32.8648C56.5338 32.626 56.3403 32.4324 56.1016 32.4324Z" fill="#FC6D26"/>
<path d="M51.7804 27.2432H51.1321C50.8934 27.2432 50.7 27.4368 50.7 27.6756C50.7 27.9144 50.8934 28.108 51.1321 28.108H51.7804C52.0191 28.108 52.2126 27.9144 52.2126 27.6756C52.2126 27.4368 52.0191 27.2432 51.7804 27.2432Z" fill="#6B4FBB"/>
<path d="M57.6153 27.2432H53.9417C53.703 27.2432 53.5095 27.4368 53.5095 27.6756C53.5095 27.9144 53.703 28.108 53.9417 28.108H57.6153C57.854 28.108 58.0475 27.9144 58.0475 27.6756C58.0475 27.4368 57.854 27.2432 57.6153 27.2432Z" fill="#FEE1D3"/>
<path d="M54.8057 29.8378H51.1321C50.8934 29.8378 50.7 30.0314 50.7 30.2702C50.7 30.509 50.8934 30.7026 51.1321 30.7026H54.8057C55.0444 30.7026 55.2379 30.509 55.2379 30.2702C55.2379 30.0314 55.0444 29.8378 54.8057 29.8378Z" fill="#FEF0E9"/>
<path d="M58.9112 24.6486H58.2629C58.0242 24.6486 57.8307 24.8422 57.8307 25.081C57.8307 25.3198 58.0242 25.5134 58.2629 25.5134H58.9112C59.1499 25.5134 59.3433 25.3198 59.3433 25.081C59.3433 24.8422 59.1499 24.6486 58.9112 24.6486Z" fill="#6B4FBB"/>
<path d="M32.1163 35.027H29.9553C29.7166 35.027 29.5231 35.2206 29.5231 35.4594C29.5231 35.6982 29.7166 35.8918 29.9553 35.8918H32.1163C32.355 35.8918 32.5484 35.6982 32.5484 35.4594C32.5484 35.2206 32.355 35.027 32.1163 35.027Z" fill="#F0EDF8"/>
<path d="M36.4372 35.027H34.2763C34.0376 35.027 33.8441 35.2206 33.8441 35.4594C33.8441 35.6982 34.0376 35.8918 34.2763 35.8918H36.4372C36.6759 35.8918 36.8694 35.6982 36.8694 35.4594C36.8694 35.2206 36.6759 35.027 36.4372 35.027Z" fill="#6B4FBB"/>
<path d="M40.7597 35.027H38.5988C38.3601 35.027 38.1666 35.2206 38.1666 35.4594C38.1666 35.6982 38.3601 35.8918 38.5988 35.8918H40.7597C40.9984 35.8918 41.1919 35.6982 41.1919 35.4594C41.1919 35.2206 40.9984 35.027 40.7597 35.027Z" fill="#E1DBF1"/>
<path d="M32.1161 37.6216H29.9551C29.7164 37.6216 29.5229 37.8152 29.5229 38.054C29.5229 38.2928 29.7164 38.4864 29.9551 38.4864H32.1161C32.3548 38.4864 32.5483 38.2928 32.5483 38.054C32.5483 37.8152 32.3548 37.6216 32.1161 37.6216Z" fill="#FEF0E9"/>
<path d="M40.7597 40.2161H38.5988C38.3601 40.2161 38.1666 40.4097 38.1666 40.6485C38.1666 40.8873 38.3601 41.0809 38.5988 41.0809H40.7597C40.9984 41.0809 41.1919 40.8873 41.1919 40.6485C41.1919 40.4097 40.9984 40.2161 40.7597 40.2161Z" fill="#FEE1D3"/>
<path d="M34.9246 37.6216H34.2763C34.0376 37.6216 33.8441 37.8152 33.8441 38.054C33.8441 38.2928 34.0376 38.4864 34.2763 38.4864H34.9246C35.1633 38.4864 35.3568 38.2928 35.3568 38.054C35.3568 37.8152 35.1633 37.6216 34.9246 37.6216Z" fill="#EEEEEE"/>
<path d="M30.6034 40.2161H29.9551C29.7164 40.2161 29.5229 40.4097 29.5229 40.6485C29.5229 40.8873 29.7164 41.0809 29.9551 41.0809H30.6034C30.8421 41.0809 31.0356 40.8873 31.0356 40.6485C31.0356 40.4097 30.8421 40.2161 30.6034 40.2161Z" fill="#6B4FBB"/>
<path d="M36.4383 40.2161H32.7647C32.526 40.2161 32.3325 40.4097 32.3325 40.6485C32.3325 40.8873 32.526 41.0809 32.7647 41.0809H36.4383C36.677 41.0809 36.8705 40.8873 36.8705 40.6485C36.8705 40.4097 36.677 40.2161 36.4383 40.2161Z" fill="#FEF0E9"/>
<path d="M37.7342 37.6216H37.0859C36.8472 37.6216 36.6537 37.8152 36.6537 38.054C36.6537 38.2928 36.8472 38.4864 37.0859 38.4864H37.7342C37.9728 38.4864 38.1663 38.2928 38.1663 38.054C38.1663 37.8152 37.9728 37.6216 37.7342 37.6216Z" fill="#FC6D26"/>
<path d="M46.3791 25.2972C46.3791 25.0584 46.1856 24.8647 45.947 24.8647C45.7083 24.8647 45.5148 25.0584 45.5148 25.2972V38.0539C45.5148 38.2927 45.7083 38.4863 45.947 38.4863C46.1856 38.4863 46.3791 38.2927 46.3791 38.0539V25.2972Z" fill="#EEEEEE"/>
<path d="M66.9082 15.135H18.0709C17.8322 15.135 17.6387 15.3286 17.6387 15.5674C17.6387 15.8063 17.8322 15.9999 18.0709 15.9999H66.9082C67.1469 15.9999 67.3404 15.8063 67.3404 15.5674C67.3404 15.3286 67.1469 15.135 66.9082 15.135Z" fill="#EEEEEE"/>
<path d="M55.8884 55.3513C59.5881 55.3513 62.5874 52.3504 62.5874 48.6486C62.5874 44.9468 59.5881 41.9459 55.8884 41.9459C52.1887 41.9459 49.1895 44.9468 49.1895 48.6486C49.1895 52.3504 52.1887 55.3513 55.8884 55.3513Z" fill="white"/>
<path d="M55.8878 54.9188C59.3489 54.9188 62.1546 52.1115 62.1546 48.6486C62.1546 45.1856 59.3489 42.3783 55.8878 42.3783C52.4268 42.3783 49.6211 45.1856 49.6211 48.6486C49.6211 52.1115 52.4268 54.9188 55.8878 54.9188Z" stroke="#EEEEEE" stroke-width="2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M55.457 48.2161V46.9188C55.457 46.6799 55.6505 46.4863 55.8892 46.4863C56.1278 46.4863 56.3213 46.6799 56.3213 46.9188V48.2161H57.6179C57.8566 48.2161 58.0501 48.4097 58.0501 48.6485C58.0501 48.8873 57.8566 49.0809 57.6179 49.0809H56.3213V50.3782C56.3213 50.617 56.1278 50.8106 55.8892 50.8106C55.6505 50.8106 55.457 50.617 55.457 50.3782V49.0809H54.1604C53.9217 49.0809 53.7282 48.8873 53.7282 48.6485C53.7282 48.4097 53.9217 48.2161 54.1604 48.2161H55.457Z" fill="#FC6D26"/>
</svg>

After

Width:  |  Height:  |  Size: 18 KiB

View file

@ -0,0 +1,36 @@
<svg width="47" height="47" viewBox="0 0 47 47" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M23.0588 47C35.7939 47 46.1176 36.6762 46.1176 23.9411C46.1176 11.2061 35.7939 0.882324 23.0588 0.882324C10.3238 0.882324 0 11.2061 0 23.9411C0 36.6762 10.3238 47 23.0588 47Z" fill="#EEEEEE"/>
<path d="M23.0588 45.1176C34.7542 45.1176 44.2353 35.6366 44.2353 23.9411C44.2353 12.2457 34.7542 2.76465 23.0588 2.76465C11.3634 2.76465 1.88232 12.2457 1.88232 23.9411C1.88232 35.6366 11.3634 45.1176 23.0588 45.1176Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.3292 14.5295H16.9802C17.4786 14.5295 17.8827 14.9336 17.8827 15.432V16.8825C17.8827 17.4023 17.4613 17.8237 16.9415 17.8237H13.6556C13.1683 17.8237 12.7732 17.4286 12.7732 16.9413C12.7732 16.6257 12.9419 16.334 13.2155 16.1766L15.8598 14.655C16.0026 14.5728 16.1644 14.5295 16.3292 14.5295ZM12.2356 23.0001H16.9415C17.4613 23.0001 17.8827 23.4215 17.8827 23.9413V25.3531C17.8827 25.8729 17.4613 26.2942 16.9415 26.2942H12.2356C11.7158 26.2942 11.2944 25.8729 11.2944 25.3531V23.9413C11.2944 23.4215 11.7158 23.0001 12.2356 23.0001Z" fill="#EFEDF8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.11793 18.7649H10.8238C11.3436 18.7649 11.765 19.1863 11.765 19.7061V21.1178C11.765 21.6376 11.3436 22.059 10.8238 22.059H6.11793C5.59814 22.059 5.17676 21.6376 5.17676 21.1178V19.7061C5.17676 19.1863 5.59814 18.7649 6.11793 18.7649Z" fill="#F9E2D5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M40.4709 18.7649H35.765C35.2452 18.7649 34.8239 19.1863 34.8239 19.7061V21.1178C34.8239 21.6376 35.2452 22.059 35.765 22.059H40.4709C40.9907 22.059 41.4121 21.6376 41.4121 21.1178V19.7061C41.4121 19.1863 40.9907 18.7649 40.4709 18.7649Z" fill="#F9E2D5"/>
<path d="M16.9415 31.0002H12.2356C11.7158 31.0002 11.2944 31.4216 11.2944 31.9414V33.3532C11.2944 33.873 11.7158 34.2944 12.2356 34.2944H16.9415C17.4613 34.2944 17.8827 33.873 17.8827 33.3532V31.9414C17.8827 31.4216 17.4613 31.0002 16.9415 31.0002Z" fill="#F9E2D5"/>
<path d="M29.6474 31.0002H34.3533C34.8731 31.0002 35.2944 31.4216 35.2944 31.9414V33.3532C35.2944 33.873 34.8731 34.2944 34.3533 34.2944H29.6474C29.1276 34.2944 28.7062 33.873 28.7062 33.3532V31.9414C28.7062 31.4216 29.1276 31.0002 29.6474 31.0002Z" fill="#F9E2D5"/>
<path d="M9.41202 31.0002H8.00026C7.48046 31.0002 7.05908 31.4216 7.05908 31.9414V33.3532C7.05908 33.873 7.48046 34.2944 8.00026 34.2944H9.41202C9.93182 34.2944 10.3532 33.873 10.3532 33.3532V31.9414C10.3532 31.4216 9.93182 31.0002 9.41202 31.0002Z" fill="#F9E2D5"/>
<path d="M37.1768 31.0002H38.5886C39.1084 31.0002 39.5298 31.4216 39.5298 31.9414V33.3532C39.5298 33.873 39.1084 34.2944 38.5886 34.2944H37.1768C36.657 34.2944 36.2357 33.873 36.2357 33.3532V31.9414C36.2357 31.4216 36.657 31.0002 37.1768 31.0002Z" fill="#F9E2D5"/>
<path d="M9.41202 23.0002H8.00026C7.48046 23.0002 7.05908 23.4216 7.05908 23.9414V25.3532C7.05908 25.873 7.48046 26.2944 8.00026 26.2944H9.41202C9.93182 26.2944 10.3532 25.873 10.3532 25.3532V23.9414C10.3532 23.4216 9.93182 23.0002 9.41202 23.0002Z" fill="#F9E2D5"/>
<path d="M37.1768 23.0002H38.5886C39.1084 23.0002 39.5298 23.4216 39.5298 23.9414V25.3532C39.5298 25.873 39.1084 26.2944 38.5886 26.2944H37.1768C36.657 26.2944 36.2357 25.873 36.2357 25.3532V23.9414C36.2357 23.4216 36.657 23.0002 37.1768 23.0002Z" fill="#F9E2D5"/>
<path d="M9.41202 14.5295H8.00026C7.48046 14.5295 7.05908 14.9509 7.05908 15.4707V16.8825C7.05908 17.4023 7.48046 17.8237 8.00026 17.8237H9.41202C9.93182 17.8237 10.3532 17.4023 10.3532 16.8825V15.4707C10.3532 14.9509 9.93182 14.5295 9.41202 14.5295Z" fill="#F9E2D5"/>
<path d="M37.1768 14.5295H38.5886C39.1084 14.5295 39.5298 14.9509 39.5298 15.4707V16.8825C39.5298 17.4023 39.1084 17.8237 38.5886 17.8237H37.1768C36.657 17.8237 36.2357 17.4023 36.2357 16.8825V15.4707C36.2357 14.9509 36.657 14.5295 37.1768 14.5295Z" fill="#F9E2D5"/>
<path d="M10.8238 26.7649H6.11793C5.59814 26.7649 5.17676 27.1863 5.17676 27.7061V29.1178C5.17676 29.6376 5.59814 30.059 6.11793 30.059H10.8238C11.3436 30.059 11.765 29.6376 11.765 29.1178V27.7061C11.765 27.1863 11.3436 26.7649 10.8238 26.7649Z" fill="#F9E2D5"/>
<path d="M35.765 26.7649H40.4709C40.9907 26.7649 41.4121 27.1863 41.4121 27.7061V29.1178C41.4121 29.6376 40.9907 30.059 40.4709 30.059H35.765C35.2452 30.059 34.8239 29.6376 34.8239 29.1178V27.7061C34.8239 27.1863 35.2452 26.7649 35.765 26.7649Z" fill="#F9E2D5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.2356 14.5295H16.9415C17.4613 14.5295 17.8827 14.9509 17.8827 15.4707V16.8825C17.8827 17.4023 17.4613 17.8237 16.9415 17.8237H12.2356C11.7158 17.8237 11.2944 17.4023 11.2944 16.8825V15.4707C11.2944 14.9509 11.7158 14.5295 12.2356 14.5295Z" fill="#EFEDF8"/>
<path d="M28.2354 14.5295H23.5296C23.0098 14.5295 22.5884 14.9509 22.5884 15.4707V16.8825C22.5884 17.4023 23.0098 17.8237 23.5296 17.8237H28.2354C28.7552 17.8237 29.1766 17.4023 29.1766 16.8825V15.4707C29.1766 14.9509 28.7552 14.5295 28.2354 14.5295Z" fill="#EFEDF8"/>
<path d="M28.2354 23.0002H23.5296C23.0098 23.0002 22.5884 23.4216 22.5884 23.9414V25.3532C22.5884 25.873 23.0098 26.2944 23.5296 26.2944H28.2354C28.7552 26.2944 29.1766 25.873 29.1766 25.3532V23.9414C29.1766 23.4216 28.7552 23.0002 28.2354 23.0002Z" fill="#EFEDF8"/>
<path d="M32.0002 26.7649H29.6472C29.1274 26.7649 28.7061 27.1863 28.7061 27.7061V29.1178C28.7061 29.6376 29.1274 30.059 29.6472 30.059H32.0002C32.52 30.059 32.9413 29.6376 32.9413 29.1178V27.7061C32.9413 27.1863 32.52 26.7649 32.0002 26.7649Z" fill="#EFEDF8"/>
<path d="M22.5885 18.7649H17.8826C17.3628 18.7649 16.9414 19.1863 16.9414 19.7061V21.1178C16.9414 21.6376 17.3628 22.059 17.8826 22.059H22.5885C23.1083 22.059 23.5296 21.6376 23.5296 21.1178V19.7061C23.5296 19.1863 23.1083 18.7649 22.5885 18.7649Z" fill="#EFEDF8"/>
<path d="M21.1767 14.5295H19.7649C19.2451 14.5295 18.8237 14.9509 18.8237 15.4707V16.8825C18.8237 17.4023 19.2451 17.8237 19.7649 17.8237H21.1767C21.6965 17.8237 22.1178 17.4023 22.1178 16.8825V15.4707C22.1178 14.9509 21.6965 14.5295 21.1767 14.5295Z" fill="#EFEDF8"/>
<path d="M21.1767 23.0002H19.7649C19.2451 23.0002 18.8237 23.4216 18.8237 23.9414V25.3532C18.8237 25.873 19.2451 26.2944 19.7649 26.2944H21.1767C21.6965 26.2944 22.1178 25.873 22.1178 25.3532V23.9414C22.1178 23.4216 21.6965 23.0002 21.1767 23.0002Z" fill="#EFEDF8"/>
<path d="M15.059 26.7649H13.6472C13.1274 26.7649 12.7061 27.1863 12.7061 27.7061V29.1178C12.7061 29.6376 13.1274 30.059 13.6472 30.059H15.059C15.5788 30.059 16.0002 29.6376 16.0002 29.1178V27.7061C16.0002 27.1863 15.5788 26.7649 15.059 26.7649Z" fill="#EFEDF8"/>
<path d="M21.1767 31.0002H19.7649C19.2451 31.0002 18.8237 31.4216 18.8237 31.9414V33.3532C18.8237 33.873 19.2451 34.2944 19.7649 34.2944H21.1767C21.6965 34.2944 22.1178 33.873 22.1178 33.3532V31.9414C22.1178 31.4216 21.6965 31.0002 21.1767 31.0002Z" fill="#EFEDF8"/>
<path d="M32.4706 23.0002H31.0589C30.5391 23.0002 30.1177 23.4216 30.1177 23.9414V25.3532C30.1177 25.873 30.5391 26.2944 31.0589 26.2944H32.4706C32.9904 26.2944 33.4118 25.873 33.4118 25.3532V23.9414C33.4118 23.4216 32.9904 23.0002 32.4706 23.0002Z" fill="#EFEDF8"/>
<path d="M15.059 18.7649H13.6472C13.1274 18.7649 12.7061 19.1863 12.7061 19.7061V21.1178C12.7061 21.6376 13.1274 22.059 13.6472 22.059H15.059C15.5788 22.059 16.0002 21.6376 16.0002 21.1178V19.7061C16.0002 19.1863 15.5788 18.7649 15.059 18.7649Z" fill="#EFEDF8"/>
<path d="M26.8241 18.7649H25.4124C24.8926 18.7649 24.4712 19.1863 24.4712 19.7061V21.1178C24.4712 21.6376 24.8926 22.059 25.4124 22.059H26.8241C27.3439 22.059 27.7653 21.6376 27.7653 21.1178V19.7061C27.7653 19.1863 27.3439 18.7649 26.8241 18.7649Z" fill="#EFEDF8"/>
<path d="M32.4706 14.5295H31.0589C30.5391 14.5295 30.1177 14.9509 30.1177 15.4707V16.8825C30.1177 17.4023 30.5391 17.8237 31.0589 17.8237H32.4706C32.9904 17.8237 33.4118 17.4023 33.4118 16.8825V15.4707C33.4118 14.9509 32.9904 14.5295 32.4706 14.5295Z" fill="#EFEDF8"/>
<path d="M34.3531 18.7649H29.6472C29.1274 18.7649 28.7061 19.1863 28.7061 19.7061V21.1178C28.7061 21.6376 29.1274 22.059 29.6472 22.059H34.3531C34.8729 22.059 35.2943 21.6376 35.2943 21.1178V19.7061C35.2943 19.1863 34.8729 18.7649 34.3531 18.7649Z" fill="#EFEDF8"/>
<path d="M22.5885 26.7649H17.8826C17.3628 26.7649 16.9414 27.1863 16.9414 27.7061V29.1178C16.9414 29.6376 17.3628 30.059 17.8826 30.059H22.5885C23.1083 30.059 23.5296 29.6376 23.5296 29.1178V27.7061C23.5296 27.1863 23.1083 26.7649 22.5885 26.7649Z" fill="#EFEDF8"/>
<path d="M28.2354 31.0002H23.5296C23.0098 31.0002 22.5884 31.4216 22.5884 31.9414V33.3532C22.5884 33.873 23.0098 34.2944 23.5296 34.2944H28.2354C28.7552 34.2944 29.1766 33.873 29.1766 33.3532V31.9414C29.1766 31.4216 28.7552 31.0002 28.2354 31.0002Z" fill="#EFEDF8"/>
<path d="M26.8241 26.7649H25.4124C24.8926 26.7649 24.4712 27.1863 24.4712 27.7061V29.1178C24.4712 29.6376 24.8926 30.059 25.4124 30.059H26.8241C27.3439 30.059 27.7653 29.6376 27.7653 29.1178V27.7061C27.7653 27.1863 27.3439 26.7649 26.8241 26.7649Z" fill="#EFEDF8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.5516 10.3323L36.0222 13.8791C36.4267 13.9942 36.7059 14.3638 36.7059 14.7844V21.1043C36.7059 25.151 35.0909 29.032 32.2166 31.8933L23.9581 40.1143C23.5909 40.4798 22.9973 40.4798 22.6301 40.1143L14.3717 31.8933C11.4972 29.032 9.88232 25.151 9.88232 21.1043V14.7844C9.88232 14.3638 10.1614 13.9942 10.566 13.8791L23.0366 10.3323C23.2049 10.2844 23.3833 10.2844 23.5516 10.3323ZM23.1301 12.4046L11.9603 15.5579C11.7575 15.6151 11.6175 15.8001 11.6175 16.0108V20.6639C11.6175 24.3243 13.0892 27.8348 15.7088 30.4231L22.9272 37.5553C23.1105 37.7364 23.4054 37.7364 23.5887 37.5553L30.807 30.4231C33.4268 27.8348 34.8983 24.3243 34.8983 20.6639V16.0108C34.8983 15.8001 34.7583 15.6151 34.5556 15.5579L23.3858 12.4046C23.3022 12.381 23.2137 12.381 23.1301 12.4046Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.3165 11.7436L34.14 14.8206C34.5447 14.9356 34.8238 15.3052 34.8238 15.7259V21.1793C34.8238 24.7274 33.4072 28.1301 30.8859 30.6389L23.723 37.7659C23.3558 38.1312 22.7625 38.1312 22.3953 37.7659L15.2325 30.6389C12.711 28.1301 11.2944 24.7274 11.2944 21.1793V15.7259C11.2944 15.3052 11.5736 14.9356 11.9782 14.8206L22.8018 11.7436C22.97 11.6958 23.1483 11.6958 23.3165 11.7436ZM22.8996 13.5561L13.1593 16.3045C12.9566 16.3617 12.8166 16.5467 12.8166 16.7574V20.7932C12.8166 24.0026 14.1075 27.0805 16.4054 29.3498L22.6968 35.5631C22.88 35.7442 23.1748 35.7442 23.3581 35.5631L29.6494 29.3498C31.9474 27.0805 33.2383 24.0026 33.2383 20.7932V16.7574C33.2383 16.5467 33.0983 16.3617 32.8955 16.3045L23.1552 13.5561C23.0717 13.5325 22.9832 13.5325 22.8996 13.5561Z" fill="#6E49CB"/>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

View file

@ -0,0 +1,9 @@
<svg width="32" height="30" viewBox="0 0 32 30" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9653 29.8263L21.8368 11.6285H10.0933L15.9653 29.8263Z" fill="#E38800"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9656 29.8263L10.0936 11.6285H1.86475L15.9656 29.8263Z" fill="#F7980A"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.86441 11.6285L0.0800968 17.1586C-0.0826524 17.663 0.0955967 18.2156 0.521693 18.5273L15.9652 29.8261L1.86441 11.6285Z" fill="#FCA326"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M1.86426 11.6286H10.0933L6.55678 0.668335C6.37489 0.104294 5.58257 0.104447 5.40067 0.668335L1.86426 11.6286Z" fill="#E38800"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M15.9653 29.8263L21.8369 11.6285H30.0658L15.9653 29.8263Z" fill="#F7980A"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.0662 11.6285L31.8505 17.1586C32.0132 17.663 31.835 18.2156 31.4089 18.5273L15.9653 29.8261L30.0662 11.6285Z" fill="#FCA326"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.066 11.6286H21.8369L25.3735 0.668335C25.5554 0.104294 26.3477 0.104447 26.5296 0.668335L30.066 11.6286Z" fill="#E38800"/>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -0,0 +1,4 @@
<svg width="38" height="24" viewBox="0 0 38 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M33.6353 7.51765H33.8824L32.4706 5.80941L31.0588 7.50353L29.6471 5.80941L28.2353 7.50353L26.8235 5.80941L25.4118 7.50353L24 5.80941L22.5882 7.51765H23.1318C23.6965 8.89412 24 10.4118 24 12C24 14.0047 23.5059 15.8824 22.6447 17.5482C24.0353 19.1576 26.0541 20.1176 28.2353 20.1176C32.3294 20.1176 35.6471 16.7718 35.6471 12.6353C35.6471 10.6588 34.8847 8.85177 33.6353 7.51765ZM22.0094 5.36471C23.7035 3.88235 25.9059 3.03529 28.2353 3.03529C33.5012 3.03529 37.7647 7.34118 37.7647 12.6353C37.7647 17.9294 33.5012 22.2353 28.2353 22.2353C25.6376 22.2353 23.2235 21.1765 21.4588 19.3835C19.2706 22.1929 15.84 24 12 24C5.36471 24 0 18.6353 0 12C0 5.36471 5.36471 0 12 0C14.2729 0 16.3976 0.635295 18.2118 1.72941C19.7153 2.64706 21.0141 3.88235 22.0094 5.37177V5.36471ZM3.52941 8.47059C3.07059 9.55765 2.82353 10.7506 2.82353 12C2.82353 17.0682 6.93177 21.1765 12 21.1765C17.0682 21.1765 21.1765 17.0682 21.1765 12C21.1765 10.7506 20.9294 9.55765 20.4706 8.47059H14.1176C13.7435 8.47059 13.3835 8.32941 13.1294 8.04706L12 6.94588L10.8706 8.06118C10.6165 8.34353 10.2565 8.48471 9.88235 8.48471H3.52941V8.47059ZM18.6212 5.64706C16.9271 3.88235 14.5553 2.82353 12 2.82353C9.44471 2.82353 7.07294 3.88235 5.37882 5.64706H9.29647L11.0047 3.95294C11.5271 3.38824 12.4165 3.38824 12.9812 3.95294L14.6753 5.64706H18.5859H18.6212Z" fill="#E1DBF2"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M25.1292 14.3435C24.6633 14.3435 24.2821 13.9623 24.2821 13.4964C24.2821 13.0164 24.6633 12.6353 25.1292 12.6353C25.5951 12.6353 25.9762 13.0164 25.9762 13.4823C25.9762 13.9623 25.5951 14.3435 25.1292 14.3435ZM31.3409 14.3435C30.8751 14.3435 30.4939 13.9623 30.4939 13.4964C30.4939 13.0164 30.8751 12.6353 31.3409 12.6353C31.8068 12.6353 32.188 13.0164 32.188 13.4823C32.188 13.9623 31.8068 14.3435 31.3409 14.3435ZM9.17624 15.5294H14.8233C14.8233 17.0823 13.5527 18.3529 11.9998 18.3529C10.4468 18.3529 9.17624 17.0823 9.17624 15.5294ZM8.11742 14.8235C7.53153 14.8235 7.05859 14.3505 7.05859 13.7647C7.05859 13.1788 7.53153 12.7058 8.11742 12.7058C8.7033 12.7058 9.17624 13.1788 9.17624 13.7647C9.17624 14.3505 8.7033 14.8235 8.11742 14.8235ZM15.8821 14.8235C15.2962 14.8235 14.8233 14.3505 14.8233 13.7647C14.8233 13.1788 15.2962 12.7058 15.8821 12.7058C16.468 12.7058 16.9409 13.1788 16.9409 13.7647C16.9409 14.3505 16.468 14.8235 15.8821 14.8235Z" fill="#6B4FBB"/>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View file

@ -0,0 +1,69 @@
<script>
import { GlFormGroup, GlFormRadio, GlFormText } from '@gitlab/ui';
import ProjectsTokenSelector from './projects_token_selector.vue';
export default {
name: 'ProjectsField',
ALL_PROJECTS: 'ALL_PROJECTS',
SELECTED_PROJECTS: 'SELECTED_PROJECTS',
components: { GlFormGroup, GlFormRadio, GlFormText, ProjectsTokenSelector },
props: {
inputAttrs: {
type: Object,
required: true,
},
},
data() {
return {
selectedRadio: !this.inputAttrs.value
? this.$options.ALL_PROJECTS
: this.$options.SELECTED_PROJECTS,
selectedProjects: [],
};
},
computed: {
allProjectsRadioSelected() {
return this.selectedRadio === this.$options.ALL_PROJECTS;
},
hiddenInputValue() {
return this.allProjectsRadioSelected
? null
: this.selectedProjects.map((project) => project.id).join(',');
},
initialProjectIds() {
if (!this.inputAttrs.value) {
return [];
}
return this.inputAttrs.value.split(',');
},
},
methods: {
handleTokenSelectorFocus() {
this.selectedRadio = this.$options.SELECTED_PROJECTS;
},
},
};
</script>
<template>
<div>
<gl-form-group :label="__('Projects')" label-class="gl-pb-0!">
<gl-form-text class="gl-pb-3">{{
__('Set access permissions for this token.')
}}</gl-form-text>
<gl-form-radio v-model="selectedRadio" :value="$options.ALL_PROJECTS">{{
__('All projects')
}}</gl-form-radio>
<gl-form-radio v-model="selectedRadio" :value="$options.SELECTED_PROJECTS">{{
__('Selected projects')
}}</gl-form-radio>
<input :id="inputAttrs.id" type="hidden" :name="inputAttrs.name" :value="hiddenInputValue" />
<projects-token-selector
v-model="selectedProjects"
:initial-project-ids="initialProjectIds"
@focus="handleTokenSelectorFocus"
/>
</gl-form-group>
</div>
</template>

View file

@ -0,0 +1,156 @@
<script>
import {
GlTokenSelector,
GlAvatar,
GlAvatarLabeled,
GlIntersectionObserver,
GlLoadingIcon,
} from '@gitlab/ui';
import produce from 'immer';
import { convertToGraphQLIds, convertNodeIdsFromGraphQLIds } from '~/graphql_shared/utils';
import getProjectsQuery from '../graphql/queries/get_projects.query.graphql';
const DEBOUNCE_DELAY = 250;
const PROJECTS_PER_PAGE = 20;
const GRAPHQL_ENTITY_TYPE = 'Project';
export default {
name: 'ProjectsTokenSelector',
components: {
GlTokenSelector,
GlAvatar,
GlAvatarLabeled,
GlIntersectionObserver,
GlLoadingIcon,
},
model: {
prop: 'selectedProjects',
},
props: {
selectedProjects: {
type: Array,
required: true,
},
initialProjectIds: {
type: Array,
required: true,
},
},
apollo: {
projects: {
query: getProjectsQuery,
debounce: DEBOUNCE_DELAY,
variables() {
return {
search: this.searchQuery,
after: null,
first: PROJECTS_PER_PAGE,
};
},
update({ projects }) {
return {
list: convertNodeIdsFromGraphQLIds(projects.nodes),
pageInfo: projects.pageInfo,
};
},
result() {
this.isLoadingMoreProjects = false;
this.isSearching = false;
},
},
initialProjects: {
query: getProjectsQuery,
variables() {
return {
ids: convertToGraphQLIds(GRAPHQL_ENTITY_TYPE, this.initialProjectIds),
};
},
manual: true,
skip() {
return !this.initialProjectIds.length;
},
result({ data: { projects } }) {
this.$emit('input', convertNodeIdsFromGraphQLIds(projects.nodes));
},
},
},
data() {
return {
projects: {
list: [],
pageInfo: {},
},
searchQuery: '',
isLoadingMoreProjects: false,
isSearching: false,
};
},
methods: {
handleSearch(query) {
this.isSearching = true;
this.searchQuery = query;
},
loadMoreProjects() {
this.isLoadingMoreProjects = true;
this.$apollo.queries.projects.fetchMore({
variables: {
after: this.projects.pageInfo.endCursor,
first: PROJECTS_PER_PAGE,
},
updateQuery(previousResult, { fetchMoreResult: { projects: newProjects } }) {
const { projects: previousProjects } = previousResult;
return produce(previousResult, (draftData) => {
draftData.projects.nodes = [...previousProjects.nodes, ...newProjects.nodes];
draftData.projects.pageInfo = newProjects.pageInfo;
});
},
});
},
},
};
</script>
<template>
<div class="gl-relative">
<gl-token-selector
:selected-tokens="selectedProjects"
:dropdown-items="projects.list"
:loading="isSearching"
:placeholder="__('Select projects')"
menu-class="gl-w-full! gl-max-w-full!"
@input="$emit('input', $event)"
@focus="$emit('focus', $event)"
@text-input="handleSearch"
@keydown.enter.prevent
>
<template #token-content="{ token: project }">
<gl-avatar
:entity-id="project.id"
:entity-name="project.name"
:src="project.avatarUrl"
:size="16"
/>
{{ project.nameWithNamespace }}
</template>
<template #dropdown-item-content="{ dropdownItem: project }">
<gl-avatar-labeled
:entity-id="project.id"
:entity-name="project.name"
:size="32"
:src="project.avatarUrl"
:label="project.name"
:sub-label="project.nameWithNamespace"
/>
</template>
<template #dropdown-footer>
<gl-intersection-observer v-if="projects.pageInfo.hasNextPage" @appear="loadMoreProjects">
<gl-loading-icon v-if="isLoadingMoreProjects" size="md" />
</gl-intersection-observer>
</template>
</gl-token-selector>
</div>
</template>

View file

@ -0,0 +1,28 @@
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
query getProjects(
$search: String = ""
$after: String = ""
$first: Int = null
$ids: [ID!] = null
) {
projects(
search: $search
after: $after
first: $first
ids: $ids
membership: true
searchNamespaces: true
sort: "UPDATED_ASC"
) {
nodes {
id
name
nameWithNamespace
avatarUrl
}
pageInfo {
...PageInfo
}
}
}

View file

@ -1,4 +1,7 @@
import Vue from 'vue'; import Vue from 'vue';
import createFlash from '~/flash';
import { __ } from '~/locale';
import ExpiresAtField from './components/expires_at_field.vue'; import ExpiresAtField from './components/expires_at_field.vue';
const getInputAttrs = (el) => { const getInputAttrs = (el) => {
@ -7,11 +10,12 @@ const getInputAttrs = (el) => {
return { return {
id: input.id, id: input.id,
name: input.name, name: input.name,
value: input.value,
placeholder: input.placeholder, placeholder: input.placeholder,
}; };
}; };
const initExpiresAtField = () => { export const initExpiresAtField = () => {
const el = document.querySelector('.js-access-tokens-expires-at'); const el = document.querySelector('.js-access-tokens-expires-at');
if (!el) { if (!el) {
@ -32,4 +36,58 @@ const initExpiresAtField = () => {
}); });
}; };
export default initExpiresAtField; export const initProjectsField = () => {
const el = document.querySelector('.js-access-tokens-projects');
if (!el) {
return null;
}
const inputAttrs = getInputAttrs(el);
if (window.gon.features.personalAccessTokensScopedToProjects) {
return new Promise((resolve) => {
Promise.all([
import('./components/projects_field.vue'),
import('vue-apollo'),
import('~/lib/graphql'),
])
.then(
([
{ default: ProjectsField },
{ default: VueApollo },
{ default: createDefaultClient },
]) => {
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
Vue.use(VueApollo);
resolve(
new Vue({
el,
apolloProvider,
render(h) {
return h(ProjectsField, {
props: {
inputAttrs,
},
});
},
}),
);
},
)
.catch(() => {
createFlash({
message: __(
'An error occurred while loading the access tokens form, please try again.',
),
});
});
});
}
return null;
};

View file

@ -1,2 +0,0 @@
// EE-specific feature. Find the implementation in the `ee/`-folder
export default () => {};

View file

@ -1,11 +1,20 @@
import Api from '~/api';
import { historyPushState } from '~/lib/utils/common_utils'; import { historyPushState } from '~/lib/utils/common_utils';
import { mergeUrlParams } from '~/lib/utils/url_utility'; import { mergeUrlParams } from '~/lib/utils/url_utility';
const COHORTS_PANE = 'cohorts'; const COHORTS_PANE = 'cohorts';
const COHORTS_PANE_TAB_CLICK_EVENT = 'i_analytics_cohorts';
const tabClickHandler = (e) => { const tabClickHandler = (e) => {
const { hash } = e.currentTarget; const { hash } = e.currentTarget;
const tab = hash === `#${COHORTS_PANE}` ? COHORTS_PANE : null;
let tab = null;
if (hash === `#${COHORTS_PANE}`) {
tab = COHORTS_PANE;
Api.trackRedisHllUserEvent(COHORTS_PANE_TAB_CLICK_EVENT);
}
const newUrl = mergeUrlParams({ tab }, window.location.href); const newUrl = mergeUrlParams({ tab }, window.location.href);
historyPushState(newUrl); historyPushState(newUrl);
}; };

View file

@ -42,6 +42,7 @@ export default {
"AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear.", "AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear.",
), ),
unassigned: __('Unassigned'), unassigned: __('Unassigned'),
closed: __('closed'),
}, },
fields: [ fields: [
{ {
@ -75,7 +76,7 @@ export default {
{ {
key: 'issue', key: 'issue',
label: s__('AlertManagement|Incident'), label: s__('AlertManagement|Incident'),
thClass: 'gl-w-12 gl-pointer-events-none', thClass: 'gl-w-15p gl-pointer-events-none',
tdClass, tdClass,
}, },
{ {
@ -221,8 +222,11 @@ export default {
hasAssignees(assignees) { hasAssignees(assignees) {
return Boolean(assignees.nodes?.length); return Boolean(assignees.nodes?.length);
}, },
getIssueLink(item) { getIssueMeta({ issue: { iid, state } }) {
return joinPaths('/', this.projectPath, '-', 'issues', item.issueIid); return {
state: state === 'closed' ? `(${this.$options.i18n.closed})` : '',
link: joinPaths('/', this.projectPath, '-', 'issues/incident', iid),
};
}, },
tbodyTrClass(item) { tbodyTrClass(item) {
return { return {
@ -343,8 +347,14 @@ export default {
</template> </template>
<template #cell(issue)="{ item }"> <template #cell(issue)="{ item }">
<gl-link v-if="item.issueIid" data-testid="issueField" :href="getIssueLink(item)"> <gl-link
#{{ item.issueIid }} v-if="item.issue"
v-gl-tooltip
:title="item.issue.title"
data-testid="issueField"
:href="getIssueMeta(item).link"
>
#{{ item.issue.iid }} {{ getIssueMeta(item).state }}
</gl-link> </gl-link>
<div v-else data-testid="issueField">{{ s__('AlertManagement|None') }}</div> <div v-else data-testid="issueField">{{ s__('AlertManagement|None') }}</div>
</template> </template>

View file

@ -7,15 +7,12 @@ import {
GlSearchBoxByType, GlSearchBoxByType,
GlTooltipDirective as GlTooltip, GlTooltipDirective as GlTooltip,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { cloneDeep } from 'lodash'; import { cloneDeep, isEqual } from 'lodash';
import Vue from 'vue'; import Vue from 'vue';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import { import { mappingFields } from '../constants';
getMappingData, import { getMappingData, transformForSave } from '../utils/mapping_transformations';
getPayloadFields,
transformForSave,
} from '../utils/mapping_transformations';
export const i18n = { export const i18n = {
columns: { columns: {
@ -33,6 +30,7 @@ export const i18n = {
export default { export default {
i18n, i18n,
mappingFields,
components: { components: {
GlIcon, GlIcon,
GlFormInput, GlFormInput,
@ -73,18 +71,15 @@ export default {
}; };
}, },
computed: { computed: {
payloadFields() {
return getPayloadFields(this.parsedPayload);
},
mappingData() { mappingData() {
return getMappingData(this.gitlabFields, this.payloadFields, this.savedMapping); return getMappingData(this.gitlabFields, this.parsedPayload, this.savedMapping);
}, },
hasFallbackColumn() { hasFallbackColumn() {
return this.gitlabFields.some(({ numberOfFallbacks }) => Boolean(numberOfFallbacks)); return this.gitlabFields.some(({ numberOfFallbacks }) => Boolean(numberOfFallbacks));
}, },
}, },
methods: { methods: {
setMapping(gitlabKey, mappingKey, valueKey) { setMapping(gitlabKey, mappingKey, valueKey = mappingFields.mapping) {
const fieldIndex = this.gitlabFields.findIndex((field) => field.name === gitlabKey); const fieldIndex = this.gitlabFields.findIndex((field) => field.name === gitlabKey);
const updatedField = { ...this.gitlabFields[fieldIndex], ...{ [valueKey]: mappingKey } }; const updatedField = { ...this.gitlabFields[fieldIndex], ...{ [valueKey]: mappingKey } };
Vue.set(this.gitlabFields, fieldIndex, updatedField); Vue.set(this.gitlabFields, fieldIndex, updatedField);
@ -100,11 +95,11 @@ export default {
return fields.filter((field) => field.label.toLowerCase().includes(search)); return fields.filter((field) => field.label.toLowerCase().includes(search));
}, },
isSelected(fieldValue, mapping) { isSelected(fieldValue, mapping) {
return fieldValue === mapping; return isEqual(fieldValue, mapping);
}, },
selectedValue(name) { selectedValue(mapping) {
return ( return (
this.payloadFields.find((item) => item.name === name)?.label || this.parsedPayload.find((item) => isEqual(item.path, mapping))?.label ||
this.$options.i18n.makeSelection this.$options.i18n.makeSelection
); );
}, },
@ -150,7 +145,7 @@ export default {
:key="gitlabField.name" :key="gitlabField.name"
class="gl-display-table-row" class="gl-display-table-row"
> >
<div class="gl-display-table-cell gl-py-3 gl-pr-3 w-30p gl-vertical-align-middle"> <div class="gl-display-table-cell gl-py-3 gl-pr-3 gl-w-30p gl-vertical-align-middle">
<gl-form-input <gl-form-input
aria-labelledby="gitlabFieldsHeader" aria-labelledby="gitlabFieldsHeader"
disabled disabled
@ -164,7 +159,7 @@ export default {
</div> </div>
</div> </div>
<div class="gl-display-table-cell gl-py-3 gl-pr-3 w-30p gl-vertical-align-middle"> <div class="gl-display-table-cell gl-py-3 gl-pr-3 gl-w-30p gl-vertical-align-middle">
<gl-dropdown <gl-dropdown
:disabled="!gitlabField.mappingFields.length" :disabled="!gitlabField.mappingFields.length"
aria-labelledby="parsedFieldsHeader" aria-labelledby="parsedFieldsHeader"
@ -175,10 +170,10 @@ export default {
<gl-search-box-by-type @input="setSearchTerm($event, 'searchTerm', gitlabField.name)" /> <gl-search-box-by-type @input="setSearchTerm($event, 'searchTerm', gitlabField.name)" />
<gl-dropdown-item <gl-dropdown-item
v-for="mappingField in filterFields(gitlabField.searchTerm, gitlabField.mappingFields)" v-for="mappingField in filterFields(gitlabField.searchTerm, gitlabField.mappingFields)"
:key="`${mappingField.name}__mapping`" :key="`${mappingField.path}__mapping`"
:is-checked="isSelected(gitlabField.mapping, mappingField.name)" :is-checked="isSelected(gitlabField.mapping, mappingField.path)"
is-check-item is-check-item
@click="setMapping(gitlabField.name, mappingField.name, 'mapping')" @click="setMapping(gitlabField.name, mappingField.path)"
> >
{{ mappingField.label }} {{ mappingField.label }}
</gl-dropdown-item> </gl-dropdown-item>
@ -188,7 +183,7 @@ export default {
</gl-dropdown> </gl-dropdown>
</div> </div>
<div class="gl-display-table-cell gl-py-3 w-30p"> <div class="gl-display-table-cell gl-py-3 gl-w-30p">
<gl-dropdown <gl-dropdown
v-if="Boolean(gitlabField.numberOfFallbacks)" v-if="Boolean(gitlabField.numberOfFallbacks)"
:disabled="!gitlabField.mappingFields.length" :disabled="!gitlabField.mappingFields.length"
@ -205,10 +200,12 @@ export default {
gitlabField.fallbackSearchTerm, gitlabField.fallbackSearchTerm,
gitlabField.mappingFields, gitlabField.mappingFields,
)" )"
:key="`${mappingField.name}__fallback`" :key="`${mappingField.path}__fallback`"
:is-checked="isSelected(gitlabField.fallback, mappingField.name)" :is-checked="isSelected(gitlabField.fallback, mappingField.path)"
is-check-item is-check-item
@click="setMapping(gitlabField.name, mappingField.name, 'fallback')" @click="
setMapping(gitlabField.name, mappingField.path, $options.mappingFields.fallback)
"
> >
{{ mappingField.label }} {{ mappingField.label }}
</gl-dropdown-item> </gl-dropdown-item>

View file

@ -10,6 +10,7 @@ import {
GlTooltipDirective, GlTooltipDirective,
GlSprintf, GlSprintf,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { capitalize } from 'lodash';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { import {
@ -77,6 +78,7 @@ export default {
{ {
key: 'type', key: 'type',
label: __('Type'), label: __('Type'),
formatter: (value) => (value === typeSet.prometheus ? capitalize(value) : value),
}, },
{ {
key: 'actions', key: 'actions',
@ -120,14 +122,17 @@ export default {
const { category, action } = trackAlertIntegrationsViewsOptions; const { category, action } = trackAlertIntegrationsViewsOptions;
Tracking.event(category, action); Tracking.event(category, action);
}, },
setIntegrationToDelete({ name, id }) { setIntegrationToDelete(integration) {
this.integrationToDelete.id = id; this.integrationToDelete = integration;
this.integrationToDelete.name = name;
}, },
deleteIntegration() { deleteIntegration() {
this.$emit('delete-integration', { id: this.integrationToDelete.id }); const { id, type } = this.integrationToDelete;
this.$emit('delete-integration', { id, type });
this.integrationToDelete = { ...integrationToDeleteDefault }; this.integrationToDelete = { ...integrationToDeleteDefault };
}, },
editIntegration({ id, type }) {
this.$emit('edit-integration', { id, type });
},
}, },
}; };
</script> </script>
@ -169,7 +174,7 @@ export default {
<template #cell(actions)="{ item }"> <template #cell(actions)="{ item }">
<gl-button-group class="gl-ml-3"> <gl-button-group class="gl-ml-3">
<gl-button icon="pencil" @click="$emit('edit-integration', { id: item.id })" /> <gl-button icon="settings" @click="editIntegration(item)" />
<gl-button <gl-button
v-gl-modal.deleteIntegration v-gl-modal.deleteIntegration
:disabled="item.type === $options.typeSet.prometheus" :disabled="item.type === $options.typeSet.prometheus"

View file

@ -1,7 +1,6 @@
<script> <script>
import { import {
GlButton, GlButton,
GlCollapse,
GlForm, GlForm,
GlFormGroup, GlFormGroup,
GlFormSelect, GlFormSelect,
@ -11,98 +10,39 @@ import {
GlModal, GlModal,
GlModalDirective, GlModalDirective,
GlToggle, GlToggle,
GlTabs,
GlTab,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { s__ } from '~/locale'; import * as Sentry from '@sentry/browser';
import { isEmpty, omit } from 'lodash';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { import {
integrationTypes, integrationTypes,
integrationSteps,
createStepNumbers,
editStepNumbers,
JSON_VALIDATE_DELAY, JSON_VALIDATE_DELAY,
targetPrometheusUrlPlaceholder, targetPrometheusUrlPlaceholder,
typeSet, typeSet,
viewCredentialsTabIndex,
i18n,
} from '../constants'; } from '../constants';
import getCurrentIntegrationQuery from '../graphql/queries/get_current_integration.query.graphql'; import getCurrentIntegrationQuery from '../graphql/queries/get_current_integration.query.graphql';
import parseSamplePayloadQuery from '../graphql/queries/parse_sample_payload.query.graphql';
import MappingBuilder from './alert_mapping_builder.vue'; import MappingBuilder from './alert_mapping_builder.vue';
import AlertSettingsFormHelpBlock from './alert_settings_form_help_block.vue'; import AlertSettingsFormHelpBlock from './alert_settings_form_help_block.vue';
// Mocks will be removed when integrating with BE is ready
// data format is defined and will be the same as mocked (maybe with some minor changes)
// feature rollout plan - https://gitlab.com/gitlab-org/gitlab/-/issues/262707#note_442529171
import mockedCustomMapping from './mocks/parsedMapping.json';
export const i18n = {
integrationFormSteps: {
step1: {
label: s__('AlertSettings|1. Select integration type'),
enterprise: s__(
'AlertSettings|In free versions of GitLab, only one integration for each type can be added. %{linkStart}Upgrade your subscription%{linkEnd} to add additional integrations.',
),
},
step2: {
label: s__('AlertSettings|2. Name integration'),
placeholder: s__('AlertSettings|Enter integration name'),
prometheus: s__('AlertSettings|Prometheus'),
},
step3: {
label: s__('AlertSettings|3. Set up webhook'),
help: s__(
"AlertSettings|Utilize the URL and authorization key below to authorize an external service to send alerts to GitLab. Review your external service's documentation to learn where to add these details, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.",
),
prometheusHelp: s__(
'AlertSettings|Utilize the URL and authorization key below to authorize Prometheus to send alerts to GitLab. Review the Prometheus documentation to learn where to add these details, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.',
),
info: s__('AlertSettings|Authorization key'),
reset: s__('AlertSettings|Reset Key'),
},
step4: {
label: s__('AlertSettings|4. Sample alert payload (optional)'),
help: s__(
'AlertSettings|Provide an example payload from the monitoring tool you intend to integrate with. This payload can be used to create a custom mapping (optional), or to test the integration (also optional).',
),
prometheusHelp: s__(
'AlertSettings|Provide an example payload from the monitoring tool you intend to integrate with. This payload can be used to test the integration (optional).',
),
placeholder: s__('AlertSettings|{ "events": [{ "application": "Name of application" }] }'),
resetHeader: s__('AlertSettings|Reset the mapping'),
resetBody: s__(
"AlertSettings|If you edit the payload, the stored mapping will be reset, and you'll need to re-map the fields.",
),
resetOk: s__('AlertSettings|Proceed with editing'),
editPayload: s__('AlertSettings|Edit payload'),
submitPayload: s__('AlertSettings|Submit payload'),
payloadParsedSucessMsg: s__(
'AlertSettings|Sample payload has been parsed. You can now map the fields.',
),
},
step5: {
label: s__('AlertSettings|5. Map fields (optional)'),
intro: s__(
"AlertSettings|If you've provided a sample alert payload, you can create a custom mapping for your endpoint. The default GitLab alert keys are listed below. Please define which payload key should map to the specified GitLab key.",
),
},
prometheusFormUrl: {
label: s__('AlertSettings|Prometheus API base URL'),
help: s__('AlertSettings|URL cannot be blank and must start with http or https'),
},
restKeyInfo: {
label: s__(
'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.',
),
},
},
};
export default { export default {
integrationTypes,
placeholders: { placeholders: {
prometheus: targetPrometheusUrlPlaceholder, prometheus: targetPrometheusUrlPlaceholder,
}, },
JSON_VALIDATE_DELAY, JSON_VALIDATE_DELAY,
typeSet, typeSet,
integrationSteps,
i18n, i18n,
components: { components: {
ClipboardButton, ClipboardButton,
GlButton, GlButton,
GlCollapse,
GlForm, GlForm,
GlFormGroup, GlFormGroup,
GlFormInput, GlFormInput,
@ -111,13 +51,14 @@ export default {
GlFormSelect, GlFormSelect,
GlModal, GlModal,
GlToggle, GlToggle,
GlTabs,
GlTab,
AlertSettingsFormHelpBlock, AlertSettingsFormHelpBlock,
MappingBuilder, MappingBuilder,
}, },
directives: { directives: {
GlModal: GlModalDirective, GlModal: GlModalDirective,
}, },
mixins: [glFeatureFlagsMixin()],
inject: { inject: {
generic: { generic: {
default: {}, default: {},
@ -128,6 +69,9 @@ export default {
multiIntegrations: { multiIntegrations: {
default: false, default: false,
}, },
projectPath: {
default: '',
},
}, },
props: { props: {
loading: { loading: {
@ -151,26 +95,40 @@ export default {
}, },
data() { data() {
return { return {
selectedIntegration: integrationTypes[0].value, integrationTypesOptions: Object.values(integrationTypes),
selectedIntegration: integrationTypes.none.value,
active: false, active: false,
formVisible: false, samplePayload: {
integrationTestPayload: {
json: null, json: null,
error: null, error: null,
}, },
resetSamplePayloadConfirmed: false, testPayload: {
customMapping: null, json: null,
error: null,
},
resetPayloadAndMappingConfirmed: false,
mapping: [], mapping: [],
parsingPayload: false, parsingPayload: false,
currentIntegration: null, currentIntegration: null,
parsedPayload: [],
activeTabIndex: 0,
}; };
}, },
computed: { computed: {
isPrometheus() { isPrometheus() {
return this.selectedIntegration === this.$options.typeSet.prometheus; return this.selectedIntegration === this.$options.typeSet.prometheus;
}, },
jsonIsValid() { isHttp() {
return this.integrationTestPayload.error === null; return this.selectedIntegration === this.$options.typeSet.http;
},
isCreating() {
return !this.currentIntegration;
},
isSampePayloadValid() {
return this.samplePayload.error === null;
},
isTestPayloadValid() {
return this.testPayload.error === null;
}, },
selectedIntegrationType() { selectedIntegrationType() {
switch (this.selectedIntegration) { switch (this.selectedIntegration) {
@ -197,90 +155,88 @@ export default {
}, },
testAlertPayload() { testAlertPayload() {
return { return {
data: this.integrationTestPayload.json, data: this.testPayload.json,
endpoint: this.integrationForm.url, endpoint: this.integrationForm.url,
token: this.integrationForm.token, token: this.integrationForm.token,
}; };
}, },
showMappingBuilder() { showMappingBuilder() {
return ( return this.multiIntegrations && this.isHttp && this.alertFields?.length;
this.multiIntegrations &&
this.glFeatures.multipleHttpIntegrationsCustomMapping &&
this.selectedIntegration === typeSet.http &&
this.alertFields?.length
);
},
parsedSamplePayload() {
return this.customMapping?.samplePayload?.payloadAlerFields?.nodes;
},
savedMapping() {
return this.customMapping?.storedMapping?.nodes;
}, },
hasSamplePayload() { hasSamplePayload() {
return Boolean(this.customMapping?.samplePayload); return this.isValidNonEmptyJSON(this.currentIntegration?.payloadExample);
}, },
canEditPayload() { canEditPayload() {
return this.hasSamplePayload && !this.resetSamplePayloadConfirmed; return this.hasSamplePayload && !this.resetPayloadAndMappingConfirmed;
},
canParseSamplePayload() {
return !this.active || !this.isSampePayloadValid || !this.samplePayload.json;
}, },
isResetAuthKeyDisabled() { isResetAuthKeyDisabled() {
return !this.active && !this.integrationForm.token !== ''; return !this.active && !this.integrationForm.token !== '';
}, },
isPayloadEditDisabled() { isPayloadEditDisabled() {
return this.glFeatures.multipleHttpIntegrationsCustomMapping return !this.active || this.canEditPayload;
? !this.active || this.canEditPayload
: !this.active;
},
isSubmitTestPayloadDisabled() {
return (
!this.active ||
Boolean(this.integrationTestPayload.error) ||
this.integrationTestPayload.json === ''
);
}, },
isSelectDisabled() { isSelectDisabled() {
return this.currentIntegration !== null || !this.canAddIntegration; return this.currentIntegration !== null || !this.canAddIntegration;
}, },
viewCredentialsHelpMsg() {
return this.isPrometheus
? i18n.integrationFormSteps.setupCredentials.prometheusHelp
: i18n.integrationFormSteps.setupCredentials.help;
},
}, },
watch: { watch: {
currentIntegration(val) { currentIntegration(val) {
if (val === null) { if (val === null) {
return this.reset(); this.reset();
return;
} }
this.selectedIntegration = val.type; const { type, active, payloadExample, payloadAlertFields, payloadAttributeMappings } = val;
this.active = val.active; this.selectedIntegration = type;
if (val.type === typeSet.http && this.showMappingBuilder) this.getIntegrationMapping(val.id); this.active = active;
return this.integrationTypeSelect();
if (type === typeSet.http && this.showMappingBuilder) {
this.parsedPayload = payloadAlertFields;
this.samplePayload.json = this.isValidNonEmptyJSON(payloadExample) ? payloadExample : null;
const mapping = payloadAttributeMappings.map((mappingItem) =>
omit(mappingItem, '__typename'),
);
this.updateMapping(mapping);
}
this.activeTabIndex = viewCredentialsTabIndex;
this.$el.scrollIntoView({ block: 'center' });
}, },
}, },
methods: { methods: {
integrationTypeSelect() { isValidNonEmptyJSON(JSONString) {
if (this.selectedIntegration === integrationTypes[0].value) { if (JSONString) {
this.formVisible = false; let parsed;
} else { try {
this.formVisible = true; parsed = JSON.parse(JSONString);
} catch (error) {
Sentry.captureException(error);
} }
if (parsed) return !isEmpty(parsed);
}
return false;
}, },
submitWithTestPayload() { sendTestAlert() {
this.$emit('set-test-alert-payload', this.testAlertPayload); this.$emit('test-alert-payload', this.testAlertPayload);
this.submit();
}, },
submit() { submit() {
const { name, apiUrl } = this.integrationForm; const { name, apiUrl } = this.integrationForm;
const customMappingVariables = this.glFeatures.multipleHttpIntegrationsCustomMapping const customMappingVariables = {
? {
payloadAttributeMappings: this.mapping, payloadAttributeMappings: this.mapping,
payloadExample: this.integrationTestPayload.json, payloadExample: this.samplePayload.json || '{}',
} };
: {};
const variables = const variables =
this.selectedIntegration === typeSet.http this.selectedIntegration === typeSet.http
? { ? { name, active: this.active, ...customMappingVariables }
name,
active: this.active,
...customMappingVariables,
}
: { apiUrl, active: this.active }; : { apiUrl, active: this.active };
const integrationPayload = { type: this.selectedIntegration, variables }; const integrationPayload = { type: this.selectedIntegration, variables };
if (this.currentIntegration) { if (this.currentIntegration) {
@ -291,19 +247,15 @@ export default {
return this.$emit('create-new-integration', integrationPayload); return this.$emit('create-new-integration', integrationPayload);
}, },
reset() { reset() {
this.selectedIntegration = integrationTypes[0].value; this.resetFormValues();
this.integrationTypeSelect(); this.resetPayloadAndMapping();
this.$emit('clear-current-integration', { type: this.currentIntegration?.type });
if (this.currentIntegration) {
return this.$emit('clear-current-integration');
}
return this.resetFormValues();
}, },
resetFormValues() { resetFormValues() {
this.selectedIntegration = integrationTypes.none.value;
this.integrationForm.name = ''; this.integrationForm.name = '';
this.integrationForm.apiUrl = ''; this.integrationForm.apiUrl = '';
this.integrationTestPayload = { this.samplePayload = {
json: null, json: null,
error: null, error: null,
}; };
@ -319,117 +271,135 @@ export default {
variables: { id: this.currentIntegration.id }, variables: { id: this.currentIntegration.id },
}); });
}, },
validateJson() { validateJson(isSamplePayload = true) {
this.integrationTestPayload.error = null; const payload = isSamplePayload ? this.samplePayload : this.testPayload;
if (this.integrationTestPayload.json === '') {
payload.error = null;
if (payload.json === '') {
return; return;
} }
try { try {
JSON.parse(this.integrationTestPayload.json); JSON.parse(payload.json);
} catch (e) { } catch (e) {
this.integrationTestPayload.error = JSON.stringify(e.message); payload.error = JSON.stringify(e.message);
} }
}, },
parseMapping() { parseMapping() {
// TODO: replace with real BE mutation when ready;
this.parsingPayload = true; this.parsingPayload = true;
return new Promise((resolve) => { return this.$apollo
setTimeout(() => resolve(mockedCustomMapping), 1000); .query({
query: parseSamplePayloadQuery,
variables: { projectPath: this.projectPath, payload: this.samplePayload.json },
}) })
.then((res) => { .then(
const mapping = { ...res }; ({
delete mapping.storedMapping; data: {
this.customMapping = res; project: { alertManagementPayloadFields },
this.integrationTestPayload.json = res?.samplePayload.body; },
this.resetSamplePayloadConfirmed = false; }) => {
this.parsedPayload = alertManagementPayloadFields;
this.resetPayloadAndMappingConfirmed = false;
this.$toast.show(this.$options.i18n.integrationFormSteps.step4.payloadParsedSucessMsg); this.$toast.show(
this.$options.i18n.integrationFormSteps.setSamplePayload.payloadParsedSucessMsg,
);
},
)
.catch(({ message }) => {
this.samplePayload.error = message;
}) })
.finally(() => { .finally(() => {
this.parsingPayload = false; this.parsingPayload = false;
}); });
}, },
getIntegrationMapping() {
// TODO: replace with real BE mutation when ready;
return Promise.resolve(mockedCustomMapping).then((res) => {
this.customMapping = res;
this.integrationTestPayload.json = res?.samplePayload.body;
});
},
updateMapping(mapping) { updateMapping(mapping) {
this.mapping = mapping; this.mapping = mapping;
}, },
resetPayloadAndMapping() {
this.resetPayloadAndMappingConfirmed = true;
this.parsedPayload = [];
this.updateMapping([]);
},
getLabelWithStepNumber(step, label) {
let stepNumber = editStepNumbers[step];
if (this.isCreating) {
stepNumber = createStepNumbers[step];
}
return stepNumber ? `${stepNumber}.${label}` : label;
},
}, },
}; };
</script> </script>
<template> <template>
<gl-form class="gl-mt-6" @submit.prevent="submit" @reset.prevent="reset"> <gl-form class="gl-mt-6" @submit.prevent="submit" @reset.prevent="reset">
<h5 class="gl-font-lg gl-my-5">{{ s__('AlertSettings|Add new integrations') }}</h5> <gl-tabs v-model="activeTabIndex">
<gl-tab :title="$options.i18n.integrationTabs.configureDetails">
<gl-form-group <gl-form-group
v-if="isCreating"
id="integration-type" id="integration-type"
:label="$options.i18n.integrationFormSteps.step1.label" :label="
getLabelWithStepNumber(
$options.integrationSteps.selectType,
$options.i18n.integrationFormSteps.selectType.label,
)
"
label-for="integration-type" label-for="integration-type"
> >
<gl-form-select <gl-form-select
v-model="selectedIntegration" v-model="selectedIntegration"
:disabled="isSelectDisabled" :disabled="isSelectDisabled"
class="mw-100" class="gl-max-w-full"
:options="$options.integrationTypes" :options="integrationTypesOptions"
@change="integrationTypeSelect"
/> />
<div v-if="!canAddIntegration" class="gl-my-4" data-testid="multi-integrations-not-supported">
<alert-settings-form-help-block <alert-settings-form-help-block
:message="$options.i18n.integrationFormSteps.step1.enterprise" v-if="!canAddIntegration"
disabled="true"
class="gl-display-inline-block gl-my-4"
:message="$options.i18n.integrationFormSteps.selectType.enterprise"
link="https://about.gitlab.com/pricing" link="https://about.gitlab.com/pricing"
data-testid="multi-integrations-not-supported"
/> />
</div>
</gl-form-group> </gl-form-group>
<gl-collapse v-model="formVisible" class="gl-mt-3"> <div class="gl-mt-3">
<div>
<gl-form-group <gl-form-group
v-if="isHttp"
id="name-integration" id="name-integration"
:label="$options.i18n.integrationFormSteps.step2.label" :label="
getLabelWithStepNumber(
$options.integrationSteps.nameIntegration,
$options.i18n.integrationFormSteps.nameIntegration.label,
)
"
label-for="name-integration" label-for="name-integration"
> >
<gl-form-input <gl-form-input
v-model="integrationForm.name" v-model="integrationForm.name"
:disabled="isPrometheus"
type="text" type="text"
:placeholder=" :placeholder="$options.i18n.integrationFormSteps.nameIntegration.placeholder"
isPrometheus
? $options.i18n.integrationFormSteps.step2.prometheus
: $options.i18n.integrationFormSteps.step2.placeholder
"
/> />
</gl-form-group> </gl-form-group>
<gl-form-group
id="integration-webhook"
:label="$options.i18n.integrationFormSteps.step3.label"
label-for="integration-webhook"
>
<alert-settings-form-help-block
:message="
isPrometheus
? $options.i18n.integrationFormSteps.step3.prometheusHelp
: $options.i18n.integrationFormSteps.step3.help
"
link="https://docs.gitlab.com/ee/operations/incident_management/alert_integrations.html"
/>
<gl-toggle <gl-toggle
v-model="active" v-model="active"
:is-loading="loading" :is-loading="loading"
:label="__('Active')" :label="$options.i18n.integrationFormSteps.nameIntegration.activeToggle"
class="gl-my-4 gl-font-weight-normal" class="gl-my-4 gl-font-weight-normal"
/> />
<div v-if="isPrometheus" class="gl-my-4"> <div v-if="isPrometheus" class="gl-my-4">
<span class="gl-font-weight-bold"> <span class="gl-font-weight-bold">
{{ $options.i18n.integrationFormSteps.prometheusFormUrl.label }} {{
getLabelWithStepNumber(
$options.integrationSteps.setPrometheusApiUrl,
$options.i18n.integrationFormSteps.prometheusFormUrl.label,
)
}}
</span> </span>
<gl-form-input <gl-form-input
@ -444,16 +414,123 @@ export default {
</span> </span>
</div> </div>
<template v-if="showMappingBuilder">
<gl-form-group
data-testid="sample-payload-section"
:label="
getLabelWithStepNumber(
$options.integrationSteps.setSamplePayload,
$options.i18n.integrationFormSteps.setSamplePayload.label,
)
"
label-for="sample-payload"
class="gl-mb-0!"
:invalid-feedback="samplePayload.error"
>
<alert-settings-form-help-block
:message="$options.i18n.integrationFormSteps.setSamplePayload.testPayloadHelpHttp"
:link="generic.alertsUsageUrl"
/>
<gl-form-textarea
id="sample-payload"
v-model.trim="samplePayload.json"
:disabled="isPayloadEditDisabled"
:state="isSampePayloadValid"
:placeholder="$options.i18n.integrationFormSteps.setSamplePayload.placeholder"
class="gl-my-3"
:debounce="$options.JSON_VALIDATE_DELAY"
rows="6"
max-rows="10"
@input="validateJson"
/>
</gl-form-group>
<gl-button
v-if="canEditPayload"
v-gl-modal.resetPayloadModal
data-testid="payload-action-btn"
:disabled="!active"
class="gl-mt-3"
>
{{ $options.i18n.integrationFormSteps.setSamplePayload.editPayload }}
</gl-button>
<gl-button
v-else
data-testid="payload-action-btn"
:class="{ 'gl-mt-3': samplePayload.error }"
:disabled="canParseSamplePayload"
:loading="parsingPayload"
@click="parseMapping"
>
{{ $options.i18n.integrationFormSteps.setSamplePayload.parsePayload }}
</gl-button>
<gl-modal
modal-id="resetPayloadModal"
:title="$options.i18n.integrationFormSteps.setSamplePayload.resetHeader"
:ok-title="$options.i18n.integrationFormSteps.setSamplePayload.resetOk"
ok-variant="danger"
@ok="resetPayloadAndMapping"
>
{{ $options.i18n.integrationFormSteps.setSamplePayload.resetBody }}
</gl-modal>
<gl-form-group
id="mapping-builder"
class="gl-mt-5"
:label="
getLabelWithStepNumber(
$options.integrationSteps.customizeMapping,
$options.i18n.integrationFormSteps.mapFields.label,
)
"
label-for="mapping-builder"
>
<span>{{ $options.i18n.integrationFormSteps.mapFields.intro }}</span>
<mapping-builder
:parsed-payload="parsedPayload"
:saved-mapping="mapping"
:alert-fields="alertFields"
@onMappingUpdate="updateMapping"
/>
</gl-form-group>
</template>
</div>
<div class="gl-display-flex gl-justify-content-start gl-py-3">
<gl-button
type="submit"
variant="confirm"
class="js-no-auto-disable"
data-testid="integration-form-submit"
>
{{ $options.i18n.saveIntegration }}
</gl-button>
<gl-button type="reset" class="gl-ml-3 js-no-auto-disable">{{
$options.i18n.cancelAndClose
}}</gl-button>
</div>
</gl-tab>
<gl-tab :title="$options.i18n.integrationTabs.viewCredentials" :disabled="isCreating">
<alert-settings-form-help-block
:message="viewCredentialsHelpMsg"
link="https://docs.gitlab.com/ee/operations/incident_management/alert_integrations.html"
/>
<gl-form-group id="integration-webhook">
<div class="gl-my-4"> <div class="gl-my-4">
<span class="gl-font-weight-bold"> <span class="gl-font-weight-bold">
{{ s__('AlertSettings|Webhook URL') }} {{ $options.i18n.integrationFormSteps.setupCredentials.webhookUrl }}
</span> </span>
<gl-form-input-group id="url" readonly :value="integrationForm.url"> <gl-form-input-group id="url" readonly :value="integrationForm.url">
<template #append> <template #append>
<clipboard-button <clipboard-button
:text="integrationForm.url || ''" :text="integrationForm.url || ''"
:title="__('Copy')" :title="$options.i18n.copy"
class="gl-m-0!" class="gl-m-0!"
/> />
</template> </template>
@ -462,7 +539,7 @@ export default {
<div class="gl-my-4"> <div class="gl-my-4">
<span class="gl-font-weight-bold"> <span class="gl-font-weight-bold">
{{ $options.i18n.integrationFormSteps.step3.info }} {{ $options.i18n.integrationFormSteps.setupCredentials.authorizationKey }}
</span> </span>
<gl-form-input-group <gl-form-input-group
@ -474,124 +551,67 @@ export default {
<template #append> <template #append>
<clipboard-button <clipboard-button
:text="integrationForm.token || ''" :text="integrationForm.token || ''"
:title="__('Copy')" :title="$options.i18n.copy"
class="gl-m-0!" class="gl-m-0!"
/> />
</template> </template>
</gl-form-input-group> </gl-form-input-group>
</div>
</gl-form-group>
<gl-button v-gl-modal.authKeyModal :disabled="isResetAuthKeyDisabled"> <gl-button v-gl-modal.authKeyModal :disabled="isResetAuthKeyDisabled" variant="danger">
{{ $options.i18n.integrationFormSteps.step3.reset }} {{ $options.i18n.integrationFormSteps.setupCredentials.reset }}
</gl-button> </gl-button>
<gl-button type="reset" class="gl-ml-3 js-no-auto-disable">{{
$options.i18n.cancelAndClose
}}</gl-button>
<gl-modal <gl-modal
modal-id="authKeyModal" modal-id="authKeyModal"
:title="$options.i18n.integrationFormSteps.step3.reset" :title="$options.i18n.integrationFormSteps.setupCredentials.reset"
:ok-title="$options.i18n.integrationFormSteps.step3.reset" :ok-title="$options.i18n.integrationFormSteps.setupCredentials.reset"
ok-variant="danger" ok-variant="danger"
@ok="resetAuthKey" @ok="resetAuthKey"
> >
{{ $options.i18n.integrationFormSteps.restKeyInfo.label }} {{ $options.i18n.integrationFormSteps.restKeyInfo.label }}
</gl-modal> </gl-modal>
</div> </gl-tab>
</gl-form-group>
<gl-form-group <gl-tab :title="$options.i18n.integrationTabs.sendTestAlert" :disabled="isCreating">
id="test-integration" <gl-form-group id="test-integration" :invalid-feedback="testPayload.error">
:label="$options.i18n.integrationFormSteps.step4.label"
label-for="test-integration"
:class="{ 'gl-mb-0!': showMappingBuilder }"
:invalid-feedback="integrationTestPayload.error"
>
<alert-settings-form-help-block <alert-settings-form-help-block
:message=" :message="$options.i18n.integrationFormSteps.setSamplePayload.testPayloadHelp"
isPrometheus || !showMappingBuilder
? $options.i18n.integrationFormSteps.step4.prometheusHelp
: $options.i18n.integrationFormSteps.step4.help
"
:link="generic.alertsUsageUrl" :link="generic.alertsUsageUrl"
/> />
<gl-form-textarea <gl-form-textarea
id="test-payload" id="test-payload"
v-model.trim="integrationTestPayload.json" v-model.trim="testPayload.json"
:disabled="isPayloadEditDisabled" :state="isTestPayloadValid"
:state="jsonIsValid" :placeholder="$options.i18n.integrationFormSteps.setSamplePayload.placeholder"
:placeholder="$options.i18n.integrationFormSteps.step4.placeholder"
class="gl-my-3" class="gl-my-3"
:debounce="$options.JSON_VALIDATE_DELAY" :debounce="$options.JSON_VALIDATE_DELAY"
rows="6" rows="6"
max-rows="10" max-rows="10"
@input="validateJson" @input="validateJson(false)"
/> />
</gl-form-group> </gl-form-group>
<template v-if="showMappingBuilder">
<gl-button <gl-button
v-if="canEditPayload" :disabled="!isTestPayloadValid"
v-gl-modal.resetPayloadModal data-testid="send-test-alert"
data-testid="payload-action-btn" variant="confirm"
:disabled="!active"
class="gl-mt-3"
>
{{ $options.i18n.integrationFormSteps.step4.editPayload }}
</gl-button>
<gl-button
v-else
data-testid="payload-action-btn"
:class="{ 'gl-mt-3': integrationTestPayload.error }"
:disabled="!active"
:loading="parsingPayload"
@click="parseMapping"
>
{{ $options.i18n.integrationFormSteps.step4.submitPayload }}
</gl-button>
<gl-modal
modal-id="resetPayloadModal"
:title="$options.i18n.integrationFormSteps.step4.resetHeader"
:ok-title="$options.i18n.integrationFormSteps.step4.resetOk"
ok-variant="danger"
@ok="resetSamplePayloadConfirmed = true"
>
{{ $options.i18n.integrationFormSteps.step4.resetBody }}
</gl-modal>
</template>
<gl-form-group
v-if="showMappingBuilder"
id="mapping-builder"
class="gl-mt-5"
:label="$options.i18n.integrationFormSteps.step5.label"
label-for="mapping-builder"
>
<span>{{ $options.i18n.integrationFormSteps.step5.intro }}</span>
<mapping-builder
:parsed-payload="parsedSamplePayload"
:saved-mapping="savedMapping"
:alert-fields="alertFields"
@onMappingUpdate="updateMapping"
/>
</gl-form-group>
</div>
<div class="gl-display-flex gl-justify-content-start gl-py-3">
<gl-button
type="submit"
variant="success"
class="js-no-auto-disable" class="js-no-auto-disable"
data-testid="integration-form-submit" @click="sendTestAlert"
>{{ s__('AlertSettings|Save integration') }}
</gl-button>
<gl-button
data-testid="integration-test-and-submit"
:disabled="isSubmitTestPayloadDisabled"
category="secondary"
variant="success"
class="gl-mx-3 js-no-auto-disable"
@click="submitWithTestPayload"
>{{ s__('AlertSettings|Save and test payload') }}</gl-button
> >
<gl-button type="reset" class="js-no-auto-disable">{{ __('Cancel') }}</gl-button> {{ $options.i18n.send }}
</div> </gl-button>
</gl-collapse>
<gl-button type="reset" class="gl-ml-3 js-no-auto-disable">{{
$options.i18n.cancelAndClose
}}</gl-button>
</gl-tab>
</gl-tabs>
</gl-form> </gl-form>
</template> </template>

View file

@ -1,22 +1,26 @@
<script> <script>
import { GlButton } from '@gitlab/ui';
import createHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql';
import updateHttpIntegrationMutation from 'ee_else_ce/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql';
import createFlash, { FLASH_TYPES } from '~/flash'; import createFlash, { FLASH_TYPES } from '~/flash';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { typeSet } from '../constants'; import { typeSet } from '../constants';
import createHttpIntegrationMutation from '../graphql/mutations/create_http_integration.mutation.graphql';
import createPrometheusIntegrationMutation from '../graphql/mutations/create_prometheus_integration.mutation.graphql'; import createPrometheusIntegrationMutation from '../graphql/mutations/create_prometheus_integration.mutation.graphql';
import destroyHttpIntegrationMutation from '../graphql/mutations/destroy_http_integration.mutation.graphql'; import destroyHttpIntegrationMutation from '../graphql/mutations/destroy_http_integration.mutation.graphql';
import resetHttpTokenMutation from '../graphql/mutations/reset_http_token.mutation.graphql'; import resetHttpTokenMutation from '../graphql/mutations/reset_http_token.mutation.graphql';
import resetPrometheusTokenMutation from '../graphql/mutations/reset_prometheus_token.mutation.graphql'; import resetPrometheusTokenMutation from '../graphql/mutations/reset_prometheus_token.mutation.graphql';
import updateCurrentIntergrationMutation from '../graphql/mutations/update_current_intergration.mutation.graphql'; import updateCurrentHttpIntegrationMutation from '../graphql/mutations/update_current_http_integration.mutation.graphql';
import updateHttpIntegrationMutation from '../graphql/mutations/update_http_integration.mutation.graphql'; import updateCurrentPrometheusIntegrationMutation from '../graphql/mutations/update_current_prometheus_integration.mutation.graphql';
import updatePrometheusIntegrationMutation from '../graphql/mutations/update_prometheus_integration.mutation.graphql'; import updatePrometheusIntegrationMutation from '../graphql/mutations/update_prometheus_integration.mutation.graphql';
import getCurrentIntegrationQuery from '../graphql/queries/get_current_integration.query.graphql'; import getCurrentIntegrationQuery from '../graphql/queries/get_current_integration.query.graphql';
import getHttpIntegrationsQuery from '../graphql/queries/get_http_integrations.query.graphql';
import getIntegrationsQuery from '../graphql/queries/get_integrations.query.graphql'; import getIntegrationsQuery from '../graphql/queries/get_integrations.query.graphql';
import service from '../services'; import service from '../services';
import { import {
updateStoreAfterIntegrationDelete, updateStoreAfterIntegrationDelete,
updateStoreAfterIntegrationAdd, updateStoreAfterIntegrationAdd,
updateStoreAfterHttpIntegrationAdd,
} from '../utils/cache_updates'; } from '../utils/cache_updates';
import { import {
DELETE_INTEGRATION_ERROR, DELETE_INTEGRATION_ERROR,
@ -28,9 +32,7 @@ import {
import IntegrationsList from './alerts_integrations_list.vue'; import IntegrationsList from './alerts_integrations_list.vue';
import AlertSettingsForm from './alerts_settings_form.vue'; import AlertSettingsForm from './alerts_settings_form.vue';
export default { export const i18n = {
typeSet,
i18n: {
changesSaved: s__( changesSaved: s__(
'AlertsIntegrations|The integration has been successfully saved. Alerts from this new integration should now appear on your alerts list.', 'AlertsIntegrations|The integration has been successfully saved. Alerts from this new integration should now appear on your alerts list.',
), ),
@ -38,10 +40,16 @@ export default {
alertSent: s__( alertSent: s__(
'AlertsIntegrations|The test alert has been successfully sent, and should now be visible on your alerts list.', 'AlertsIntegrations|The test alert has been successfully sent, and should now be visible on your alerts list.',
), ),
}, addNewIntegration: s__('AlertSettings|Add new integration'),
};
export default {
typeSet,
i18n,
components: { components: {
IntegrationsList, IntegrationsList,
AlertSettingsForm, AlertSettingsForm,
GlButton,
}, },
inject: { inject: {
generic: { generic: {
@ -84,6 +92,28 @@ export default {
createFlash({ message: err }); createFlash({ message: err });
}, },
}, },
// TODO: we'll need to update the logic to request specific http integration by its id on edit
// when BE adds support for it https://gitlab.com/gitlab-org/gitlab/-/issues/321674
// currently the request for ALL http integrations is made and on specific integration edit we search it in the list
httpIntegrations: {
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
query: getHttpIntegrationsQuery,
variables() {
return {
projectPath: this.projectPath,
};
},
update(data) {
const { alertManagementHttpIntegrations: { nodes: list = [] } = {} } = data.project || {};
return {
list,
};
},
error(err) {
createFlash({ message: err });
},
},
currentIntegration: { currentIntegration: {
query: getCurrentIntegrationQuery, query: getCurrentIntegrationQuery,
}, },
@ -91,9 +121,10 @@ export default {
data() { data() {
return { return {
isUpdating: false, isUpdating: false,
testAlertPayload: null,
integrations: {}, integrations: {},
httpIntegrations: {},
currentIntegration: null, currentIntegration: null,
formVisible: false,
}; };
}, },
computed: { computed: {
@ -105,22 +136,28 @@ export default {
}, },
}, },
methods: { methods: {
isHttp(type) {
return type === typeSet.http;
},
createNewIntegration({ type, variables }) { createNewIntegration({ type, variables }) {
const { projectPath } = this; const { projectPath } = this;
const isHttp = this.isHttp(type);
this.isUpdating = true; this.isUpdating = true;
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: mutation: isHttp ? createHttpIntegrationMutation : createPrometheusIntegrationMutation,
type === this.$options.typeSet.http
? createHttpIntegrationMutation
: createPrometheusIntegrationMutation,
variables: { variables: {
...variables, ...variables,
projectPath, projectPath,
}, },
update(store, { data }) { update(store, { data }) {
updateStoreAfterIntegrationAdd(store, getIntegrationsQuery, data, { projectPath }); updateStoreAfterIntegrationAdd(store, getIntegrationsQuery, data, { projectPath });
if (isHttp) {
updateStoreAfterHttpIntegrationAdd(store, getHttpIntegrationsQuery, data, {
projectPath,
});
}
}, },
}) })
.then(({ data: { httpIntegrationCreate, prometheusIntegrationCreate } = {} } = {}) => { .then(({ data: { httpIntegrationCreate, prometheusIntegrationCreate } = {} } = {}) => {
@ -128,18 +165,9 @@ export default {
if (error) { if (error) {
return createFlash({ message: error }); return createFlash({ message: error });
} }
const { integration } = httpIntegrationCreate || prometheusIntegrationCreate;
if (this.testAlertPayload) { this.editIntegration(integration);
const integration =
httpIntegrationCreate?.integration || prometheusIntegrationCreate?.integration;
const payload = {
...this.testAlertPayload,
endpoint: integration.url,
token: integration.token,
};
return this.validateAlertPayload(payload);
}
return createFlash({ return createFlash({
message: this.$options.i18n.changesSaved, message: this.$options.i18n.changesSaved,
@ -157,8 +185,7 @@ export default {
this.isUpdating = true; this.isUpdating = true;
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: mutation: this.isHttp(type)
type === this.$options.typeSet.http
? updateHttpIntegrationMutation ? updateHttpIntegrationMutation
: updatePrometheusIntegrationMutation, : updatePrometheusIntegrationMutation,
variables: { variables: {
@ -172,11 +199,7 @@ export default {
return createFlash({ message: error }); return createFlash({ message: error });
} }
if (this.testAlertPayload) { this.clearCurrentIntegration({ type });
return this.validateAlertPayload();
}
this.clearCurrentIntegration();
return createFlash({ return createFlash({
message: this.$options.i18n.changesSaved, message: this.$options.i18n.changesSaved,
@ -188,23 +211,19 @@ export default {
}) })
.finally(() => { .finally(() => {
this.isUpdating = false; this.isUpdating = false;
this.testAlertPayload = null;
}); });
}, },
resetToken({ type, variables }) { resetToken({ type, variables }) {
this.isUpdating = true; this.isUpdating = true;
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: mutation: this.isHttp(type) ? resetHttpTokenMutation : resetPrometheusTokenMutation,
type === this.$options.typeSet.http
? resetHttpTokenMutation
: resetPrometheusTokenMutation,
variables, variables,
}) })
.then( .then(
({ data: { httpIntegrationResetToken, prometheusIntegrationResetToken } = {} } = {}) => { ({ data: { httpIntegrationResetToken, prometheusIntegrationResetToken } = {} } = {}) => {
const error = const [error] =
httpIntegrationResetToken?.errors[0] || prometheusIntegrationResetToken?.errors[0]; httpIntegrationResetToken?.errors || prometheusIntegrationResetToken?.errors;
if (error) { if (error) {
return createFlash({ message: error }); return createFlash({ message: error });
} }
@ -214,10 +233,10 @@ export default {
prometheusIntegrationResetToken?.integration; prometheusIntegrationResetToken?.integration;
this.$apollo.mutate({ this.$apollo.mutate({
mutation: updateCurrentIntergrationMutation, mutation: this.isHttp(type)
variables: { ? updateCurrentHttpIntegrationMutation
...integration, : updateCurrentPrometheusIntegrationMutation,
}, variables: integration,
}); });
return createFlash({ return createFlash({
@ -233,33 +252,31 @@ export default {
this.isUpdating = false; this.isUpdating = false;
}); });
}, },
editIntegration({ id }) { editIntegration({ id, type }) {
const currentIntegration = this.integrations.list.find( let currentIntegration = this.integrations.list.find((integration) => integration.id === id);
if (this.isHttp(type)) {
const httpIntegrationMappingData = this.httpIntegrations.list.find(
(integration) => integration.id === id, (integration) => integration.id === id,
); );
currentIntegration = { ...currentIntegration, ...httpIntegrationMappingData };
}
this.$apollo.mutate({ this.$apollo.mutate({
mutation: updateCurrentIntergrationMutation, mutation: this.isHttp(type)
variables: { ? updateCurrentHttpIntegrationMutation
id: currentIntegration.id, : updateCurrentPrometheusIntegrationMutation,
name: currentIntegration.name, variables: currentIntegration,
active: currentIntegration.active,
token: currentIntegration.token,
type: currentIntegration.type,
url: currentIntegration.url,
apiUrl: currentIntegration.apiUrl,
},
}); });
this.setFormVisibility(true);
}, },
deleteIntegration({ id }) { deleteIntegration({ id, type }) {
const { projectPath } = this; const { projectPath } = this;
this.isUpdating = true; this.isUpdating = true;
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: destroyHttpIntegrationMutation, mutation: destroyHttpIntegrationMutation,
variables: { variables: { id },
id,
},
update(store, { data }) { update(store, { data }) {
updateStoreAfterIntegrationDelete(store, getIntegrationsQuery, data, { projectPath }); updateStoreAfterIntegrationDelete(store, getIntegrationsQuery, data, { projectPath });
}, },
@ -269,7 +286,7 @@ export default {
if (error) { if (error) {
return createFlash({ message: error }); return createFlash({ message: error });
} }
this.clearCurrentIntegration(); this.clearCurrentIntegration({ type });
return createFlash({ return createFlash({
message: this.$options.i18n.integrationRemoved, message: this.$options.i18n.integrationRemoved,
type: FLASH_TYPES.SUCCESS, type: FLASH_TYPES.SUCCESS,
@ -282,18 +299,20 @@ export default {
this.isUpdating = false; this.isUpdating = false;
}); });
}, },
clearCurrentIntegration() { clearCurrentIntegration({ type }) {
if (type) {
this.$apollo.mutate({ this.$apollo.mutate({
mutation: updateCurrentIntergrationMutation, mutation: this.isHttp(type)
? updateCurrentHttpIntegrationMutation
: updateCurrentPrometheusIntegrationMutation,
variables: {}, variables: {},
}); });
}
this.setFormVisibility(false);
}, },
setTestAlertPayload(payload) { testAlertPayload(payload) {
this.testAlertPayload = payload;
},
validateAlertPayload(payload) {
return service return service
.updateTestAlert(payload ?? this.testAlertPayload) .updateTestAlert(payload)
.then(() => { .then(() => {
return createFlash({ return createFlash({
message: this.$options.i18n.alertSent, message: this.$options.i18n.alertSent,
@ -304,6 +323,9 @@ export default {
createFlash({ message: INTEGRATION_PAYLOAD_TEST_ERROR }); createFlash({ message: INTEGRATION_PAYLOAD_TEST_ERROR });
}); });
}, },
setFormVisibility(visible) {
this.formVisible = visible;
},
}, },
}; };
</script> </script>
@ -316,7 +338,18 @@ export default {
@edit-integration="editIntegration" @edit-integration="editIntegration"
@delete-integration="deleteIntegration" @delete-integration="deleteIntegration"
/> />
<gl-button
v-if="canAddIntegration && !formVisible"
category="secondary"
variant="confirm"
data-testid="add-integration-btn"
class="gl-mt-3"
@click="setFormVisibility(true)"
>
{{ $options.i18n.addNewIntegration }}
</gl-button>
<alert-settings-form <alert-settings-form
v-if="formVisible"
:loading="isUpdating" :loading="isUpdating"
:can-add-integration="canAddIntegration" :can-add-integration="canAddIntegration"
:alert-fields="alertFields" :alert-fields="alertFields"
@ -324,7 +357,7 @@ export default {
@update-integration="updateIntegration" @update-integration="updateIntegration"
@reset-token="resetToken" @reset-token="resetToken"
@clear-current-integration="clearCurrentIntegration" @clear-current-integration="clearCurrentIntegration"
@set-test-alert-payload="setTestAlertPayload" @test-alert-payload="testAlertPayload"
/> />
</div> </div>
</template> </template>

View file

@ -1,95 +0,0 @@
{
"samplePayload": {
"body": "{\n \"dashboardId\":1,\n \"evalMatches\":[\n {\n \"value\":1,\n \"metric\":\"Count\",\n \"tags\":{}\n }\n ],\n \"imageUrl\":\"https://grafana.com/static/assets/img/blog/mixed_styles.png\",\n \"message\":\"Notification Message\",\n \"orgId\":1,\n \"panelId\":2,\n \"ruleId\":1,\n \"ruleName\":\"Panel Title alert\",\n \"ruleUrl\":\"http://localhost:3000/d/hZ7BuVbWz/test-dashboard?fullscreen\\u0026edit\\u0026tab=alert\\u0026panelId=2\\u0026orgId=1\",\n \"state\":\"alerting\",\n \"tags\":{\n \"tag name\":\"tag value\"\n },\n \"title\":\"[Alerting] Panel Title alert\"\n}\n",
"payloadAlerFields": {
"nodes": [
{
"path": ["dashboardId"],
"label": "Dashboard Id",
"type": "string"
},
{
"path": ["evalMatches"],
"label": "Eval Matches",
"type": "array"
},
{
"path": ["createdAt"],
"label": "Created At",
"type": "datetime"
},
{
"path": ["imageUrl"],
"label": "Image Url",
"type": "string"
},
{
"path": ["message"],
"label": "Message",
"type": "string"
},
{
"path": ["orgId"],
"label": "Org Id",
"type": "string"
},
{
"path": ["panelId"],
"label": "Panel Id",
"type": "string"
},
{
"path": ["ruleId"],
"label": "Rule Id",
"type": "string"
},
{
"path": ["ruleName"],
"label": "Rule Name",
"type": "string"
},
{
"path": ["ruleUrl"],
"label": "Rule Url",
"type": "string"
},
{
"path": ["state"],
"label": "State",
"type": "string"
},
{
"path": ["title"],
"label": "Title",
"type": "string"
},
{
"path": ["tags", "tag"],
"label": "Tags",
"type": "string"
}
]
}
},
"storedMapping": {
"nodes": [
{
"alertFieldName": "title",
"payloadAlertPaths": "title",
"fallbackAlertPaths": "ruleUrl"
},
{
"alertFieldName": "description",
"payloadAlertPaths": "message"
},
{
"alertFieldName": "hosts",
"payloadAlertPaths": "evalMatches"
},
{
"alertFieldName": "startTime",
"payloadAlertPaths": "createdAt"
}
]
}
}

View file

@ -1,50 +1,106 @@
import { s__ } from '~/locale'; import { s__, __ } from '~/locale';
// TODO: Remove this as part of the form old removal
export const i18n = { export const i18n = {
usageSection: s__( integrationTabs: {
'AlertSettings|You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page.', configureDetails: s__('AlertSettings|Configure details'),
viewCredentials: s__('AlertSettings|View credentials'),
sendTestAlert: s__('AlertSettings|Send test alert'),
},
integrationFormSteps: {
selectType: {
label: s__('AlertSettings|Select integration type'),
enterprise: s__(
'AlertSettings|In free versions of GitLab, only one integration for each type can be added. %{linkStart}Upgrade your subscription%{linkEnd} to add additional integrations.',
), ),
setupSection: s__( },
"AlertSettings|Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.", nameIntegration: {
label: s__('AlertSettings|Name integration'),
placeholder: s__('AlertSettings|Enter integration name'),
activeToggle: __('Active'),
},
setupCredentials: {
help: s__(
"AlertSettings|Utilize the URL and authorization key below to authorize an external service to send alerts to GitLab. Review your external service's documentation to learn where to add these details, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.",
), ),
errorMsg: s__('AlertSettings|There was an error updating the alert settings.'), prometheusHelp: s__(
errorKeyMsg: s__( 'AlertSettings|Utilize the URL and authorization key below to authorize Prometheus to send alerts to GitLab. Review the Prometheus documentation to learn where to add these details, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.',
'AlertSettings|There was an error while trying to reset the key. Please refresh the page to try again.',
), ),
restKeyInfo: s__( webhookUrl: s__('AlertSettings|Webhook URL'),
authorizationKey: s__('AlertSettings|Authorization key'),
reset: s__('AlertSettings|Reset Key'),
},
setSamplePayload: {
label: s__('AlertSettings|Sample alert payload (optional)'),
testPayloadHelpHttp: s__(
'AlertSettings|Provide an example payload from the monitoring tool you intend to integrate with. This payload can be used to create a custom mapping (optional).',
),
testPayloadHelp: s__(
'AlertSettings|Provide an example payload from the monitoring tool you intend to integrate with. This will allow you to send an alert to an active GitLab alerting point.',
),
placeholder: s__('AlertSettings|{ "events": [{ "application": "Name of application" }] }'),
resetHeader: s__('AlertSettings|Reset the mapping'),
resetBody: s__(
"AlertSettings|If you edit the payload, the stored mapping will be reset, and you'll need to re-map the fields.",
),
resetOk: s__('AlertSettings|Proceed with editing'),
editPayload: s__('AlertSettings|Edit payload'),
parsePayload: s__('AlertSettings|Parse payload for custom mapping'),
payloadParsedSucessMsg: s__(
'AlertSettings|Sample payload has been parsed. You can now map the fields.',
),
},
mapFields: {
label: s__('AlertSettings|Customize alert payload mapping (optional)'),
intro: s__(
'AlertSettings|If you intend to create a custom mapping, provide an example payload from your monitoring tool and click "parse payload fields" button to continue. The sample payload is required for completing the custom mapping; if you want to skip the mapping step, progress straight to saving your integration.',
),
},
prometheusFormUrl: {
label: s__('AlertSettings|Prometheus API base URL'),
help: s__('AlertSettings|URL cannot be blank and must start with http or https'),
},
restKeyInfo: {
label: s__(
'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.', 'AlertSettings|Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in.',
), ),
},
},
saveIntegration: s__('AlertSettings|Save integration'),
changesSaved: s__('AlertSettings|Your integration was successfully updated.'), changesSaved: s__('AlertSettings|Your integration was successfully updated.'),
prometheusInfo: s__('AlertSettings|Add URL and auth key to your Prometheus config file'), cancelAndClose: __('Cancel and close'),
integrationsInfo: s__( send: s__('AlertSettings|Send'),
'AlertSettings|Learn more about our our upcoming %{linkStart}integrations%{linkEnd}', copy: __('Copy'),
),
resetKey: s__('AlertSettings|Reset key'),
copyToClipboard: s__('AlertSettings|Copy'),
apiBaseUrlLabel: s__('AlertSettings|API URL'),
authKeyLabel: s__('AlertSettings|Authorization key'),
urlLabel: s__('AlertSettings|Webhook URL'),
activeLabel: s__('AlertSettings|Active'),
apiBaseUrlHelpText: s__('AlertSettings|URL cannot be blank and must start with http or https'),
testAlertInfo: s__('AlertSettings|Test alert payload'),
alertJson: s__('AlertSettings|Alert test payload'),
alertJsonPlaceholder: s__('AlertSettings|Enter test alert JSON....'),
testAlertFailed: s__('AlertSettings|Test failed. Do you still want to save your changes anyway?'),
testAlertSuccess: s__(
'AlertSettings|Test alert sent successfully. If you have made other changes, please save them now.',
),
authKeyRest: s__(
'AlertSettings|Authorization key has been successfully reset. Please save your changes now.',
),
integration: s__('AlertSettings|Integration'),
}; };
export const integrationTypes = [ export const integrationSteps = {
{ value: '', text: s__('AlertSettings|Select integration type') }, selectType: 'SELECT_TYPE',
{ value: 'HTTP', text: s__('AlertSettings|HTTP Endpoint') }, nameIntegration: 'NAME_INTEGRATION',
{ value: 'PROMETHEUS', text: s__('AlertSettings|External Prometheus') }, setPrometheusApiUrl: 'SET_PROMETHEUS_API_URL',
]; setSamplePayload: 'SET_SAMPLE_PAYLOAD',
customizeMapping: 'CUSTOMIZE_MAPPING',
};
export const createStepNumbers = {
[integrationSteps.selectType]: 1,
[integrationSteps.nameIntegration]: 2,
[integrationSteps.setPrometheusApiUrl]: 2,
[integrationSteps.setSamplePayload]: 3,
[integrationSteps.customizeMapping]: 4,
};
export const editStepNumbers = {
[integrationSteps.selectType]: 1,
[integrationSteps.nameIntegration]: 1,
[integrationSteps.setPrometheusApiUrl]: null,
[integrationSteps.setSamplePayload]: 2,
[integrationSteps.customizeMapping]: 3,
};
export const integrationTypes = {
none: { value: '', text: s__('AlertSettings|Select integration type') },
http: { value: 'HTTP', text: s__('AlertSettings|HTTP Endpoint') },
prometheus: { value: 'PROMETHEUS', text: s__('AlertSettings|External Prometheus') },
};
export const typeSet = { export const typeSet = {
http: 'HTTP', http: 'HTTP',
@ -57,14 +113,18 @@ export const JSON_VALIDATE_DELAY = 250;
export const targetPrometheusUrlPlaceholder = 'http://prometheus.example.com/'; export const targetPrometheusUrlPlaceholder = 'http://prometheus.example.com/';
export const sectionHash = 'js-alert-management-settings';
/* eslint-disable @gitlab/require-i18n-strings */
/** /**
* Tracks snowplow event when user views alerts integration list * Tracks snowplow event when user views alerts integration list
*/ */
export const trackAlertIntegrationsViewsOptions = { export const trackAlertIntegrationsViewsOptions = {
/* eslint-disable-next-line @gitlab/require-i18n-strings */
category: 'Alert Integrations', category: 'Alert Integrations',
action: 'view_alert_integrations_list', action: 'view_alert_integrations_list',
}; };
export const mappingFields = {
mapping: 'mapping',
fallback: 'fallback',
};
export const viewCredentialsTabIndex = 1;

View file

@ -10,16 +10,25 @@ const resolvers = {
Mutation: { Mutation: {
updateCurrentIntegration: ( updateCurrentIntegration: (
_, _,
{ id = null, name, active, token, type, url, apiUrl }, {
id = null,
name,
active,
token,
type,
url,
apiUrl,
payloadExample,
payloadAttributeMappings,
payloadAlertFields,
},
{ cache }, { cache },
) => { ) => {
const sourceData = cache.readQuery({ query: getCurrentIntegrationQuery }); const sourceData = cache.readQuery({ query: getCurrentIntegrationQuery });
const data = produce(sourceData, (draftData) => { const data = produce(sourceData, (draftData) => {
if (id === null) { if (id === null) {
// eslint-disable-next-line no-param-reassign
draftData.currentIntegration = null; draftData.currentIntegration = null;
} else { } else {
// eslint-disable-next-line no-param-reassign
draftData.currentIntegration = { draftData.currentIntegration = {
id, id,
name, name,
@ -28,6 +37,9 @@ const resolvers = {
type, type,
url, url,
apiUrl, apiUrl,
payloadExample,
payloadAttributeMappings,
payloadAlertFields,
}; };
} }
}); });

View file

@ -0,0 +1,7 @@
#import "./integration_item.fragment.graphql"
#import "ee_else_ce/alerts_settings/graphql/fragments/http_integration_payload_data.fragment.graphql"
fragment HttpIntegrationItem on AlertManagementHttpIntegration {
...IntegrationItem
...HttpIntegrationPayloadData
}

View file

@ -0,0 +1,3 @@
fragment HttpIntegrationPayloadData on AlertManagementHttpIntegration {
id
}

View file

@ -1,24 +1,10 @@
#import "../fragments/integration_item.fragment.graphql" #import "../fragments/http_integration_item.fragment.graphql"
mutation createHttpIntegration( mutation createHttpIntegration($projectPath: ID!, $name: String!, $active: Boolean!) {
$projectPath: ID! httpIntegrationCreate(input: { projectPath: $projectPath, name: $name, active: $active }) {
$name: String!
$active: Boolean!
$payloadExample: JsonString
$payloadAttributeMappings: [AlertManagementPayloadAlertFieldInput!]
) {
httpIntegrationCreate(
input: {
projectPath: $projectPath
name: $name
active: $active
payloadExample: $payloadExample
payloadAttributeMappings: $payloadAttributeMappings
}
) {
errors errors
integration { integration {
...IntegrationItem ...HttpIntegrationItem
} }
} }
} }

View file

@ -1,10 +1,10 @@
#import "../fragments/integration_item.fragment.graphql" #import "../fragments/http_integration_item.fragment.graphql"
mutation destroyHttpIntegration($id: ID!) { mutation destroyHttpIntegration($id: ID!) {
httpIntegrationDestroy(input: { id: $id }) { httpIntegrationDestroy(input: { id: $id }) {
errors errors
integration { integration {
...IntegrationItem ...HttpIntegrationItem
} }
} }
} }

View file

@ -1,10 +1,10 @@
#import "../fragments/integration_item.fragment.graphql" #import "../fragments/http_integration_item.fragment.graphql"
mutation resetHttpIntegrationToken($id: ID!) { mutation resetHttpIntegrationToken($id: ID!) {
httpIntegrationResetToken(input: { id: $id }) { httpIntegrationResetToken(input: { id: $id }) {
errors errors
integration { integration {
...IntegrationItem ...HttpIntegrationItem
} }
} }
} }

View file

@ -0,0 +1,25 @@
mutation updateCurrentHttpIntegration(
$id: String
$name: String
$active: Boolean
$token: String
$type: String
$url: String
$apiUrl: String
$payloadExample: JsonString
$payloadAttributeMappings: [AlertManagementPayloadAlertFieldInput!]
$payloadAlertFields: [AlertManagementPayloadAlertField!]
) {
updateCurrentIntegration(
id: $id
name: $name
active: $active
token: $token
type: $type
url: $url
apiUrl: $apiUrl
payloadExample: $payloadExample
payloadAttributeMappings: $payloadAttributeMappings
payloadAlertFields: $payloadAlertFields
) @client
}

View file

@ -1,19 +0,0 @@
mutation updateCurrentIntegration(
$id: String
$name: String
$active: Boolean
$token: String
$type: String
$url: String
$apiUrl: String
) {
updateCurrentIntegration(
id: $id
name: $name
active: $active
token: $token
type: $type
url: $url
apiUrl: $apiUrl
) @client
}

View file

@ -0,0 +1,21 @@
mutation updateCurrentPrometheusIntegration(
$id: String
$name: String
$active: Boolean
$token: String
$type: String
$url: String
$apiUrl: String
$samplePayload: String
) {
updateCurrentIntegration(
id: $id
name: $name
active: $active
token: $token
type: $type
url: $url
apiUrl: $apiUrl
samplePayload: $samplePayload
) @client
}

View file

@ -1,10 +1,10 @@
#import "../fragments/integration_item.fragment.graphql" #import "../fragments/http_integration_item.fragment.graphql"
mutation updateHttpIntegration($id: ID!, $name: String!, $active: Boolean!) { mutation updateHttpIntegration($id: ID!, $name: String!, $active: Boolean!) {
httpIntegrationUpdate(input: { id: $id, name: $name, active: $active }) { httpIntegrationUpdate(input: { id: $id, name: $name, active: $active }) {
errors errors
integration { integration {
...IntegrationItem ...HttpIntegrationItem
} }
} }
} }

View file

@ -0,0 +1,12 @@
#import "ee_else_ce/alerts_settings/graphql/fragments/http_integration_payload_data.fragment.graphql"
# TODO: this query need to accept http integration id to request a sepcific integration
query getHttpIntegrations($projectPath: ID!) {
project(fullPath: $projectPath) {
alertManagementHttpIntegrations {
nodes {
...HttpIntegrationPayloadData
}
}
}
}

View file

@ -0,0 +1,9 @@
query parsePayloadFields($projectPath: ID!, $payload: String!) {
project(fullPath: $projectPath) {
alertManagementPayloadFields(payloadExample: $payload) {
path
label
type
}
}
}

View file

@ -63,10 +63,7 @@ export default (el) => {
render(createElement) { render(createElement) {
return createElement('alert-settings-wrapper', { return createElement('alert-settings-wrapper', {
props: { props: {
alertFields: alertFields: parseBoolean(multiIntegrations) ? JSON.parse(alertFields) : null,
gon.features?.multipleHttpIntegrationsCustomMapping && parseBoolean(multiIntegrations)
? JSON.parse(alertFields)
: null,
}, },
}); });
}, },

View file

@ -15,7 +15,6 @@ const deleteIntegrationFromStore = (store, query, { httpIntegrationDestroy }, va
}); });
const data = produce(sourceData, (draftData) => { const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.alertManagementIntegrations.nodes = draftData.project.alertManagementIntegrations.nodes.filter( draftData.project.alertManagementIntegrations.nodes = draftData.project.alertManagementIntegrations.nodes.filter(
({ id }) => id !== integration.id, ({ id }) => id !== integration.id,
); );
@ -46,7 +45,6 @@ const addIntegrationToStore = (
}); });
const data = produce(sourceData, (draftData) => { const data = produce(sourceData, (draftData) => {
// eslint-disable-next-line no-param-reassign
draftData.project.alertManagementIntegrations.nodes = [ draftData.project.alertManagementIntegrations.nodes = [
integration, integration,
...draftData.project.alertManagementIntegrations.nodes, ...draftData.project.alertManagementIntegrations.nodes,
@ -60,6 +58,31 @@ const addIntegrationToStore = (
}); });
}; };
const addHttpIntegrationToStore = (store, query, { httpIntegrationCreate }, variables) => {
const integration = httpIntegrationCreate?.integration;
if (!integration) {
return;
}
const sourceData = store.readQuery({
query,
variables,
});
const data = produce(sourceData, (draftData) => {
draftData.project.alertManagementHttpIntegrations.nodes = [
integration,
...draftData.project.alertManagementHttpIntegrations.nodes,
];
});
store.writeQuery({
query,
variables,
data,
});
};
const onError = (data, message) => { const onError = (data, message) => {
createFlash({ message }); createFlash({ message });
throw new Error(data.errors); throw new Error(data.errors);
@ -82,3 +105,11 @@ export const updateStoreAfterIntegrationAdd = (store, query, data, variables) =>
addIntegrationToStore(store, query, data, variables); addIntegrationToStore(store, query, data, variables);
} }
}; };
export const updateStoreAfterHttpIntegrationAdd = (store, query, data, variables) => {
if (hasErrors(data)) {
onError(data, ADD_INTEGRATION_ERROR);
} else {
addHttpIntegrationToStore(store, query, data, variables);
}
};

View file

@ -17,5 +17,5 @@ export const RESET_INTEGRATION_TOKEN_ERROR = s__(
); );
export const INTEGRATION_PAYLOAD_TEST_ERROR = s__( export const INTEGRATION_PAYLOAD_TEST_ERROR = s__(
'AlertsIntegrations|Integration payload is invalid. You can still save your changes.', 'AlertsIntegrations|Integration payload is invalid.',
); );

View file

@ -1,3 +1,4 @@
import { isEqual } from 'lodash';
/** /**
* Given data for GitLab alert fields, parsed payload fields data and previously stored mapping (if any) * Given data for GitLab alert fields, parsed payload fields data and previously stored mapping (if any)
* creates an object in a form convenient to build UI && interact with it * creates an object in a form convenient to build UI && interact with it
@ -10,16 +11,19 @@
export const getMappingData = (gitlabFields, payloadFields, savedMapping) => { export const getMappingData = (gitlabFields, payloadFields, savedMapping) => {
return gitlabFields.map((gitlabField) => { return gitlabFields.map((gitlabField) => {
// find fields from payload that match gitlab alert field by type // find fields from payload that match gitlab alert field by type
const mappingFields = payloadFields.filter(({ type }) => gitlabField.types.includes(type)); const mappingFields = payloadFields.filter(({ type }) =>
gitlabField.types.includes(type.toLowerCase()),
);
// find the mapping that was previously stored // find the mapping that was previously stored
const foundMapping = savedMapping.find(({ fieldName }) => fieldName === gitlabField.name); const foundMapping = savedMapping.find(
({ fieldName }) => fieldName.toLowerCase() === gitlabField.name,
const { fallbackAlertPaths, payloadAlertPaths } = foundMapping || {}; );
const { path: mapping, fallbackPath: fallback } = foundMapping || {};
return { return {
mapping: payloadAlertPaths, mapping,
fallback: fallbackAlertPaths, fallback,
searchTerm: '', searchTerm: '',
fallbackSearchTerm: '', fallbackSearchTerm: '',
mappingFields, mappingFields,
@ -36,7 +40,7 @@ export const getMappingData = (gitlabFields, payloadFields, savedMapping) => {
*/ */
export const transformForSave = (mappingData) => { export const transformForSave = (mappingData) => {
return mappingData.reduce((acc, field) => { return mappingData.reduce((acc, field) => {
const mapped = field.mappingFields.find(({ name }) => name === field.mapping); const mapped = field.mappingFields.find(({ path }) => isEqual(path, field.mapping));
if (mapped) { if (mapped) {
const { path, type, label } = mapped; const { path, type, label } = mapped;
acc.push({ acc.push({
@ -49,13 +53,3 @@ export const transformForSave = (mappingData) => {
return acc; return acc;
}, []); }, []);
}; };
/**
* Adds `name` prop to each provided by BE parsed payload field
* @param {Object} payload - parsed sample payload
*
* @return {Object} same as input with an extra `name` property which basically serves as a key to make a match
*/
export const getPayloadFields = (payload) => {
return payload.map((field) => ({ ...field, name: field.path.join('_') }));
};

View file

@ -1,48 +0,0 @@
<script>
import { TODAY, TOTAL_DAYS_TO_SHOW, START_DATE } from '../constants';
import ChartsConfig from './charts_config';
import InstanceCounts from './instance_counts.vue';
import InstanceStatisticsCountChart from './instance_statistics_count_chart.vue';
import ProjectsAndGroupsChart from './projects_and_groups_chart.vue';
import UsersChart from './users_chart.vue';
export default {
name: 'InstanceStatisticsApp',
components: {
InstanceCounts,
InstanceStatisticsCountChart,
UsersChart,
ProjectsAndGroupsChart,
},
TOTAL_DAYS_TO_SHOW,
START_DATE,
TODAY,
configs: ChartsConfig,
};
</script>
<template>
<div>
<instance-counts />
<users-chart
:start-date="$options.START_DATE"
:end-date="$options.TODAY"
:total-data-points="$options.TOTAL_DAYS_TO_SHOW"
/>
<projects-and-groups-chart
:start-date="$options.START_DATE"
:end-date="$options.TODAY"
:total-data-points="$options.TOTAL_DAYS_TO_SHOW"
/>
<instance-statistics-count-chart
v-for="chartOptions in $options.configs"
:key="chartOptions.chartTitle"
:queries="chartOptions.queries"
:x-axis-title="chartOptions.xAxisTitle"
:y-axis-title="chartOptions.yAxisTitle"
:load-chart-error-message="chartOptions.loadChartError"
:no-data-message="chartOptions.noDataMessage"
:chart-title="chartOptions.chartTitle"
/>
</div>
</template>

View file

@ -1,87 +0,0 @@
import { s__, __, sprintf } from '~/locale';
import query from '../graphql/queries/instance_count.query.graphql';
const noDataMessage = s__('InstanceStatistics|No data available.');
export default [
{
loadChartError: sprintf(
s__(
'InstanceStatistics|Could not load the pipelines chart. Please refresh the page to try again.',
),
),
noDataMessage,
chartTitle: s__('InstanceStatistics|Pipelines'),
yAxisTitle: s__('InstanceStatistics|Items'),
xAxisTitle: s__('InstanceStatistics|Month'),
queries: [
{
query,
title: s__('InstanceStatistics|Pipelines total'),
identifier: 'PIPELINES',
loadError: sprintf(
s__('InstanceStatistics|There was an error fetching the total pipelines'),
),
},
{
query,
title: s__('InstanceStatistics|Pipelines succeeded'),
identifier: 'PIPELINES_SUCCEEDED',
loadError: sprintf(
s__('InstanceStatistics|There was an error fetching the successful pipelines'),
),
},
{
query,
title: s__('InstanceStatistics|Pipelines failed'),
identifier: 'PIPELINES_FAILED',
loadError: sprintf(
s__('InstanceStatistics|There was an error fetching the failed pipelines'),
),
},
{
query,
title: s__('InstanceStatistics|Pipelines canceled'),
identifier: 'PIPELINES_CANCELED',
loadError: sprintf(
s__('InstanceStatistics|There was an error fetching the cancelled pipelines'),
),
},
{
query,
title: s__('InstanceStatistics|Pipelines skipped'),
identifier: 'PIPELINES_SKIPPED',
loadError: sprintf(
s__('InstanceStatistics|There was an error fetching the skipped pipelines'),
),
},
],
},
{
loadChartError: sprintf(
s__(
'InstanceStatistics|Could not load the issues and merge requests chart. Please refresh the page to try again.',
),
),
noDataMessage,
chartTitle: s__('InstanceStatistics|Issues & Merge Requests'),
yAxisTitle: s__('InstanceStatistics|Items'),
xAxisTitle: s__('InstanceStatistics|Month'),
queries: [
{
query,
title: __('Issues'),
identifier: 'ISSUES',
loadError: sprintf(s__('InstanceStatistics|There was an error fetching the issues')),
},
{
query,
title: __('Merge requests'),
identifier: 'MERGE_REQUESTS',
loadError: sprintf(
s__('InstanceStatistics|There was an error fetching the merge requests'),
),
},
],
},
];

View file

@ -1,64 +0,0 @@
<script>
import MetricCard from '~/analytics/shared/components/metric_card.vue';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { SUPPORTED_FORMATS, getFormatter } from '~/lib/utils/unit_format';
import { s__ } from '~/locale';
import * as Sentry from '~/sentry/wrapper';
import instanceStatisticsCountQuery from '../graphql/queries/instance_statistics_count.query.graphql';
const defaultPrecision = 0;
export default {
name: 'InstanceCounts',
components: {
MetricCard,
},
data() {
return {
counts: [],
};
},
apollo: {
counts: {
query: instanceStatisticsCountQuery,
update(data) {
return Object.entries(data).map(([key, obj]) => {
const label = this.$options.i18n.labels[key];
const formatter = getFormatter(SUPPORTED_FORMATS.number);
const value = obj.nodes?.length ? formatter(obj.nodes[0].count, defaultPrecision) : null;
return {
key,
value,
label,
};
});
},
error(error) {
createFlash(this.$options.i18n.loadCountsError);
Sentry.captureException(error);
},
},
},
i18n: {
labels: {
users: s__('InstanceStatistics|Users'),
projects: s__('InstanceStatistics|Projects'),
groups: s__('InstanceStatistics|Groups'),
issues: s__('InstanceStatistics|Issues'),
mergeRequests: s__('InstanceStatistics|Merge Requests'),
pipelines: s__('InstanceStatistics|Pipelines'),
},
loadCountsError: s__('Could not load instance counts. Please refresh the page to try again.'),
},
};
</script>
<template>
<metric-card
:title="__('Usage Trends')"
:metrics="counts"
:is-loading="$apollo.queries.counts.loading"
class="gl-mt-4"
/>
</template>

View file

@ -1,206 +0,0 @@
<script>
import { GlAlert } from '@gitlab/ui';
import { GlLineChart } from '@gitlab/ui/dist/charts';
import { some, every } from 'lodash';
import {
differenceInMonths,
formatDateAsMonth,
getDayDifference,
} from '~/lib/utils/datetime_utility';
import * as Sentry from '~/sentry/wrapper';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
import { TODAY, START_DATE } from '../constants';
import { getAverageByMonth, getEarliestDate, generateDataKeys } from '../utils';
const QUERY_DATA_KEY = 'instanceStatisticsMeasurements';
export default {
name: 'InstanceStatisticsCountChart',
components: {
GlLineChart,
GlAlert,
ChartSkeletonLoader,
},
startDate: START_DATE,
endDate: TODAY,
props: {
chartTitle: {
type: String,
required: true,
},
loadChartErrorMessage: {
type: String,
required: true,
},
noDataMessage: {
type: String,
required: true,
},
xAxisTitle: {
type: String,
required: true,
},
yAxisTitle: {
type: String,
required: true,
},
queries: {
type: Array,
required: true,
},
},
data() {
return {
errors: { ...generateDataKeys(this.queries, '') },
...generateDataKeys(this.queries, []),
};
},
computed: {
errorMessages() {
return Object.values(this.errors);
},
isLoading() {
return some(this.$apollo.queries, (query) => query?.loading);
},
allQueriesFailed() {
return every(this.errorMessages, (message) => message.length);
},
hasLoadingErrors() {
return some(this.errorMessages, (message) => message.length);
},
errorMessage() {
// show the generic loading message if all requests fail
return this.allQueriesFailed ? this.loadChartErrorMessage : this.errorMessages.join('\n\n');
},
hasEmptyDataSet() {
return this.chartData.every(({ data }) => data.length === 0);
},
totalDaysToShow() {
return getDayDifference(this.$options.startDate, this.$options.endDate);
},
chartData() {
const options = { shouldRound: true };
return this.queries.map(({ identifier, title }) => ({
name: title,
data: getAverageByMonth(this[identifier]?.nodes, options),
}));
},
range() {
return {
min: this.$options.startDate,
max: this.$options.endDate,
};
},
chartOptions() {
const { endDate, startDate } = this.$options;
return {
xAxis: {
...this.range,
name: this.xAxisTitle,
type: 'time',
splitNumber: differenceInMonths(startDate, endDate) + 1,
axisLabel: {
interval: 0,
showMinLabel: false,
showMaxLabel: false,
align: 'right',
formatter: formatDateAsMonth,
},
},
yAxis: {
name: this.yAxisTitle,
},
};
},
},
created() {
this.queries.forEach(({ query, identifier, loadError }) => {
this.$apollo.addSmartQuery(identifier, {
query,
variables() {
return {
identifier,
first: this.totalDaysToShow,
after: null,
};
},
update(data) {
const { nodes = [], pageInfo } = data[QUERY_DATA_KEY] || {};
return {
nodes,
pageInfo,
};
},
result() {
const { pageInfo, nodes } = this[identifier];
if (pageInfo?.hasNextPage && this.calculateDaysToFetch(getEarliestDate(nodes)) > 0) {
this.fetchNextPage({
query: this.$apollo.queries[identifier],
errorMessage: loadError,
pageInfo,
identifier,
});
}
},
error(error) {
this.handleError({
message: loadError,
identifier,
error,
});
},
});
});
},
methods: {
calculateDaysToFetch(firstDataPointDate = null) {
return firstDataPointDate
? Math.max(0, getDayDifference(this.$options.startDate, new Date(firstDataPointDate)))
: 0;
},
handleError({ identifier, error, message }) {
this.loadingError = true;
this.errors = { ...this.errors, [identifier]: message };
Sentry.captureException(error);
},
fetchNextPage({ query, pageInfo, identifier, errorMessage }) {
query
.fetchMore({
variables: {
identifier,
first: this.calculateDaysToFetch(getEarliestDate(this[identifier].nodes)),
after: pageInfo.endCursor,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
const { nodes, ...rest } = fetchMoreResult[QUERY_DATA_KEY];
const { nodes: previousNodes } = previousResult[QUERY_DATA_KEY];
return {
[QUERY_DATA_KEY]: { ...rest, nodes: [...previousNodes, ...nodes] },
};
},
})
.catch((error) => this.handleError({ identifier, error, message: errorMessage }));
},
},
};
</script>
<template>
<div>
<h3>{{ chartTitle }}</h3>
<gl-alert v-if="hasLoadingErrors" variant="danger" :dismissible="false" class="gl-mt-3">
{{ errorMessage }}
</gl-alert>
<div v-if="!allQueriesFailed">
<chart-skeleton-loader v-if="isLoading" />
<gl-alert v-else-if="hasEmptyDataSet" variant="info" :dismissible="false" class="gl-mt-3">
{{ noDataMessage }}
</gl-alert>
<gl-line-chart
v-else
:option="chartOptions"
:include-legend-avg-max="true"
:data="chartData"
/>
</div>
</div>
</template>

View file

@ -1,224 +0,0 @@
<script>
import { GlAlert } from '@gitlab/ui';
import { GlLineChart } from '@gitlab/ui/dist/charts';
import produce from 'immer';
import { sortBy } from 'lodash';
import { formatDateAsMonth } from '~/lib/utils/datetime_utility';
import { s__, __ } from '~/locale';
import * as Sentry from '~/sentry/wrapper';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
import latestGroupsQuery from '../graphql/queries/groups.query.graphql';
import latestProjectsQuery from '../graphql/queries/projects.query.graphql';
import { getAverageByMonth } from '../utils';
const sortByDate = (data) => sortBy(data, (item) => new Date(item[0]).getTime());
const averageAndSortData = (data = [], maxDataPoints) => {
const averaged = getAverageByMonth(
data.length > maxDataPoints ? data.slice(0, maxDataPoints) : data,
{ shouldRound: true },
);
return sortByDate(averaged);
};
export default {
name: 'ProjectsAndGroupsChart',
components: { GlAlert, GlLineChart, ChartSkeletonLoader },
props: {
startDate: {
type: Date,
required: true,
},
endDate: {
type: Date,
required: true,
},
totalDataPoints: {
type: Number,
required: true,
},
},
data() {
return {
loadingError: false,
errorMessage: '',
groups: [],
projects: [],
groupsPageInfo: null,
projectsPageInfo: null,
};
},
apollo: {
groups: {
query: latestGroupsQuery,
variables() {
return {
first: this.totalDataPoints,
after: null,
};
},
update(data) {
return data.groups?.nodes || [];
},
result({ data }) {
const {
groups: { pageInfo },
} = data;
this.groupsPageInfo = pageInfo;
this.fetchNextPage({
query: this.$apollo.queries.groups,
pageInfo: this.groupsPageInfo,
dataKey: 'groups',
errorMessage: this.$options.i18n.loadGroupsDataError,
});
},
error(error) {
this.handleError({
message: this.$options.i18n.loadGroupsDataError,
error,
dataKey: 'groups',
});
},
},
projects: {
query: latestProjectsQuery,
variables() {
return {
first: this.totalDataPoints,
after: null,
};
},
update(data) {
return data.projects?.nodes || [];
},
result({ data }) {
const {
projects: { pageInfo },
} = data;
this.projectsPageInfo = pageInfo;
this.fetchNextPage({
query: this.$apollo.queries.projects,
pageInfo: this.projectsPageInfo,
dataKey: 'projects',
errorMessage: this.$options.i18n.loadProjectsDataError,
});
},
error(error) {
this.handleError({
message: this.$options.i18n.loadProjectsDataError,
error,
dataKey: 'projects',
});
},
},
},
i18n: {
yAxisTitle: s__('InstanceStatistics|Total projects & groups'),
xAxisTitle: __('Month'),
loadChartError: s__(
'InstanceStatistics|Could not load the projects and groups chart. Please refresh the page to try again.',
),
loadProjectsDataError: s__('InstanceStatistics|There was an error while loading the projects'),
loadGroupsDataError: s__('InstanceStatistics|There was an error while loading the groups'),
noDataMessage: s__('InstanceStatistics|No data available.'),
},
computed: {
isLoadingGroups() {
return this.$apollo.queries.groups.loading || this.groupsPageInfo?.hasNextPage;
},
isLoadingProjects() {
return this.$apollo.queries.projects.loading || this.projectsPageInfo?.hasNextPage;
},
isLoading() {
return this.isLoadingProjects && this.isLoadingGroups;
},
groupChartData() {
return averageAndSortData(this.groups, this.totalDataPoints);
},
projectChartData() {
return averageAndSortData(this.projects, this.totalDataPoints);
},
hasNoData() {
const { projectChartData, groupChartData } = this;
return Boolean(!projectChartData.length && !groupChartData.length);
},
options() {
return {
xAxis: {
name: this.$options.i18n.xAxisTitle,
type: 'category',
axisLabel: {
formatter: (value) => {
return formatDateAsMonth(value);
},
},
},
yAxis: {
name: this.$options.i18n.yAxisTitle,
},
};
},
chartData() {
return [
{
name: s__('InstanceStatistics|Total projects'),
data: this.projectChartData,
},
{
name: s__('InstanceStatistics|Total groups'),
data: this.groupChartData,
},
];
},
},
methods: {
handleError({ error, message = this.$options.i18n.loadChartError, dataKey = null }) {
this.loadingError = true;
this.errorMessage = message;
if (!dataKey) {
this.projects = [];
this.groups = [];
} else {
this[dataKey] = [];
}
Sentry.captureException(error);
},
fetchNextPage({ pageInfo, query, dataKey, errorMessage }) {
if (pageInfo?.hasNextPage) {
query
.fetchMore({
variables: { first: this.totalDataPoints, after: pageInfo.endCursor },
updateQuery: (previousResult, { fetchMoreResult }) => {
const results = produce(fetchMoreResult, (newData) => {
// eslint-disable-next-line no-param-reassign
newData[dataKey].nodes = [
...previousResult[dataKey].nodes,
...newData[dataKey].nodes,
];
});
return results;
},
})
.catch((error) => {
this.handleError({ error, message: errorMessage, dataKey });
});
}
},
},
};
</script>
<template>
<div>
<h3>{{ $options.i18n.yAxisTitle }}</h3>
<chart-skeleton-loader v-if="isLoading" />
<gl-alert v-else-if="hasNoData" variant="info" :dismissible="false" class="gl-mt-3">
{{ $options.i18n.noDataMessage }}
</gl-alert>
<div v-else>
<gl-alert v-if="loadingError" variant="danger" :dismissible="false" class="gl-mt-3">{{
errorMessage
}}</gl-alert>
<gl-line-chart :option="options" :include-legend-avg-max="true" :data="chartData" />
</div>
</div>
</template>

View file

@ -1,4 +0,0 @@
fragment Count on InstanceStatisticsMeasurement {
count
recordedAt
}

View file

@ -1,13 +0,0 @@
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "../fragments/count.fragment.graphql"
query getGroupsCount($first: Int, $after: String) {
groups: instanceStatisticsMeasurements(identifier: GROUPS, first: $first, after: $after) {
nodes {
...Count
}
pageInfo {
...PageInfo
}
}
}

View file

@ -1,13 +0,0 @@
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "../fragments/count.fragment.graphql"
query getCount($identifier: MeasurementIdentifier!, $first: Int, $after: String) {
instanceStatisticsMeasurements(identifier: $identifier, first: $first, after: $after) {
nodes {
...Count
}
pageInfo {
...PageInfo
}
}
}

View file

@ -1,34 +0,0 @@
#import "../fragments/count.fragment.graphql"
query getInstanceCounts {
projects: instanceStatisticsMeasurements(identifier: PROJECTS, first: 1) {
nodes {
...Count
}
}
groups: instanceStatisticsMeasurements(identifier: GROUPS, first: 1) {
nodes {
...Count
}
}
users: instanceStatisticsMeasurements(identifier: USERS, first: 1) {
nodes {
...Count
}
}
issues: instanceStatisticsMeasurements(identifier: ISSUES, first: 1) {
nodes {
...Count
}
}
mergeRequests: instanceStatisticsMeasurements(identifier: MERGE_REQUESTS, first: 1) {
nodes {
...Count
}
}
pipelines: instanceStatisticsMeasurements(identifier: PIPELINES, first: 1) {
nodes {
...Count
}
}
}

View file

@ -1,13 +0,0 @@
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "../fragments/count.fragment.graphql"
query getProjectsCount($first: Int, $after: String) {
projects: instanceStatisticsMeasurements(identifier: PROJECTS, first: $first, after: $after) {
nodes {
...Count
}
pageInfo {
...PageInfo
}
}
}

View file

@ -1,13 +0,0 @@
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "../fragments/count.fragment.graphql"
query getUsersCount($first: Int, $after: String) {
users: instanceStatisticsMeasurements(identifier: USERS, first: $first, after: $after) {
nodes {
...Count
}
pageInfo {
...PageInfo
}
}
}

View file

@ -1,24 +0,0 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import InstanceStatisticsApp from './components/app.vue';
Vue.use(VueApollo);
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
});
export default () => {
const el = document.getElementById('js-instance-statistics-app');
if (!el) return false;
return new Vue({
el,
apolloProvider,
render(h) {
return h(InstanceStatisticsApp);
},
});
};

View file

@ -1,68 +0,0 @@
import { masks } from 'dateformat';
import { get } from 'lodash';
import { formatDate } from '~/lib/utils/datetime_utility';
const { isoDate } = masks;
/**
* Takes an array of items and returns one item per month with the average of the `count`s from that month
* @param {Array} items
* @param {Number} items[index].count value to be averaged
* @param {String} items[index].recordedAt item dateTime time stamp to be collected into a month
* @param {Object} options
* @param {Object} options.shouldRound an option to specify whether the retuned averages should be rounded
* @return {Array} items collected into [month, average],
* where month is a dateTime string representing the first of the given month
* and average is the average of the count
*/
export function getAverageByMonth(items = [], options = {}) {
const { shouldRound = false } = options;
const itemsMap = items.reduce((memo, item) => {
const { count, recordedAt } = item;
const date = new Date(recordedAt);
const month = formatDate(new Date(date.getFullYear(), date.getMonth(), 1), isoDate);
if (memo[month]) {
const { sum, recordCount } = memo[month];
return { ...memo, [month]: { sum: sum + count, recordCount: recordCount + 1 } };
}
return { ...memo, [month]: { sum: count, recordCount: 1 } };
}, {});
return Object.keys(itemsMap).map((month) => {
const { sum, recordCount } = itemsMap[month];
const avg = sum / recordCount;
if (shouldRound) {
return [month, Math.round(avg)];
}
return [month, avg];
});
}
/**
* Takes an array of instance counts and returns the last item in the list
* @param {Array} arr array of instance counts in the form { count: Number, recordedAt: date String }
* @return {String} the 'recordedAt' value of the earliest item
*/
export const getEarliestDate = (arr = []) => {
const len = arr.length;
return get(arr, `[${len - 1}].recordedAt`, null);
};
/**
* Takes an array of queries and produces an object with the query identifier as key
* and a supplied defaultValue as its value
* @param {Array} queries array of chart query configs,
* see ./analytics/instance_statistics/components/charts_config.js
* @param {any} defaultValue value to set each identifier to
* @return {Object} key value pair of the form { queryIdentifier: defaultValue }
*/
export const generateDataKeys = (queries, defaultValue) =>
queries.reduce(
(acc, { identifier }) => ({
...acc,
[identifier]: defaultValue,
}),
{},
);

View file

@ -0,0 +1,41 @@
<script>
import { TODAY, TOTAL_DAYS_TO_SHOW, START_DATE } from '../constants';
import ChartsConfig from './charts_config';
import UsageCounts from './usage_counts.vue';
import UsageTrendsCountChart from './usage_trends_count_chart.vue';
import UsersChart from './users_chart.vue';
export default {
name: 'UsageTrendsApp',
components: {
UsageCounts,
UsageTrendsCountChart,
UsersChart,
},
TOTAL_DAYS_TO_SHOW,
START_DATE,
TODAY,
configs: ChartsConfig,
};
</script>
<template>
<div>
<usage-counts />
<users-chart
:start-date="$options.START_DATE"
:end-date="$options.TODAY"
:total-data-points="$options.TOTAL_DAYS_TO_SHOW"
/>
<usage-trends-count-chart
v-for="chartOptions in $options.configs"
:key="chartOptions.chartTitle"
:queries="chartOptions.queries"
:x-axis-title="chartOptions.xAxisTitle"
:y-axis-title="chartOptions.yAxisTitle"
:load-chart-error-message="chartOptions.loadChartError"
:no-data-message="chartOptions.noDataMessage"
:chart-title="chartOptions.chartTitle"
/>
</div>
</template>

View file

@ -0,0 +1,106 @@
import { s__, __ } from '~/locale';
import query from '../graphql/queries/usage_count.query.graphql';
const noDataMessage = s__('UsageTrends|No data available.');
export default [
{
loadChartError: s__(
'UsageTrends|Could not load the projects and groups chart. Please refresh the page to try again.',
),
noDataMessage,
chartTitle: s__('UsageTrends|Total projects & groups'),
yAxisTitle: s__('UsageTrends|Total projects & groups'),
xAxisTitle: s__('UsageTrends|Month'),
queries: [
{
query,
title: s__('UsageTrends|Total projects'),
identifier: 'PROJECTS',
loadError: s__('UsageTrends|There was an error fetching the projects. Please try again.'),
},
{
query,
title: s__('UsageTrends|Total groups'),
identifier: 'GROUPS',
loadError: s__('UsageTrends|There was an error fetching the groups. Please try again.'),
},
],
},
{
loadChartError: s__(
'UsageTrends|Could not load the pipelines chart. Please refresh the page to try again.',
),
noDataMessage,
chartTitle: s__('UsageTrends|Pipelines'),
yAxisTitle: s__('UsageTrends|Items'),
xAxisTitle: s__('UsageTrends|Month'),
queries: [
{
query,
title: s__('UsageTrends|Pipelines total'),
identifier: 'PIPELINES',
loadError: s__(
'UsageTrends|There was an error fetching the total pipelines. Please try again.',
),
},
{
query,
title: s__('UsageTrends|Pipelines succeeded'),
identifier: 'PIPELINES_SUCCEEDED',
loadError: s__(
'UsageTrends|There was an error fetching the successful pipelines. Please try again.',
),
},
{
query,
title: s__('UsageTrends|Pipelines failed'),
identifier: 'PIPELINES_FAILED',
loadError: s__(
'UsageTrends|There was an error fetching the failed pipelines. Please try again.',
),
},
{
query,
title: s__('UsageTrends|Pipelines canceled'),
identifier: 'PIPELINES_CANCELED',
loadError: s__(
'UsageTrends|There was an error fetching the cancelled pipelines. Please try again.',
),
},
{
query,
title: s__('UsageTrends|Pipelines skipped'),
identifier: 'PIPELINES_SKIPPED',
loadError: s__(
'UsageTrends|There was an error fetching the skipped pipelines. Please try again.',
),
},
],
},
{
loadChartError: s__(
'UsageTrends|Could not load the issues and merge requests chart. Please refresh the page to try again.',
),
noDataMessage,
chartTitle: s__('UsageTrends|Issues & Merge Requests'),
yAxisTitle: s__('UsageTrends|Items'),
xAxisTitle: s__('UsageTrends|Month'),
queries: [
{
query,
title: __('Issues'),
identifier: 'ISSUES',
loadError: s__('UsageTrends|There was an error fetching the issues. Please try again.'),
},
{
query,
title: __('Merge requests'),
identifier: 'MERGE_REQUESTS',
loadError: s__(
'UsageTrends|There was an error fetching the merge requests. Please try again.',
),
},
],
},
];

View file

@ -0,0 +1,63 @@
<script>
import * as Sentry from '@sentry/browser';
import MetricCard from '~/analytics/shared/components/metric_card.vue';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { number } from '~/lib/utils/unit_format';
import { s__ } from '~/locale';
import usageTrendsCountQuery from '../graphql/queries/usage_trends_count.query.graphql';
const defaultPrecision = 0;
export default {
name: 'UsageCounts',
components: {
MetricCard,
},
data() {
return {
counts: [],
};
},
apollo: {
counts: {
query: usageTrendsCountQuery,
update(data) {
return Object.entries(data).map(([key, obj]) => {
const label = this.$options.i18n.labels[key];
const value = obj.nodes?.length ? number(obj.nodes[0].count, defaultPrecision) : null;
return {
key,
value,
label,
};
});
},
error(error) {
createFlash(this.$options.i18n.loadCountsError);
Sentry.captureException(error);
},
},
},
i18n: {
labels: {
users: s__('UsageTrends|Users'),
projects: s__('UsageTrends|Projects'),
groups: s__('UsageTrends|Groups'),
issues: s__('UsageTrends|Issues'),
mergeRequests: s__('UsageTrends|Merge Requests'),
pipelines: s__('UsageTrends|Pipelines'),
},
loadCountsError: s__('Could not load usage counts. Please refresh the page to try again.'),
},
};
</script>
<template>
<metric-card
:title="__('Usage Trends')"
:metrics="counts"
:is-loading="$apollo.queries.counts.loading"
class="gl-mt-4"
/>
</template>

View file

@ -0,0 +1,206 @@
<script>
import { GlAlert } from '@gitlab/ui';
import { GlLineChart } from '@gitlab/ui/dist/charts';
import * as Sentry from '@sentry/browser';
import { some, every } from 'lodash';
import {
differenceInMonths,
formatDateAsMonth,
getDayDifference,
} from '~/lib/utils/datetime_utility';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
import { TODAY, START_DATE } from '../constants';
import { getAverageByMonth, getEarliestDate, generateDataKeys } from '../utils';
const QUERY_DATA_KEY = 'usageTrendsMeasurements';
export default {
name: 'UsageTrendsCountChart',
components: {
GlLineChart,
GlAlert,
ChartSkeletonLoader,
},
startDate: START_DATE,
endDate: TODAY,
props: {
chartTitle: {
type: String,
required: true,
},
loadChartErrorMessage: {
type: String,
required: true,
},
noDataMessage: {
type: String,
required: true,
},
xAxisTitle: {
type: String,
required: true,
},
yAxisTitle: {
type: String,
required: true,
},
queries: {
type: Array,
required: true,
},
},
data() {
return {
errors: { ...generateDataKeys(this.queries, '') },
...generateDataKeys(this.queries, []),
};
},
computed: {
errorMessages() {
return Object.values(this.errors);
},
isLoading() {
return some(this.$apollo.queries, (query) => query?.loading);
},
allQueriesFailed() {
return every(this.errorMessages, (message) => message.length);
},
hasLoadingErrors() {
return some(this.errorMessages, (message) => message.length);
},
errorMessage() {
// show the generic loading message if all requests fail
return this.allQueriesFailed ? this.loadChartErrorMessage : this.errorMessages.join('\n\n');
},
hasEmptyDataSet() {
return this.chartData.every(({ data }) => data.length === 0);
},
totalDaysToShow() {
return getDayDifference(this.$options.startDate, this.$options.endDate);
},
chartData() {
const options = { shouldRound: true };
return this.queries.map(({ identifier, title }) => ({
name: title,
data: getAverageByMonth(this[identifier]?.nodes, options),
}));
},
range() {
return {
min: this.$options.startDate,
max: this.$options.endDate,
};
},
chartOptions() {
const { endDate, startDate } = this.$options;
return {
xAxis: {
...this.range,
name: this.xAxisTitle,
type: 'time',
splitNumber: differenceInMonths(startDate, endDate) + 1,
axisLabel: {
interval: 0,
showMinLabel: false,
showMaxLabel: false,
align: 'right',
formatter: formatDateAsMonth,
},
},
yAxis: {
name: this.yAxisTitle,
},
};
},
},
created() {
this.queries.forEach(({ query, identifier, loadError }) => {
this.$apollo.addSmartQuery(identifier, {
query,
variables() {
return {
identifier,
first: this.totalDaysToShow,
after: null,
};
},
update(data) {
const { nodes = [], pageInfo } = data[QUERY_DATA_KEY] || {};
return {
nodes,
pageInfo,
};
},
result() {
const { pageInfo, nodes } = this[identifier];
if (pageInfo?.hasNextPage && this.calculateDaysToFetch(getEarliestDate(nodes)) > 0) {
this.fetchNextPage({
query: this.$apollo.queries[identifier],
errorMessage: loadError,
pageInfo,
identifier,
});
}
},
error(error) {
this.handleError({
message: loadError,
identifier,
error,
});
},
});
});
},
methods: {
calculateDaysToFetch(firstDataPointDate = null) {
return firstDataPointDate
? Math.max(0, getDayDifference(this.$options.startDate, new Date(firstDataPointDate)))
: 0;
},
handleError({ identifier, error, message }) {
this.loadingError = true;
this.errors = { ...this.errors, [identifier]: message };
Sentry.captureException(error);
},
fetchNextPage({ query, pageInfo, identifier, errorMessage }) {
query
.fetchMore({
variables: {
identifier,
first: this.calculateDaysToFetch(getEarliestDate(this[identifier].nodes)),
after: pageInfo.endCursor,
},
updateQuery: (previousResult, { fetchMoreResult }) => {
const { nodes, ...rest } = fetchMoreResult[QUERY_DATA_KEY];
const { nodes: previousNodes } = previousResult[QUERY_DATA_KEY];
return {
[QUERY_DATA_KEY]: { ...rest, nodes: [...previousNodes, ...nodes] },
};
},
})
.catch((error) => this.handleError({ identifier, error, message: errorMessage }));
},
},
};
</script>
<template>
<div>
<h3>{{ chartTitle }}</h3>
<gl-alert v-if="hasLoadingErrors" variant="danger" :dismissible="false" class="gl-mt-3">
{{ errorMessage }}
</gl-alert>
<div v-if="!allQueriesFailed">
<chart-skeleton-loader v-if="isLoading" />
<gl-alert v-else-if="hasEmptyDataSet" variant="info" :dismissible="false" class="gl-mt-3">
{{ noDataMessage }}
</gl-alert>
<gl-line-chart
v-else
:option="chartOptions"
:include-legend-avg-max="true"
:data="chartData"
/>
</div>
</div>
</template>

View file

@ -1,11 +1,11 @@
<script> <script>
import { GlAlert } from '@gitlab/ui'; import { GlAlert } from '@gitlab/ui';
import { GlAreaChart } from '@gitlab/ui/dist/charts'; import { GlAreaChart } from '@gitlab/ui/dist/charts';
import * as Sentry from '@sentry/browser';
import produce from 'immer'; import produce from 'immer';
import { sortBy } from 'lodash'; import { sortBy } from 'lodash';
import { formatDateAsMonth } from '~/lib/utils/datetime_utility'; import { formatDateAsMonth } from '~/lib/utils/datetime_utility';
import { __ } from '~/locale'; import { __ } from '~/locale';
import * as Sentry from '~/sentry/wrapper';
import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue'; import ChartSkeletonLoader from '~/vue_shared/components/resizable_chart/skeleton_loader.vue';
import usersQuery from '../graphql/queries/users.query.graphql'; import usersQuery from '../graphql/queries/users.query.graphql';
import { getAverageByMonth } from '../utils'; import { getAverageByMonth } from '../utils';

View file

@ -0,0 +1,4 @@
fragment Count on UsageTrendsMeasurement {
count
recordedAt
}

View file

@ -0,0 +1,13 @@
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "../fragments/count.fragment.graphql"
query getCount($identifier: MeasurementIdentifier!, $first: Int, $after: String) {
usageTrendsMeasurements(identifier: $identifier, first: $first, after: $after) {
nodes {
...Count
}
pageInfo {
...PageInfo
}
}
}

View file

@ -0,0 +1,34 @@
#import "../fragments/count.fragment.graphql"
query getInstanceCounts {
projects: usageTrendsMeasurements(identifier: PROJECTS, first: 1) {
nodes {
...Count
}
}
groups: usageTrendsMeasurements(identifier: GROUPS, first: 1) {
nodes {
...Count
}
}
users: usageTrendsMeasurements(identifier: USERS, first: 1) {
nodes {
...Count
}
}
issues: usageTrendsMeasurements(identifier: ISSUES, first: 1) {
nodes {
...Count
}
}
mergeRequests: usageTrendsMeasurements(identifier: MERGE_REQUESTS, first: 1) {
nodes {
...Count
}
}
pipelines: usageTrendsMeasurements(identifier: PIPELINES, first: 1) {
nodes {
...Count
}
}
}

View file

@ -0,0 +1,13 @@
#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
#import "../fragments/count.fragment.graphql"
query getUsersCount($first: Int, $after: String) {
users: usageTrendsMeasurements(identifier: USERS, first: $first, after: $after) {
nodes {
...Count
}
pageInfo {
...PageInfo
}
}
}

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