Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/review.gitlab-ci.yml2
-rw-r--r--app/assets/javascripts/issuables_list/components/issuables_list_app.vue21
-rw-r--r--app/controllers/concerns/spammable_actions.rb2
-rw-r--r--app/helpers/labels_helper.rb24
-rw-r--r--app/models/service.rb6
-rw-r--r--app/services/concerns/akismet_methods.rb10
-rw-r--r--app/services/spam/ham_service.rb2
-rw-r--r--app/services/spam/mark_as_spam_service.rb14
-rw-r--r--app/services/spam/spam_check_service.rb22
-rw-r--r--app/views/ide/_show.html.haml2
-rw-r--r--changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-ide.yml5
-rw-r--r--doc/development/documentation/site_architecture/index.md44
-rw-r--r--package.json4
-rw-r--r--spec/controllers/projects/issues_controller_spec.rb16
-rw-r--r--spec/frontend/issuables_list/components/issuables_list_app_spec.js141
-rw-r--r--spec/models/service_spec.rb7
-rw-r--r--spec/requests/api/error_tracking_spec.rb2
-rw-r--r--spec/services/spam/mark_as_spam_service_spec.rb2
-rw-r--r--yarn.lock18
19 files changed, 249 insertions, 95 deletions
diff --git a/.gitlab/ci/review.gitlab-ci.yml b/.gitlab/ci/review.gitlab-ci.yml
index 3835ad62ba2..678be464dfe 100644
--- a/.gitlab/ci/review.gitlab-ci.yml
+++ b/.gitlab/ci/review.gitlab-ci.yml
@@ -253,4 +253,4 @@ danger-review:
- git version
- node --version
- yarn install --frozen-lockfile --cache-folder .yarn-cache --prefer-offline
- - danger --fail-on-errors=true
+ - danger --verbose # fail-on-errors=true
diff --git a/app/assets/javascripts/issuables_list/components/issuables_list_app.vue b/app/assets/javascripts/issuables_list/components/issuables_list_app.vue
index 1e071f46347..640827fe564 100644
--- a/app/assets/javascripts/issuables_list/components/issuables_list_app.vue
+++ b/app/assets/javascripts/issuables_list/components/issuables_list_app.vue
@@ -1,9 +1,14 @@
<script>
-import { omit } from 'lodash';
+import { toNumber, omit } from 'lodash';
import { GlEmptyState, GlPagination, GlSkeletonLoading } from '@gitlab/ui';
import flash from '~/flash';
import axios from '~/lib/utils/axios_utils';
-import { scrollToElement, urlParamsToObject } from '~/lib/utils/common_utils';
+import {
+ scrollToElement,
+ urlParamsToObject,
+ historyPushState,
+ getParameterByName,
+} from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import initManualOrdering from '~/manual_ordering';
import Issuable from './issuable.vue';
@@ -14,6 +19,7 @@ import {
PAGE_SIZE_MANUAL,
LOADING_LIST_ITEMS_LENGTH,
} from '../constants';
+import { setUrlParams } from '~/lib/utils/url_utility';
import issueableEventHub from '../eventhub';
export default {
@@ -56,7 +62,10 @@ export default {
isBulkEditing: false,
issuables: [],
loading: false,
- page: 1,
+ page:
+ getParameterByName('page', window.location.href) !== null
+ ? toNumber(getParameterByName('page'))
+ : 1,
selection: {},
totalItems: 0,
};
@@ -189,6 +198,12 @@ export default {
if (newPage === this.page) return;
scrollToElement('#content-body');
+
+ // NOTE: This allows for the params to be updated on pagination
+ historyPushState(
+ setUrlParams({ ...this.filters, page: newPage }, window.location.href, true),
+ );
+
this.fetchIssuables(newPage);
},
onSelectAll() {
diff --git a/app/controllers/concerns/spammable_actions.rb b/app/controllers/concerns/spammable_actions.rb
index 9ec8f930a78..46ba270f328 100644
--- a/app/controllers/concerns/spammable_actions.rb
+++ b/app/controllers/concerns/spammable_actions.rb
@@ -11,7 +11,7 @@ module SpammableActions
end
def mark_as_spam
- if Spam::MarkAsSpamService.new(spammable: spammable).execute
+ if Spam::MarkAsSpamService.new(target: spammable).execute
redirect_to spammable_path, notice: _("%{spammable_titlecase} was submitted to Akismet successfully.") % { spammable_titlecase: spammable.spammable_entity_type.titlecase }
else
redirect_to spammable_path, alert: _('Error with Akismet. Please check the logs for more info.')
diff --git a/app/helpers/labels_helper.rb b/app/helpers/labels_helper.rb
index 97232def91c..3142d7d7782 100644
--- a/app/helpers/labels_helper.rb
+++ b/app/helpers/labels_helper.rb
@@ -115,13 +115,7 @@ module LabelsHelper
end
def text_color_class_for_bg(bg_color)
- if bg_color.length == 4
- r, g, b = bg_color[1, 4].scan(/./).map { |v| (v * 2).hex }
- else
- r, g, b = bg_color[1, 7].scan(/.{2}/).map(&:hex)
- end
-
- if (r + g + b) > 500
+ if light_color?(bg_color)
'gl-label-text-dark'
else
'gl-label-text-light'
@@ -129,17 +123,21 @@ module LabelsHelper
end
def text_color_for_bg(bg_color)
- if bg_color.length == 4
- r, g, b = bg_color[1, 4].scan(/./).map { |v| (v * 2).hex }
+ if light_color?(bg_color)
+ '#333333'
else
- r, g, b = bg_color[1, 7].scan(/.{2}/).map(&:hex)
+ '#FFFFFF'
end
+ end
- if (r + g + b) > 500
- '#333333'
+ def light_color?(color)
+ if color.length == 4
+ r, g, b = color[1, 4].scan(/./).map { |v| (v * 2).hex }
else
- '#FFFFFF'
+ r, g, b = color[1, 7].scan(/.{2}/).map(&:hex)
end
+
+ (r + g + b) > 500
end
def labels_filter_path_with_defaults(only_group_labels: false, include_ancestor_groups: true, include_descendant_groups: false)
diff --git a/app/models/service.rb b/app/models/service.rb
index e60dda59176..41ae197f432 100644
--- a/app/models/service.rb
+++ b/app/models/service.rb
@@ -32,7 +32,7 @@ class Service < ApplicationRecord
belongs_to :project, inverse_of: :services
has_one :service_hook
- validates :project_id, presence: true, unless: proc { |service| service.template? }
+ validates :project_id, presence: true, unless: -> { template? }
validates :type, presence: true
scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
@@ -70,10 +70,6 @@ class Service < ApplicationRecord
true
end
- def template?
- template
- end
-
def category
read_attribute(:category).to_sym
end
diff --git a/app/services/concerns/akismet_methods.rb b/app/services/concerns/akismet_methods.rb
index 105b79785bd..4e554ddac4c 100644
--- a/app/services/concerns/akismet_methods.rb
+++ b/app/services/concerns/akismet_methods.rb
@@ -1,15 +1,15 @@
# frozen_string_literal: true
module AkismetMethods
- def spammable_owner
- @user ||= User.find(spammable.author_id)
+ def target_owner
+ @user ||= User.find(target.author_id)
end
def akismet
@akismet ||= Spam::AkismetService.new(
- spammable_owner.name,
- spammable_owner.email,
- spammable.try(:spammable_text) || spammable&.text,
+ target_owner.name,
+ target_owner.email,
+ target.try(:spammable_text) || target&.text,
options
)
end
diff --git a/app/services/spam/ham_service.rb b/app/services/spam/ham_service.rb
index d0f53eea90c..87069d5cd54 100644
--- a/app/services/spam/ham_service.rb
+++ b/app/services/spam/ham_service.rb
@@ -23,6 +23,6 @@ module Spam
end
end
- alias_method :spammable, :spam_log
+ alias_method :target, :spam_log
end
end
diff --git a/app/services/spam/mark_as_spam_service.rb b/app/services/spam/mark_as_spam_service.rb
index 0ebcf17927a..ed5e674d8e9 100644
--- a/app/services/spam/mark_as_spam_service.rb
+++ b/app/services/spam/mark_as_spam_service.rb
@@ -4,21 +4,21 @@ module Spam
class MarkAsSpamService
include ::AkismetMethods
- attr_accessor :spammable, :options
+ attr_accessor :target, :options
- def initialize(spammable:)
- @spammable = spammable
+ def initialize(target:)
+ @target = target
@options = {}
- @options[:ip_address] = @spammable.ip_address
- @options[:user_agent] = @spammable.user_agent
+ @options[:ip_address] = @target.ip_address
+ @options[:user_agent] = @target.user_agent
end
def execute
- return unless spammable.submittable_as_spam?
+ return unless target.submittable_as_spam?
return unless akismet.submit_spam
- spammable.user_agent_detail.update_attribute(:submitted, true)
+ target.user_agent_detail.update_attribute(:submitted, true)
end
end
end
diff --git a/app/services/spam/spam_check_service.rb b/app/services/spam/spam_check_service.rb
index d19ef03976f..3269f9d687a 100644
--- a/app/services/spam/spam_check_service.rb
+++ b/app/services/spam/spam_check_service.rb
@@ -4,11 +4,11 @@ module Spam
class SpamCheckService
include AkismetMethods
- attr_accessor :spammable, :request, :options
+ attr_accessor :target, :request, :options
attr_reader :spam_log
def initialize(spammable:, request:)
- @spammable = spammable
+ @target = spammable
@request = request
@options = {}
@@ -17,8 +17,8 @@ module Spam
@options[:user_agent] = @request.env['HTTP_USER_AGENT']
@options[:referrer] = @request.env['HTTP_REFERRER']
else
- @options[:ip_address] = @spammable.ip_address
- @options[:user_agent] = @spammable.user_agent
+ @options[:ip_address] = @target.ip_address
+ @options[:user_agent] = @target.user_agent
end
end
@@ -31,8 +31,8 @@ module Spam
# Otherwise, it goes to Akismet for spam check.
# If so, it assigns spammable object as "spam" and creates a SpamLog record.
possible_spam = check(api)
- spammable.spam = possible_spam unless spammable.allow_possible_spam?
- spammable.spam_log = spam_log
+ target.spam = possible_spam unless target.allow_possible_spam?
+ target.spam_log = spam_log
end
end
@@ -48,18 +48,18 @@ module Spam
end
def check_for_spam?
- spammable.check_for_spam?
+ target.check_for_spam?
end
def create_spam_log(api)
@spam_log = SpamLog.create!(
{
- user_id: spammable.author_id,
- title: spammable.spam_title,
- description: spammable.spam_description,
+ user_id: target.author_id,
+ title: target.spam_title,
+ description: target.spam_description,
source_ip: options[:ip_address],
user_agent: options[:user_agent],
- noteable_type: spammable.class.to_s,
+ noteable_type: target.class.to_s,
via_api: api
}
)
diff --git a/app/views/ide/_show.html.haml b/app/views/ide/_show.html.haml
index 057225d021f..b871f0363f3 100644
--- a/app/views/ide/_show.html.haml
+++ b/app/views/ide/_show.html.haml
@@ -6,5 +6,5 @@
#ide.ide-loading{ data: ide_data }
.text-center
- = icon('spinner spin 2x')
+ .spinner.spinner-md
%h2.clgray= _('Loading the GitLab IDE...')
diff --git a/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-ide.yml b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-ide.yml
new file mode 100644
index 00000000000..2b206e3ddb1
--- /dev/null
+++ b/changelogs/unreleased/Resolve-Migrate--fa-spinner-app-views-ide.yml
@@ -0,0 +1,5 @@
+---
+title: Migrate .fa-spinner to .spinner for app/views/ide
+merge_request: 25022
+author: nuwe1
+type: other
diff --git a/doc/development/documentation/site_architecture/index.md b/doc/development/documentation/site_architecture/index.md
index 57a3dde55e6..232bca30e0f 100644
--- a/doc/development/documentation/site_architecture/index.md
+++ b/doc/development/documentation/site_architecture/index.md
@@ -96,6 +96,50 @@ Read through [the global navigation documentation](global_nav.md) to understand:
TBA
-->
+## Pipelines
+
+The pipeline in the `gitlab-docs` project:
+
+- Tests changes to the docs site code.
+- Builds the Docker images used in various pipeline jobs.
+- Builds and deploys the docs site itself.
+- Generates the review apps when the `review-docs-deploy` job is triggered.
+
+### Rebuild the docs site Docker images
+
+Once a week, on Mondays, a scheduled pipeline runs and rebuilds the Docker images
+used in various pipeline jobs, like `docs-lint`. The Docker image configuration files are
+located at <https://gitlab.com/gitlab-org/gitlab-docs/-/tree/master/dockerfiles>.
+
+If you need to rebuild the Docker images immediately (must have maintainer level permissions):
+
+CAUTION: **Caution**
+If you change the dockerfile configuration and rebuild the images, you can break the master
+pipeline in the main `gitlab` repo as well as in `gitlab-docs`. Create an image with
+a different name first and test it to ensure you do not break the pipelines.
+
+1. In [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs), go to **{rocket}** **CI / CD > Pipelines**.
+1. Click the **Run Pipeline** button.
+1. See that a new pipeline is running. The jobs that build the images are in the first
+ stage, `build-images`. You can click the pipeline number to see the larger pipeline
+ graph, or click the first (`build-images`) stage in the mini pipeline graph to
+ expose the jobs that build the images.
+1. Click the **play** (**{play}**) button next to the images you want to rebuild.
+ - Normally, you do not need to rebuild the `image:gitlab-docs-base` image, as it
+ rarely changes. If it does need to be rebuilt, be sure to only run `image:docs-lint`
+ after it is finished rebuilding.
+
+### Deploy the docs site
+
+Every four hours a scheduled pipeline builds and deploys the docs site. The pipeline
+fetches the current docs from the main project's master branch, builds it with Nanoc
+and deploys it to <https://docs.gitlab.com>.
+
+If you need to build and deploy the site immediately (must have maintainer level permissions):
+
+1. In [`gitlab-docs`](https://gitlab.com/gitlab-org/gitlab-docs), go to **{rocket}** **CI / CD > Schedules**.
+1. For the `Build docs.gitlab.com every 4 hours` scheduled pipeline, click the **play** (**{play}**) button.
+
## Using YAML data files
The easiest way to achieve something similar to
diff --git a/package.json b/package.json
index f0ff6c50709..b8304fee6e1 100644
--- a/package.json
+++ b/package.json
@@ -38,8 +38,8 @@
"@babel/plugin-syntax-import-meta": "^7.8.3",
"@babel/preset-env": "^7.8.4",
"@gitlab/at.js": "^1.5.5",
- "@gitlab/svgs": "^1.101.0",
- "@gitlab/ui": "^9.16.0",
+ "@gitlab/svgs": "^1.103.0",
+ "@gitlab/ui": "^9.17.0",
"@gitlab/visual-review-tools": "1.5.1",
"@sentry/browser": "^5.10.2",
"@sourcegraph/code-host-integration": "0.0.30",
diff --git a/spec/controllers/projects/issues_controller_spec.rb b/spec/controllers/projects/issues_controller_spec.rb
index fb4d1cf59fe..806a4e2f52c 100644
--- a/spec/controllers/projects/issues_controller_spec.rb
+++ b/spec/controllers/projects/issues_controller_spec.rb
@@ -740,16 +740,16 @@ describe Projects::IssuesController do
.to log_spam(title: 'Spam title', noteable_type: 'Issue')
end
- it 'renders recaptcha_html json response' do
- update_issue
-
- expect(json_response).to have_key('recaptcha_html')
- end
+ context 'renders properly' do
+ render_views
- it 'returns 200 status' do
- update_issue
+ it 'renders recaptcha_html json response' do
+ update_issue
- expect(response).to have_gitlab_http_status(:ok)
+ expect(response).to have_gitlab_http_status(:ok)
+ expect(json_response).to have_key('recaptcha_html')
+ expect(json_response['recaptcha_html']).not_to be_empty
+ end
end
end
diff --git a/spec/frontend/issuables_list/components/issuables_list_app_spec.js b/spec/frontend/issuables_list/components/issuables_list_app_spec.js
index eafc4d83d87..6b680af354e 100644
--- a/spec/frontend/issuables_list/components/issuables_list_app_spec.js
+++ b/spec/frontend/issuables_list/components/issuables_list_app_spec.js
@@ -12,12 +12,21 @@ import { PAGE_SIZE, PAGE_SIZE_MANUAL, RELATIVE_POSITION } from '~/issuables_list
jest.mock('~/flash', () => jest.fn());
jest.mock('~/issuables_list/eventhub');
+jest.mock('~/lib/utils/common_utils', () => ({
+ ...jest.requireActual('~/lib/utils/common_utils'),
+ scrollToElement: () => {},
+}));
const TEST_LOCATION = `${TEST_HOST}/issues`;
const TEST_ENDPOINT = '/issues';
const TEST_CREATE_ISSUES_PATH = '/createIssue';
const TEST_EMPTY_SVG_PATH = '/emptySvg';
+const setUrl = query => {
+ window.location.href = `${TEST_LOCATION}${query}`;
+ window.location.search = query;
+};
+
const MOCK_ISSUES = Array(PAGE_SIZE_MANUAL)
.fill(0)
.map((_, i) => ({
@@ -267,8 +276,6 @@ describe('Issuables list component', () => {
});
describe('with query params in window.location', () => {
- const query =
- '?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&utf8=%E2%9C%93&weight=0';
const expectedFilters = {
assignee_username: 'root',
author_username: 'root',
@@ -284,32 +291,73 @@ describe('Issuables list component', () => {
sort: 'desc',
};
- beforeEach(() => {
- window.location.href = `${TEST_LOCATION}${query}`;
- window.location.search = query;
- setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
- factory({ sortKey: 'milestone_due_desc' });
- return waitForPromises();
- });
+ describe('when page is not present in params', () => {
+ const query =
+ '?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&utf8=%E2%9C%93&weight=0';
- it('applies filters and sorts', () => {
- expect(wrapper.vm.hasFilters).toBe(true);
- expect(wrapper.vm.filters).toEqual(expectedFilters);
+ beforeEach(() => {
+ setUrl(query);
- expect(apiSpy).toHaveBeenCalledWith(
- expect.objectContaining({
- params: {
- ...expectedFilters,
- with_labels_details: true,
- page: 1,
- per_page: PAGE_SIZE,
- },
- }),
- );
+ setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
+ factory({ sortKey: 'milestone_due_desc' });
+
+ return waitForPromises();
+ });
+
+ afterEach(() => {
+ apiSpy.mockClear();
+ });
+
+ it('applies filters and sorts', () => {
+ expect(wrapper.vm.hasFilters).toBe(true);
+ expect(wrapper.vm.filters).toEqual(expectedFilters);
+
+ expect(apiSpy).toHaveBeenCalledWith(
+ expect.objectContaining({
+ params: {
+ ...expectedFilters,
+ with_labels_details: true,
+ page: 1,
+ per_page: PAGE_SIZE,
+ },
+ }),
+ );
+ });
+
+ it('passes the base url to issuable', () => {
+ expect(findFirstIssuable().props('baseUrl')).toBe(TEST_LOCATION);
+ });
});
- it('passes the base url to issuable', () => {
- expect(findFirstIssuable().props('baseUrl')).toEqual(TEST_LOCATION);
+ describe('when page is present in the param', () => {
+ const query =
+ '?assignee_username=root&author_username=root&confidential=yes&label_name%5B%5D=Aquapod&label_name%5B%5D=Astro&milestone_title=v3.0&my_reaction_emoji=airplane&scope=all&sort=priority&state=opened&utf8=%E2%9C%93&weight=0&page=3';
+
+ beforeEach(() => {
+ setUrl(query);
+
+ setupApiMock(() => [200, MOCK_ISSUES.slice(0)]);
+ factory({ sortKey: 'milestone_due_desc' });
+
+ return waitForPromises();
+ });
+
+ afterEach(() => {
+ apiSpy.mockClear();
+ });
+
+ it('applies filters and sorts', () => {
+ expect(apiSpy).toHaveBeenCalledWith(
+ expect.objectContaining({
+ params: {
+ ...expectedFilters,
+ with_labels_details: true,
+ page: 3,
+ per_page: PAGE_SIZE,
+ },
+ }),
+ );
+ });
});
});
@@ -322,7 +370,7 @@ describe('Issuables list component', () => {
});
it('passes the base url to issuable', () => {
- expect(findFirstIssuable().props('baseUrl')).toEqual(TEST_LOCATION);
+ expect(findFirstIssuable().props('baseUrl')).toBe(TEST_LOCATION);
});
});
@@ -402,4 +450,47 @@ describe('Issuables list component', () => {
});
});
});
+
+ describe('when paginates', () => {
+ const newPage = 3;
+
+ beforeEach(() => {
+ window.history.pushState = jest.fn();
+ setupApiMock(() => [
+ 200,
+ MOCK_ISSUES.slice(0, PAGE_SIZE),
+ {
+ 'x-total': 100,
+ 'x-page': 2,
+ },
+ ]);
+
+ factory();
+
+ return waitForPromises();
+ });
+
+ afterEach(() => {
+ // reset to original value
+ window.history.pushState.mockRestore();
+ });
+
+ it('calls window.history.pushState one time', () => {
+ // Trigger pagination
+ wrapper.find(GlPagination).vm.$emit('input', newPage);
+
+ expect(window.history.pushState).toHaveBeenCalledTimes(1);
+ });
+
+ it('sets params in the url', () => {
+ // Trigger pagination
+ wrapper.find(GlPagination).vm.$emit('input', newPage);
+
+ expect(window.history.pushState).toHaveBeenCalledWith(
+ {},
+ '',
+ `${TEST_LOCATION}?state=opened&order_by=priority&sort=asc&page=${newPage}`,
+ );
+ });
+ });
});
diff --git a/spec/models/service_spec.rb b/spec/models/service_spec.rb
index f58bcbebd67..eaf19bd4fea 100644
--- a/spec/models/service_spec.rb
+++ b/spec/models/service_spec.rb
@@ -10,8 +10,13 @@ describe Service do
it { is_expected.to have_one :issue_tracker_data }
end
- describe 'Validations' do
+ describe 'validations' do
it { is_expected.to validate_presence_of(:type) }
+
+ it 'validates presence of project_id if not template', :aggregate_failures do
+ expect(build(:service, project_id: nil, template: true)).to be_valid
+ expect(build(:service, project_id: nil, template: false)).to be_invalid
+ end
end
describe 'Scopes' do
diff --git a/spec/requests/api/error_tracking_spec.rb b/spec/requests/api/error_tracking_spec.rb
index 120248bdbc6..deed9777025 100644
--- a/spec/requests/api/error_tracking_spec.rb
+++ b/spec/requests/api/error_tracking_spec.rb
@@ -22,7 +22,7 @@ describe API::ErrorTracking do
end
shared_examples 'returns 404' do
- it 'returns correct project settings' do
+ it 'returns no project settings' do
make_request
expect(response).to have_gitlab_http_status(:not_found)
diff --git a/spec/services/spam/mark_as_spam_service_spec.rb b/spec/services/spam/mark_as_spam_service_spec.rb
index cba9d6a39cb..9978005279a 100644
--- a/spec/services/spam/mark_as_spam_service_spec.rb
+++ b/spec/services/spam/mark_as_spam_service_spec.rb
@@ -7,7 +7,7 @@ describe Spam::MarkAsSpamService do
let(:spammable) { build(:issue, user_agent_detail: user_agent_detail) }
let(:fake_akismet_service) { double(:akismet_service, submit_spam: true) }
- subject { described_class.new(spammable: spammable) }
+ subject { described_class.new(target: spammable) }
describe '#execute' do
before do
diff --git a/yarn.lock b/yarn.lock
index 50899ad79e5..07e119260ea 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -796,15 +796,15 @@
dependencies:
vue-eslint-parser "^7.0.0"
-"@gitlab/svgs@^1.101.0":
- version "1.101.0"
- resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.101.0.tgz#5440ada1774758e42fd67212d495a29523dd0d5e"
- integrity sha512-GE6wRn0UqA5f0pmX5wL/vTgUnAgZEdTIDam+OTMuMxf5a1jfxc1KlSLudgZbS3O/W79jN4uMkTdZ7X8gEzAChw==
-
-"@gitlab/ui@^9.16.0":
- version "9.16.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.16.0.tgz#ac66b55cffdfd9ac2df2abddb11445edc3494732"
- integrity sha512-9PbFgqNxIAGn1LyIcnlqQuNGAiBT/fqTx8vPdaDQkdScFZksZOBwiIhpxnRk9UFABC3h+0TNeHgVigD7TKGqJw==
+"@gitlab/svgs@^1.103.0":
+ version "1.103.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.103.0.tgz#fb7136df9f5df3f53685740daf0ebf565b735608"
+ integrity sha512-+Bt+a8ln9KSz3QxB2P57ub71/eiEnKXJQSheTagYh2KlT6Glzh7XeLjyc3W6uGWBOONqsp96H/tYEa9dmDnLqQ==
+
+"@gitlab/ui@^9.17.0":
+ version "9.17.0"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-9.17.0.tgz#2c2e0412b8293889ab3c2e8f9d7ae1e4b9b508b7"
+ integrity sha512-6Ph3eE7ygUc6A72J6+mfce/MQSkyN4Rl2moSIZeMcAnHhIXBn6qoj4+Pq+jTWXYFqy3/ow6Iddle63Flj1dnkA==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"