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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-09-28 12:09:28 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-09-28 12:09:28 +0300
commitf3cfb235c76426ce5a18003bb80ba625097bf1d0 (patch)
tree01705538824afb4ef6651d3e013c9e2411c08891
parentf8184e504b8aa6f77b42583a9fd08daebbdcc8ab (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--.rubocop_todo/gitlab/no_code_coverage_comment.yml3
-rw-r--r--app/assets/javascripts/error_tracking/components/error_details.vue8
-rw-r--r--app/assets/javascripts/error_tracking/store/actions.js4
-rw-r--r--app/assets/javascripts/error_tracking/store/details/actions.js4
-rw-r--r--app/assets/javascripts/error_tracking/store/list/actions.js4
-rw-r--r--app/assets/javascripts/error_tracking_settings/store/actions.js4
-rw-r--r--app/assets/javascripts/feature_flags/components/environments_dropdown.vue4
-rw-r--r--app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue4
-rw-r--r--app/assets/javascripts/feature_flags/store/edit/actions.js4
-rw-r--r--app/assets/javascripts/feature_highlight/feature_highlight_helper.js4
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_ajax_filter.js4
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_emoji.js4
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_non_user.js4
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js4
-rw-r--r--app/assets/javascripts/filtered_search/visual_token_value.js6
-rw-r--r--app/assets/javascripts/gpg_badges.js4
-rw-r--r--app/assets/javascripts/grafana_integration/store/actions.js4
-rw-r--r--app/assets/javascripts/group.js6
-rw-r--r--app/assets/javascripts/groups/components/app.vue6
-rw-r--r--app/assets/javascripts/groups/settings/components/access_dropdown.vue4
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/modal.vue4
-rw-r--r--app/assets/javascripts/ide/components/repo_editor.vue6
-rw-r--r--app/assets/javascripts/ide/stores/actions.js6
-rw-r--r--app/assets/javascripts/ide/stores/actions/merge_request.js6
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js6
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js4
-rw-r--r--app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js6
-rw-r--r--app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js4
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table.vue4
-rw-r--r--app/assets/javascripts/import_entities/import_groups/services/status_poller.js4
-rw-r--r--app/assets/javascripts/import_entities/import_projects/store/actions.js12
-rw-r--r--app/assets/javascripts/milestones/components/promote_milestone_modal.vue4
-rw-r--r--app/assets/javascripts/milestones/milestone.js4
-rw-r--r--app/assets/javascripts/mirrors/mirror_repos.js4
-rw-r--r--app/assets/javascripts/mirrors/ssh_mirror.js4
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard.vue8
-rw-r--r--app/assets/javascripts/monitoring/stores/actions.js30
-rw-r--r--app/assets/javascripts/namespaces/leave_by_url.js4
-rw-r--r--app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue4
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js4
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/edit/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/project.js4
-rw-r--r--app/assets/javascripts/pages/sessions/new/username_validator.js4
-rw-r--r--app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue4
-rw-r--r--app/assets/javascripts/pages/users/activity_calendar.js4
-rw-r--r--app/assets/javascripts/persistent_user_callout.js6
-rw-r--r--app/assets/javascripts/projects/settings/access_dropdown.js6
-rw-r--r--app/assets/javascripts/projects/settings/components/access_dropdown.vue6
-rw-r--r--app/assets/javascripts/projects/settings/repository/branch_rules/app.vue4
-rw-r--r--app/assets/javascripts/projects/star.js4
-rw-r--r--app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue4
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_create.js4
-rw-r--r--app/assets/javascripts/protected_branches/protected_branch_edit.js6
-rw-r--r--app/assets/javascripts/protected_tags/protected_tag_edit.js4
-rw-r--r--app/assets/javascripts/related_issues/components/related_issues_root.vue12
-rw-r--r--app/assets/javascripts/releases/components/app_index.vue4
-rw-r--r--app/assets/javascripts/releases/components/app_show.vue4
-rw-r--r--app/assets/javascripts/releases/stores/modules/edit_new/actions.js14
-rw-r--r--app/assets/javascripts/work_items/components/work_item_assignees.vue3
-rw-r--r--app/assets/javascripts/work_items/components/work_item_labels.vue3
-rw-r--r--app/assets/javascripts/work_items/pages/create_work_item.vue43
-rw-r--r--app/models/bulk_imports/entity.rb16
-rw-r--r--app/views/admin/application_settings/_network_rate_limits.html.haml2
-rw-r--r--app/views/admin/application_settings/_outbound.html.haml2
-rw-r--r--app/views/admin/application_settings/_prometheus.html.haml2
-rw-r--r--app/views/shared/issuable/_form.html.haml4
-rw-r--r--app/views/shared/web_hooks/_index.html.haml25
-rw-r--r--app/workers/bulk_import_worker.rb5
-rw-r--r--app/workers/bulk_imports/export_request_worker.rb59
-rw-r--r--doc/administration/auth/atlassian.md12
-rw-r--r--doc/administration/auth/authentiq.md24
-rw-r--r--doc/administration/sidekiq/index.md4
-rw-r--r--doc/architecture/blueprints/work_items/index.md130
-rw-r--r--doc/development/gitlab_flavored_markdown/specification_guide/index.md62
-rw-r--r--doc/user/group/epics/manage_epics.md2
-rw-r--r--doc/user/markdown.md1
-rw-r--r--lib/bulk_imports/common/rest/get_badges_query.rb5
-rw-r--r--lib/bulk_imports/groups/extractors/subgroups_extractor.rb4
-rw-r--r--lib/bulk_imports/groups/graphql/get_group_query.rb2
-rw-r--r--lib/bulk_imports/groups/graphql/get_projects_query.rb1
-rw-r--r--lib/bulk_imports/groups/pipelines/project_entities_pipeline.rb3
-rw-r--r--lib/bulk_imports/groups/transformers/group_attributes_transformer.rb97
-rw-r--r--lib/bulk_imports/projects/graphql/get_project_query.rb1
-rw-r--r--locale/gitlab.pot3
-rw-r--r--spec/factories/bulk_import/entities.rb1
-rw-r--r--spec/frontend/commit/commit_pipeline_status_component_spec.js4
-rw-r--r--spec/frontend/error_tracking/components/error_details_spec.js8
-rw-r--r--spec/frontend/error_tracking/store/actions_spec.js6
-rw-r--r--spec/frontend/error_tracking/store/details/actions_spec.js6
-rw-r--r--spec/frontend/error_tracking/store/list/actions_spec.js4
-rw-r--r--spec/frontend/feature_highlight/feature_highlight_helper_spec.js4
-rw-r--r--spec/frontend/grafana_integration/components/grafana_integration_spec.js6
-rw-r--r--spec/frontend/groups/components/app_spec.js8
-rw-r--r--spec/frontend/ide/components/new_dropdown/modal_spec.js10
-rw-r--r--spec/frontend/ide/stores/actions/merge_request_spec.js8
-rw-r--r--spec/frontend/ide/stores/actions/project_spec.js6
-rw-r--r--spec/frontend/ide/stores/actions_spec.js12
-rw-r--r--spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js6
-rw-r--r--spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js4
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_spec.js4
-rw-r--r--spec/frontend/import_entities/import_groups/services/status_poller_spec.js4
-rw-r--r--spec/frontend/import_entities/import_projects/store/actions_spec.js10
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_root_spec.js8
-rw-r--r--spec/frontend/milestones/components/promote_milestone_modal_spec.js4
-rw-r--r--spec/frontend/monitoring/components/dashboard_spec.js8
-rw-r--r--spec/frontend/monitoring/components/dashboard_url_time_spec.js4
-rw-r--r--spec/frontend/monitoring/store/actions_spec.js20
-rw-r--r--spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js4
-rw-r--r--spec/frontend/persistent_user_callout_spec.js6
-rw-r--r--spec/frontend/projects/settings/repository/branch_rules/app_spec.js4
-rw-r--r--spec/frontend/protected_branches/protected_branch_edit_spec.js6
-rw-r--r--spec/frontend/releases/components/app_index_spec.js6
-rw-r--r--spec/frontend/releases/components/app_show_spec.js6
-rw-r--r--spec/frontend/releases/stores/modules/detail/actions_spec.js34
-rw-r--r--spec/frontend/work_items/components/work_item_assignees_spec.js4
-rw-r--r--spec/frontend/work_items/components/work_item_labels_spec.js4
-rw-r--r--spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb2
-rw-r--r--spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb4
-rw-r--r--spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb31
-rw-r--r--spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb2
-rw-r--r--spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb2
-rw-r--r--spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb78
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb5
-rw-r--r--spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb5
-rw-r--r--spec/models/bulk_imports/entity_spec.rb12
-rw-r--r--spec/spec_helper.rb2
-rw-r--r--spec/support/helpers/html_escaped_helpers.rb31
-rw-r--r--spec/support/shared_contexts/html_safe_shared_context.rb23
-rw-r--r--spec/support/shared_contexts/views/html_safe_render_shared_context.rb39
-rw-r--r--spec/support/view_component.rb7
-rw-r--r--spec/support_specs/helpers/html_escaped_helpers_spec.rb29
-rw-r--r--spec/workers/bulk_import_worker_spec.rb3
-rw-r--r--spec/workers/bulk_imports/export_request_worker_spec.rb67
133 files changed, 848 insertions, 553 deletions
diff --git a/.rubocop_todo/gitlab/no_code_coverage_comment.yml b/.rubocop_todo/gitlab/no_code_coverage_comment.yml
index f4d50fda11b..0dcee5f32ee 100644
--- a/.rubocop_todo/gitlab/no_code_coverage_comment.yml
+++ b/.rubocop_todo/gitlab/no_code_coverage_comment.yml
@@ -7,10 +7,9 @@ Gitlab/NoCodeCoverageComment:
- 'app/workers/database/batched_background_migration/single_database_worker.rb'
- 'config/initializers/net_http_response_patch.rb'
- 'ee/app/models/concerns/geo/replicable_model.rb'
- - 'ee/app/services/namespaces/free_user_cap/remove_group_group_links_outside_hierarchy_service.rb'
- - 'ee/app/workers/namespaces/free_user_cap/remediation_worker.rb'
- 'ee/lib/gitlab/geo/replicator.rb'
- 'lib/gitlab/auth/o_auth/session.rb'
+ - 'lib/gitlab/cleanup/personal_access_tokens.rb'
- 'lib/gitlab/cycle_analytics/summary/defaults.rb'
- 'lib/gitlab/database/background_migration/health_status/signals.rb'
- 'lib/gitlab/seeder.rb'
diff --git a/app/assets/javascripts/error_tracking/components/error_details.vue b/app/assets/javascripts/error_tracking/components/error_details.vue
index a602c92a840..b02c3cd2cba 100644
--- a/app/assets/javascripts/error_tracking/components/error_details.vue
+++ b/app/assets/javascripts/error_tracking/components/error_details.vue
@@ -13,7 +13,7 @@ import {
GlIcon,
} from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
-import createFlash from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/flash';
import { __, sprintf, n__ } from '~/locale';
import Tracking from '~/tracking';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
@@ -89,7 +89,7 @@ export default {
pollInterval: 2000,
update: (data) => data.project.sentryErrors.detailedError,
error: () =>
- createFlash({
+ createAlert({
message: __('Failed to load error details from Sentry.'),
}),
result(res) {
@@ -234,9 +234,9 @@ export default {
if (Date.now() > this.errorPollTimeout) {
this.$apollo.queries.error.stopPolling();
this.errorLoading = false;
- createFlash({
+ createAlert({
message: __('Could not connect to Sentry. Refresh the page to try again.'),
- type: 'warning',
+ variant: VARIANT_WARNING,
});
}
},
diff --git a/app/assets/javascripts/error_tracking/store/actions.js b/app/assets/javascripts/error_tracking/store/actions.js
index fbfcd6ce2df..603f8611005 100644
--- a/app/assets/javascripts/error_tracking/store/actions.js
+++ b/app/assets/javascripts/error_tracking/store/actions.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { visitUrl } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import service from '../services';
@@ -18,7 +18,7 @@ export const updateStatus = ({ commit }, { endpoint, redirectUrl, status }) =>
return resp.data.result;
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Failed to update issue status'),
}),
);
diff --git a/app/assets/javascripts/error_tracking/store/details/actions.js b/app/assets/javascripts/error_tracking/store/details/actions.js
index 09fa650f64b..1409399940a 100644
--- a/app/assets/javascripts/error_tracking/store/details/actions.js
+++ b/app/assets/javascripts/error_tracking/store/details/actions.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import Poll from '~/lib/utils/poll';
import { __ } from '~/locale';
import service from '../../services';
@@ -26,7 +26,7 @@ export function startPollingStacktrace({ commit }, endpoint) {
},
errorCallback: () => {
commit(types.SET_LOADING_STACKTRACE, false);
- createFlash({
+ createAlert({
message: __('Failed to load stacktrace.'),
});
},
diff --git a/app/assets/javascripts/error_tracking/store/list/actions.js b/app/assets/javascripts/error_tracking/store/list/actions.js
index 418056314f6..f633711add3 100644
--- a/app/assets/javascripts/error_tracking/store/list/actions.js
+++ b/app/assets/javascripts/error_tracking/store/list/actions.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import Poll from '~/lib/utils/poll';
import { __ } from '~/locale';
import Service from '../../services';
@@ -33,7 +33,7 @@ export function startPolling({ state, commit, dispatch }) {
},
errorCallback: () => {
commit(types.SET_LOADING, false);
- createFlash({
+ createAlert({
message: __('Failed to load errors from Sentry.'),
});
},
diff --git a/app/assets/javascripts/error_tracking_settings/store/actions.js b/app/assets/javascripts/error_tracking_settings/store/actions.js
index 972ad58c617..4d6fe767f3a 100644
--- a/app/assets/javascripts/error_tracking_settings/store/actions.js
+++ b/app/assets/javascripts/error_tracking_settings/store/actions.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -46,7 +46,7 @@ export const requestSettings = ({ commit }) => {
export const receiveSettingsError = ({ commit }, { response = {} }) => {
const message = response.data && response.data.message ? response.data.message : '';
- createFlash({
+ createAlert({
message: `${__('There was an error saving your changes.')} ${message}`,
});
commit(types.UPDATE_SETTINGS_LOADING, false);
diff --git a/app/assets/javascripts/feature_flags/components/environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
index 70b60b4b113..ce5f7915dbf 100644
--- a/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
+++ b/app/assets/javascripts/feature_flags/components/environments_dropdown.vue
@@ -1,7 +1,7 @@
<script>
import { GlButton, GlSearchBoxByType } from '@gitlab/ui';
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -87,7 +87,7 @@ export default {
.catch(() => {
this.isLoading = false;
this.closeSuggestions();
- createFlash({
+ createAlert({
message: __('Something went wrong on our end. Please try again.'),
});
});
diff --git a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
index 98982920121..89400bc4742 100644
--- a/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
+++ b/app/assets/javascripts/feature_flags/components/new_environments_dropdown.vue
@@ -8,7 +8,7 @@ import {
GlSearchBoxByType,
} from '@gitlab/ui';
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __, sprintf } from '~/locale';
@@ -52,7 +52,7 @@ export default {
this.results = data || [];
})
.catch(() => {
- createFlash({
+ createAlert({
message: __('Something went wrong on our end. Please try again.'),
});
})
diff --git a/app/assets/javascripts/feature_flags/store/edit/actions.js b/app/assets/javascripts/feature_flags/store/edit/actions.js
index 8656479190a..97c22781ac5 100644
--- a/app/assets/javascripts/feature_flags/store/edit/actions.js
+++ b/app/assets/javascripts/feature_flags/store/edit/actions.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -49,7 +49,7 @@ export const receiveFeatureFlagSuccess = ({ commit }, response) =>
commit(types.RECEIVE_FEATURE_FLAG_SUCCESS, response);
export const receiveFeatureFlagError = ({ commit }) => {
commit(types.RECEIVE_FEATURE_FLAG_ERROR);
- createFlash({
+ createAlert({
message: __('Something went wrong on our end. Please try again!'),
});
};
diff --git a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
index b26a96499ba..a9542a9667e 100644
--- a/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
+++ b/app/assets/javascripts/feature_highlight/feature_highlight_helper.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -10,7 +10,7 @@ export function dismiss(endpoint, highlightId) {
feature_name: highlightId,
})
.catch(() =>
- createFlash({
+ createAlert({
message: __(
'An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again.',
),
diff --git a/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js b/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js
index 9726b2164b7..23591fc0667 100644
--- a/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js
+++ b/app/assets/javascripts/filtered_search/dropdown_ajax_filter.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import AjaxFilter from './droplab/plugins/ajax_filter';
import DropdownUtils from './dropdown_utils';
@@ -27,7 +27,7 @@ export default class DropdownAjaxFilter extends FilteredSearchDropdown {
searchValueFunction: this.getSearchInput.bind(this),
loadingTemplate: this.loadingTemplate,
onError() {
- createFlash({
+ createAlert({
message: __('An error occurred fetching the dropdown data.'),
});
},
diff --git a/app/assets/javascripts/filtered_search/dropdown_emoji.js b/app/assets/javascripts/filtered_search/dropdown_emoji.js
index aeea66bf51c..8c50c1860ec 100644
--- a/app/assets/javascripts/filtered_search/dropdown_emoji.js
+++ b/app/assets/javascripts/filtered_search/dropdown_emoji.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import Ajax from './droplab/plugins/ajax';
import Filter from './droplab/plugins/filter';
@@ -14,7 +14,7 @@ export default class DropdownEmoji extends FilteredSearchDropdown {
method: 'setData',
loadingTemplate: this.loadingTemplate,
onError() {
- createFlash({
+ createAlert({
message: __('An error occurred fetching the dropdown data.'),
});
},
diff --git a/app/assets/javascripts/filtered_search/dropdown_non_user.js b/app/assets/javascripts/filtered_search/dropdown_non_user.js
index ddc3c06a9d1..ab95986dc62 100644
--- a/app/assets/javascripts/filtered_search/dropdown_non_user.js
+++ b/app/assets/javascripts/filtered_search/dropdown_non_user.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import Ajax from './droplab/plugins/ajax';
import Filter from './droplab/plugins/filter';
@@ -17,7 +17,7 @@ export default class DropdownNonUser extends FilteredSearchDropdown {
loadingTemplate: this.loadingTemplate,
preprocessing,
onError() {
- createFlash({
+ createAlert({
message: __('An error occurred fetching the dropdown data.'),
});
},
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index ac2cf27e873..bc0f5398b4c 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -1,7 +1,7 @@
import { last } from 'lodash';
import recentSearchesStorageKeys from 'ee_else_ce/filtered_search/recent_searches_storage_keys';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import {
ENTER_KEY_CODE,
BACKSPACE_KEY_CODE,
@@ -91,7 +91,7 @@ export default class FilteredSearchManager {
.fetch()
.catch((error) => {
if (error.name === 'RecentSearchesServiceError') return undefined;
- createFlash({
+ createAlert({
message: __('An error occurred while parsing recent searches'),
});
// Gracefully fail to empty array
diff --git a/app/assets/javascripts/filtered_search/visual_token_value.js b/app/assets/javascripts/filtered_search/visual_token_value.js
index 0d144398531..1ad2006d689 100644
--- a/app/assets/javascripts/filtered_search/visual_token_value.js
+++ b/app/assets/javascripts/filtered_search/visual_token_value.js
@@ -4,7 +4,7 @@ import * as Emoji from '~/emoji';
import FilteredSearchContainer from '~/filtered_search/container';
import DropdownUtils from '~/filtered_search/dropdown_utils';
import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import AjaxCache from '~/lib/utils/ajax_cache';
import UsersCache from '~/lib/utils/users_cache';
import { __ } from '~/locale';
@@ -85,7 +85,7 @@ export default class VisualTokenValue {
);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while fetching label colors.'),
}),
);
@@ -111,7 +111,7 @@ export default class VisualTokenValue {
VisualTokenValue.replaceEpicTitle(tokenValueContainer, matchingEpic.title, matchingEpic.id);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while adding formatted title for epic'),
}),
);
diff --git a/app/assets/javascripts/gpg_badges.js b/app/assets/javascripts/gpg_badges.js
index d376c9f76ba..0a4733de65f 100644
--- a/app/assets/javascripts/gpg_badges.js
+++ b/app/assets/javascripts/gpg_badges.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { queryToObject } from '~/lib/utils/url_utility';
import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
@@ -19,7 +19,7 @@ export default class GpgBadges {
badges.children().attr('aria-label', __('Loading'));
const displayError = () =>
- createFlash({
+ createAlert({
message: __('An error occurred while loading commit signatures'),
});
diff --git a/app/assets/javascripts/grafana_integration/store/actions.js b/app/assets/javascripts/grafana_integration/store/actions.js
index 25347ad6433..db2fd3cc256 100644
--- a/app/assets/javascripts/grafana_integration/store/actions.js
+++ b/app/assets/javascripts/grafana_integration/store/actions.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
@@ -38,7 +38,7 @@ export const receiveGrafanaIntegrationUpdateError = (_, error) => {
const { response } = error;
const message = response.data && response.data.message ? response.data.message : '';
- createFlash({
+ createAlert({
message: `${__('There was an error saving your changes.')} ${message}`,
});
};
diff --git a/app/assets/javascripts/group.js b/app/assets/javascripts/group.js
index 49e7dd28ff6..cc70d832edc 100644
--- a/app/assets/javascripts/group.js
+++ b/app/assets/javascripts/group.js
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import { getGroupPathAvailability } from '~/rest_api';
import axios from '~/lib/utils/axios_utils';
@@ -77,7 +77,7 @@ export default class Group {
element.value = suggestedSlug;
});
} else if (exists && !suggests.length) {
- createFlash({
+ createAlert({
message: __('Unable to suggest a path. Please refresh and try again.'),
});
}
@@ -87,7 +87,7 @@ export default class Group {
return;
}
- createFlash({
+ createAlert({
message: __('An error occurred while checking group path. Please refresh and try again.'),
});
});
diff --git a/app/assets/javascripts/groups/components/app.vue b/app/assets/javascripts/groups/components/app.vue
index 0bd7371d39b..6caf5aa8e94 100644
--- a/app/assets/javascripts/groups/components/app.vue
+++ b/app/assets/javascripts/groups/components/app.vue
@@ -1,6 +1,6 @@
<script>
import { GlLoadingIcon, GlModal } from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { mergeUrlParams, getParameterByName } from '~/lib/utils/url_utility';
import { HIDDEN_CLASS } from '~/lib/utils/constants';
import { __, s__, sprintf } from '~/locale';
@@ -132,7 +132,7 @@ export default {
this.isLoading = false;
window.scrollTo({ top: 0, behavior: 'smooth' });
- createFlash({ message: COMMON_STR.FAILURE });
+ createAlert({ message: COMMON_STR.FAILURE });
});
},
fetchAllGroups() {
@@ -218,7 +218,7 @@ export default {
if (err.status === 403) {
message = COMMON_STR.LEAVE_FORBIDDEN;
}
- createFlash({ message });
+ createAlert({ message });
this.targetGroup.isBeingRemoved = false;
});
},
diff --git a/app/assets/javascripts/groups/settings/components/access_dropdown.vue b/app/assets/javascripts/groups/settings/components/access_dropdown.vue
index 28f059fa23e..db8e424e166 100644
--- a/app/assets/javascripts/groups/settings/components/access_dropdown.vue
+++ b/app/assets/javascripts/groups/settings/components/access_dropdown.vue
@@ -1,7 +1,7 @@
<script>
import { GlDropdown, GlDropdownItem, GlDropdownSectionHeader, GlSearchBoxByType } from '@gitlab/ui';
import { debounce, intersectionWith, groupBy, differenceBy, intersectionBy } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __, s__, n__ } from '~/locale';
import { getSubGroups } from '../api/access_dropdown_api';
import { LEVEL_TYPES } from '../constants';
@@ -98,7 +98,7 @@ export default {
this.consolidateData(groupsResponse.data);
this.setSelected({ initial });
})
- .catch(() => createFlash({ message: __('Failed to load groups.') }))
+ .catch(() => createAlert({ message: __('Failed to load groups.') }))
.finally(() => {
this.initialLoading = false;
this.loading = false;
diff --git a/app/assets/javascripts/ide/components/new_dropdown/modal.vue b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
index 9684bf8f18c..dbfaeba9708 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/modal.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/modal.vue
@@ -1,7 +1,7 @@
<script>
import { GlModal, GlButton } from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __, sprintf } from '~/locale';
import { modalTypes } from '../../constants';
import { trimPathComponents, getPathParent } from '../../utils';
@@ -77,7 +77,7 @@ export default {
if (this.modalType === modalTypes.rename) {
if (this.entries[this.entryName] && !this.entries[this.entryName].deleted) {
- createFlash({
+ createAlert({
message: sprintf(__('The name "%{name}" is already taken in this directory.'), {
name: this.entryName,
}),
diff --git a/app/assets/javascripts/ide/components/repo_editor.vue b/app/assets/javascripts/ide/components/repo_editor.vue
index a1396995a3b..5f35dbdc5e7 100644
--- a/app/assets/javascripts/ide/components/repo_editor.vue
+++ b/app/assets/javascripts/ide/components/repo_editor.vue
@@ -11,7 +11,7 @@ import {
import { SourceEditorExtension } from '~/editor/extensions/source_editor_extension_base';
import { EditorWebIdeExtension } from '~/editor/extensions/source_editor_webide_ext';
import SourceEditor from '~/editor/source_editor';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import ModelManager from '~/ide/lib/common/model_manager';
import { defaultDiffEditorOptions, defaultEditorOptions } from '~/ide/lib/editor_options';
import { __ } from '~/locale';
@@ -239,7 +239,7 @@ export default {
this.createEditorInstance();
})
.catch((err) => {
- createFlash({
+ createAlert({
message: __('Error setting up editor. Please try again.'),
fadeTransition: false,
addBodyClass: true,
@@ -331,7 +331,7 @@ export default {
useLivePreviewExtension();
})
.catch((e) =>
- createFlash({
+ createAlert({
message: e,
}),
);
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index b22e58a376d..dc0f3a1d7e9 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -1,6 +1,6 @@
import { escape } from 'lodash';
import Vue from 'vue';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { visitUrl } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import {
@@ -36,7 +36,7 @@ export const createTempEntry = (
const fullName = name.slice(-1) !== '/' && type === 'tree' ? `${name}/` : name;
if (getters.entryExists(name)) {
- createFlash({
+ createAlert({
message: sprintf(__('The name "%{name}" is already taken in this directory.'), {
name: name.split('/').pop(),
}),
@@ -281,7 +281,7 @@ export const getBranchData = ({ commit, state }, { projectId, branchId, force =
if (e.response.status === 404) {
reject(e);
} else {
- createFlash({
+ createAlert({
message: __('Error loading branch data. Please try again.'),
fadeTransition: false,
addBodyClass: true,
diff --git a/app/assets/javascripts/ide/stores/actions/merge_request.js b/app/assets/javascripts/ide/stores/actions/merge_request.js
index f3f603d4ae9..cd8088bf667 100644
--- a/app/assets/javascripts/ide/stores/actions/merge_request.js
+++ b/app/assets/javascripts/ide/stores/actions/merge_request.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import { leftSidebarViews, PERMISSION_READ_MR, MAX_MR_FILES_AUTO_OPEN } from '../../constants';
import service from '../../services';
@@ -34,7 +34,7 @@ export const getMergeRequestsForBranch = (
}
})
.catch((e) => {
- createFlash({
+ createAlert({
message: __(`Error fetching merge requests for ${branchId}`),
fadeTransition: false,
addBodyClass: true,
@@ -233,7 +233,7 @@ export const openMergeRequest = async (
await dispatch('openMergeRequestChanges', changes);
} catch (e) {
- createFlash({ message: __('Error while loading the merge request. Please try again.') });
+ createAlert({ message: __('Error while loading the merge request. Please try again.') });
throw e;
}
};
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index 37a405e3fac..7a6a267e7d0 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -1,5 +1,5 @@
import { escape } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __, sprintf } from '~/locale';
import { logError } from '~/lib/logger';
import api from '~/api';
@@ -11,7 +11,7 @@ const ERROR_LOADING_PROJECT = __('Error loading project data. Please try again.'
const errorFetchingData = (e) => {
logError(ERROR_LOADING_PROJECT, e);
- createFlash({
+ createAlert({
message: ERROR_LOADING_PROJECT,
fadeTransition: false,
addBodyClass: true,
@@ -51,7 +51,7 @@ export const refreshLastCommitData = ({ commit }, { projectId, branchId } = {})
});
})
.catch((e) => {
- createFlash({
+ createAlert({
message: __('Error loading last commit.'),
fadeTransition: false,
addBodyClass: true,
diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js
index 2ff71523b1b..cbc6e0fe519 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { addNumericSuffix } from '~/ide/utils';
import { sprintf, __ } from '~/locale';
import { leftSidebarViews } from '../../../constants';
@@ -143,7 +143,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
commit(types.UPDATE_LOADING, false);
if (!data.short_id) {
- createFlash({
+ createAlert({
message: data.message,
fadeTransition: false,
addBodyClass: true,
diff --git a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js
index 82d9300d30b..91868132a5a 100644
--- a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js
+++ b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_controls.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import httpStatus from '~/lib/utils/http_status';
import * as terminalService from '../../../../services/terminals';
@@ -26,7 +26,7 @@ export const receiveStartSessionSuccess = ({ commit, dispatch }, data) => {
};
export const receiveStartSessionError = ({ dispatch }) => {
- createFlash({ message: messages.UNEXPECTED_ERROR_STARTING });
+ createAlert({ message: messages.UNEXPECTED_ERROR_STARTING });
dispatch('killSession');
};
@@ -59,7 +59,7 @@ export const receiveStopSessionSuccess = ({ dispatch }) => {
};
export const receiveStopSessionError = ({ dispatch }) => {
- createFlash({ message: messages.UNEXPECTED_ERROR_STOPPING });
+ createAlert({ message: messages.UNEXPECTED_ERROR_STOPPING });
dispatch('killSession');
};
diff --git a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js
index 7fe1a8cc2df..4aa0768d394 100644
--- a/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js
+++ b/app/assets/javascripts/ide/stores/modules/terminal/actions/session_status.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import * as messages from '../messages';
import * as types from '../mutation_types';
@@ -42,7 +42,7 @@ export const receiveSessionStatusSuccess = ({ commit, dispatch }, data) => {
};
export const receiveSessionStatusError = ({ dispatch }) => {
- createFlash({ message: messages.UNEXPECTED_ERROR_STATUS });
+ createAlert({ message: messages.UNEXPECTED_ERROR_STATUS });
dispatch('killSession');
};
diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
index 98ee858ca91..1be7d40190f 100644
--- a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
+++ b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
@@ -12,7 +12,7 @@ import {
GlFormCheckbox,
} from '@gitlab/ui';
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { s__, __, n__, sprintf } from '~/locale';
import PaginationBar from '~/vue_shared/components/pagination_bar/pagination_bar.vue';
import HelpPopover from '~/vue_shared/components/help_popover.vue';
@@ -342,7 +342,7 @@ export default {
variables: { importRequests },
});
} catch (error) {
- createFlash({
+ createAlert({
message: i18n.ERROR_IMPORT,
captureError: true,
error,
diff --git a/app/assets/javascripts/import_entities/import_groups/services/status_poller.js b/app/assets/javascripts/import_entities/import_groups/services/status_poller.js
index ba0f2bb947a..6ad5e448a40 100644
--- a/app/assets/javascripts/import_entities/import_groups/services/status_poller.js
+++ b/app/assets/javascripts/import_entities/import_groups/services/status_poller.js
@@ -1,5 +1,5 @@
import Visibility from 'visibilityjs';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import Poll from '~/lib/utils/poll';
import { s__ } from '~/locale';
@@ -15,7 +15,7 @@ export class StatusPoller {
statuses.forEach((status) => updateImportStatus(status));
},
errorCallback: () =>
- createFlash({
+ createAlert({
message: s__('BulkImport|Update of import statuses with realtime changes failed'),
}),
});
diff --git a/app/assets/javascripts/import_entities/import_projects/store/actions.js b/app/assets/javascripts/import_entities/import_projects/store/actions.js
index 92be028b8a9..cbdce96ab40 100644
--- a/app/assets/javascripts/import_entities/import_projects/store/actions.js
+++ b/app/assets/javascripts/import_entities/import_projects/store/actions.js
@@ -1,5 +1,5 @@
import Visibility from 'visibilityjs';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import httpStatusCodes from '~/lib/utils/http_status';
@@ -73,7 +73,7 @@ const fetchReposFactory = ({ reposPath = isRequired() }) => ({ state, commit })
if (hasRedirectInError(e)) {
redirectToUrlInError(e);
} else if (tooManyRequests(e)) {
- createFlash({
+ createAlert({
message: sprintf(s__('ImportProjects|%{provider} rate limit exceeded. Try again later'), {
provider: capitalizeFirstCharacter(provider),
}),
@@ -81,7 +81,7 @@ const fetchReposFactory = ({ reposPath = isRequired() }) => ({ state, commit })
commit(types.RECEIVE_REPOS_ERROR);
} else {
- createFlash({
+ createAlert({
message: sprintf(s__('ImportProjects|Requesting your %{provider} repositories failed'), {
provider,
}),
@@ -124,7 +124,7 @@ const fetchImportFactory = (importPath = isRequired()) => ({ state, commit, gett
)
: s__('ImportProjects|Importing the project failed');
- createFlash({
+ createAlert({
message: flashMessage,
});
@@ -149,7 +149,7 @@ export const fetchJobsFactory = (jobsPath = isRequired()) => ({ state, commit, d
if (hasRedirectInError(e)) {
redirectToUrlInError(e);
} else {
- createFlash({
+ createAlert({
message: s__('ImportProjects|Update of imported projects with realtime changes failed'),
});
}
@@ -177,7 +177,7 @@ const fetchNamespacesFactory = (namespacesPath = isRequired()) => ({ commit }) =
commit(types.RECEIVE_NAMESPACES_SUCCESS, convertObjectPropsToCamelCase(data, { deep: true })),
)
.catch(() => {
- createFlash({
+ createAlert({
message: s__('ImportProjects|Requesting namespaces failed'),
});
diff --git a/app/assets/javascripts/milestones/components/promote_milestone_modal.vue b/app/assets/javascripts/milestones/components/promote_milestone_modal.vue
index cac6d722ced..9e537fa2c82 100644
--- a/app/assets/javascripts/milestones/components/promote_milestone_modal.vue
+++ b/app/assets/javascripts/milestones/components/promote_milestone_modal.vue
@@ -1,6 +1,6 @@
<script>
import { GlModal } from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale';
@@ -63,7 +63,7 @@ export default {
visitUrl(response.data.url);
})
.catch((error) => {
- createFlash({
+ createAlert({
message: error,
});
})
diff --git a/app/assets/javascripts/milestones/milestone.js b/app/assets/javascripts/milestones/milestone.js
index 8f2721c2a5b..d9e72340d62 100644
--- a/app/assets/javascripts/milestones/milestone.js
+++ b/app/assets/javascripts/milestones/milestone.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { sanitize } from '~/lib/dompurify';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -34,7 +34,7 @@ export default class Milestone {
this.loadedTabs.add(tab);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Error loading milestone tab'),
}),
);
diff --git a/app/assets/javascripts/mirrors/mirror_repos.js b/app/assets/javascripts/mirrors/mirror_repos.js
index 5bf08be1ead..2995f19c470 100644
--- a/app/assets/javascripts/mirrors/mirror_repos.js
+++ b/app/assets/javascripts/mirrors/mirror_repos.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import { hide } from '~/tooltips';
@@ -120,7 +120,7 @@ export default class MirrorRepos {
.put(this.mirrorEndpoint, payload)
.then(() => this.removeRow($target))
.catch(() =>
- createFlash({
+ createAlert({
message: __('Failed to remove mirror.'),
}),
);
diff --git a/app/assets/javascripts/mirrors/ssh_mirror.js b/app/assets/javascripts/mirrors/ssh_mirror.js
index eb7c43034a4..3b7e5a5f2ee 100644
--- a/app/assets/javascripts/mirrors/ssh_mirror.js
+++ b/app/assets/javascripts/mirrors/ssh_mirror.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import { escape } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { backOff } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
@@ -115,7 +115,7 @@ export default class SSHMirror {
const failureMessage = response.data
? response.data.message
: __('An error occurred while detecting host keys');
- createFlash({
+ createAlert({
message: failureMessage,
});
diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue
index e3fcdf716d4..b6ad2d21757 100644
--- a/app/assets/javascripts/monitoring/components/dashboard.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard.vue
@@ -11,7 +11,7 @@ import {
import Mousetrap from 'mousetrap';
import VueDraggable from 'vuedraggable';
import { mapActions, mapState, mapGetters } from 'vuex';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import invalidUrl from '~/lib/utils/invalid_url';
import { ESC_KEY } from '~/lib/utils/keys';
import { mergeUrlParams, updateHistory } from '~/lib/utils/url_utility';
@@ -176,7 +176,7 @@ export default {
this.setExpandedPanel(expandedPanel);
}
} catch {
- createFlash({
+ createAlert({
message: s__(
'Metrics|Link contains invalid chart information, please verify the link to see the expanded panel.',
),
@@ -201,7 +201,7 @@ export default {
* This watcher is set for future SPA behaviour of the dashboard
*/
if (hasWarnings) {
- createFlash({
+ createAlert({
message: s__(
'Metrics|Your dashboard schema is invalid. Edit the dashboard to correct the YAML schema.',
),
@@ -319,7 +319,7 @@ export default {
this.isRearrangingPanels = isRearrangingPanels;
},
onDateTimePickerInvalid() {
- createFlash({
+ createAlert({
message: s__(
'Metrics|Link contains an invalid time window, please verify the link to see the requested time range.',
),
diff --git a/app/assets/javascripts/monitoring/stores/actions.js b/app/assets/javascripts/monitoring/stores/actions.js
index 5c99dbc0d98..0ef365c6368 100644
--- a/app/assets/javascripts/monitoring/stores/actions.js
+++ b/app/assets/javascripts/monitoring/stores/actions.js
@@ -1,5 +1,5 @@
import * as Sentry from '@sentry/browser';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { convertToFixedRange } from '~/lib/utils/datetime_range';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
@@ -134,7 +134,7 @@ export const fetchDashboard = ({ state, commit, dispatch, getters }) => {
if (state.showErrorBanner) {
if (error.response.data && error.response.data.message) {
const { message } = error.response.data;
- createFlash({
+ createAlert({
message: sprintf(
s__('Metrics|There was an error while retrieving metrics. %{message}'),
{ message },
@@ -142,7 +142,7 @@ export const fetchDashboard = ({ state, commit, dispatch, getters }) => {
),
});
} else {
- createFlash({
+ createAlert({
message: s__('Metrics|There was an error while retrieving metrics'),
});
}
@@ -176,7 +176,7 @@ export const fetchDashboardData = ({ state, dispatch, getters }) => {
dispatch('fetchDeploymentsData');
if (!state.timeRange) {
- createFlash({
+ createAlert({
message: s__(`Metrics|Invalid time range, please verify.`),
type: 'warning',
});
@@ -207,7 +207,7 @@ export const fetchDashboardData = ({ state, dispatch, getters }) => {
});
})
.catch(() => {
- createFlash({
+ createAlert({
message: s__(`Metrics|There was an error while retrieving metrics`),
type: 'warning',
});
@@ -246,7 +246,7 @@ export const fetchPrometheusMetric = (
Sentry.captureException(error);
commit(types.RECEIVE_METRIC_RESULT_FAILURE, { metricId: metric.metricId, error });
- // Continue to throw error so the dashboard can notify using createFlash
+ // Continue to throw error so the dashboard can notify using createAlert
throw error;
});
};
@@ -262,7 +262,7 @@ export const fetchDeploymentsData = ({ state, dispatch }) => {
.then((resp) => resp.data)
.then((response) => {
if (!response || !response.deployments) {
- createFlash({
+ createAlert({
message: s__('Metrics|Unexpected deployment data response from prometheus endpoint'),
});
}
@@ -272,7 +272,7 @@ export const fetchDeploymentsData = ({ state, dispatch }) => {
.catch((error) => {
Sentry.captureException(error);
dispatch('receiveDeploymentsDataFailure');
- createFlash({
+ createAlert({
message: s__('Metrics|There was an error getting deployment information.'),
});
});
@@ -302,7 +302,7 @@ export const fetchEnvironmentsData = ({ state, dispatch }) => {
)
.then((environments) => {
if (!environments) {
- createFlash({
+ createAlert({
message: s__(
'Metrics|There was an error fetching the environments data, please try again',
),
@@ -314,7 +314,7 @@ export const fetchEnvironmentsData = ({ state, dispatch }) => {
.catch((err) => {
Sentry.captureException(err);
dispatch('receiveEnvironmentsDataFailure');
- createFlash({
+ createAlert({
message: s__('Metrics|There was an error getting environments information.'),
});
});
@@ -348,7 +348,7 @@ export const fetchAnnotations = ({ state, dispatch, getters }) => {
.then(parseAnnotationsResponse)
.then((annotations) => {
if (!annotations) {
- createFlash({
+ createAlert({
message: s__('Metrics|There was an error fetching annotations. Please try again.'),
});
}
@@ -358,7 +358,7 @@ export const fetchAnnotations = ({ state, dispatch, getters }) => {
.catch((err) => {
Sentry.captureException(err);
dispatch('receiveAnnotationsFailure');
- createFlash({
+ createAlert({
message: s__('Metrics|There was an error getting annotations information.'),
});
});
@@ -397,7 +397,7 @@ export const fetchDashboardValidationWarnings = ({ state, dispatch, getters }) =
.catch((err) => {
Sentry.captureException(err);
dispatch('receiveDashboardValidationWarningsFailure');
- createFlash({
+ createAlert({
message: s__(
'Metrics|There was an error getting dashboard validation warnings information.',
),
@@ -502,7 +502,7 @@ export const fetchVariableMetricLabelValues = ({ state, commit }, { defaultQuery
commit(types.UPDATE_VARIABLE_METRIC_LABEL_VALUES, { variable, label, data });
})
.catch(() => {
- createFlash({
+ createAlert({
message: sprintf(
s__('Metrics|There was an error getting options for variable "%{name}".'),
{
@@ -569,7 +569,7 @@ export const fetchPanelPreviewMetrics = ({ state, commit }) => {
Sentry.captureException(error);
commit(types.RECEIVE_PANEL_PREVIEW_METRIC_RESULT_FAILURE, { index, error });
- // Continue to throw error so the panel builder can notify using createFlash
+ // Continue to throw error so the panel builder can notify using createAlert
throw error;
});
});
diff --git a/app/assets/javascripts/namespaces/leave_by_url.js b/app/assets/javascripts/namespaces/leave_by_url.js
index e00c2abfbef..09757ce17fa 100644
--- a/app/assets/javascripts/namespaces/leave_by_url.js
+++ b/app/assets/javascripts/namespaces/leave_by_url.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { initRails } from '~/lib/utils/rails_ujs';
import { getParameterByName } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
@@ -18,7 +18,7 @@ export default function leaveByUrl(namespaceType) {
if (leaveLink) {
leaveLink.click();
} else {
- createFlash({
+ createAlert({
message: sprintf(__('You do not have permission to leave this %{namespaceType}.'), {
namespaceType,
}),
diff --git a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
index 2b3055ecd66..00e0649deed 100644
--- a/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
+++ b/app/assets/javascripts/pages/projects/forks/new/components/project_namespace.vue
@@ -9,7 +9,7 @@ import {
GlSearchBoxByType,
GlTruncate,
} from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants';
import { s__ } from '~/locale';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
@@ -41,7 +41,7 @@ export default {
return length > 0 && length < MINIMUM_SEARCH_LENGTH;
},
error(error) {
- createFlash({
+ createAlert({
message: s__(
'ForkProject|Something went wrong while loading data. Please refresh the page to try again.',
),
diff --git a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
index 9a38c2cc765..65942464e2b 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
@@ -2,7 +2,7 @@
import $ from 'jquery';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { __ } from '~/locale';
@@ -39,7 +39,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = (
}
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Error fetching refs'),
}),
);
diff --git a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
index 5179d1b31ab..406959c80ea 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/edit/index.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -33,7 +33,7 @@ function initTargetBranchSelector() {
callback(data);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Error fetching branches'),
}),
);
diff --git a/app/assets/javascripts/pages/projects/project.js b/app/assets/javascripts/pages/projects/project.js
index ccabaad5b2e..d177c67f133 100644
--- a/app/assets/javascripts/pages/projects/project.js
+++ b/app/assets/javascripts/pages/projects/project.js
@@ -4,7 +4,7 @@ import $ from 'jquery';
import { setCookie } from '~/lib/utils/common_utils';
import initClonePanel from '~/clone_panel';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { serializeForm } from '~/lib/utils/forms';
import { mergeUrlParams } from '~/lib/utils/url_utility';
@@ -80,7 +80,7 @@ export default class Project {
})
.then(({ data }) => callback(data))
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while getting projects'),
}),
);
diff --git a/app/assets/javascripts/pages/sessions/new/username_validator.js b/app/assets/javascripts/pages/sessions/new/username_validator.js
index 7ea744a68a6..1848aa70cf0 100644
--- a/app/assets/javascripts/pages/sessions/new/username_validator.js
+++ b/app/assets/javascripts/pages/sessions/new/username_validator.js
@@ -1,6 +1,6 @@
import { debounce } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import InputValidator from '~/validators/input_validator';
@@ -51,7 +51,7 @@ export default class UsernameValidator extends InputValidator {
);
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while validating username'),
}),
);
diff --git a/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue b/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
index 10b95fd6f3c..b72579276e8 100644
--- a/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
+++ b/app/assets/javascripts/pages/shared/wikis/components/wiki_content.vue
@@ -1,6 +1,6 @@
<script>
import { GlSkeletonLoader, GlSafeHtmlDirective, GlAlert } from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __ } from '~/locale';
import axios from '~/lib/utils/axios_utils';
import { handleLocationHash } from '~/lib/utils/common_utils';
@@ -47,7 +47,7 @@ export default {
handleLocationHash();
})
.catch(() =>
- createFlash({
+ createAlert({
message: this.$options.i18n.renderingContentFailed,
}),
);
diff --git a/app/assets/javascripts/pages/users/activity_calendar.js b/app/assets/javascripts/pages/users/activity_calendar.js
index 9e0af426f6e..e8ffa81654c 100644
--- a/app/assets/javascripts/pages/users/activity_calendar.js
+++ b/app/assets/javascripts/pages/users/activity_calendar.js
@@ -1,7 +1,7 @@
import { select } from 'd3-selection';
import $ from 'jquery';
import { last } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import dateFormat from '~/lib/dateformat';
import axios from '~/lib/utils/axios_utils';
import { getDayName, getDayDifference } from '~/lib/utils/datetime_utility';
@@ -302,7 +302,7 @@ export default class ActivityCalendar {
});
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('An error occurred while retrieving calendar activity'),
}),
);
diff --git a/app/assets/javascripts/persistent_user_callout.js b/app/assets/javascripts/persistent_user_callout.js
index 7e331bdd91d..6ee33902a01 100644
--- a/app/assets/javascripts/persistent_user_callout.js
+++ b/app/assets/javascripts/persistent_user_callout.js
@@ -1,4 +1,4 @@
-import createFlash from './flash';
+import { createAlert } from '~/flash';
import axios from './lib/utils/axios_utils';
import { parseBoolean } from './lib/utils/common_utils';
import { __ } from './locale';
@@ -73,7 +73,7 @@ export default class PersistentUserCallout {
}
})
.catch(() => {
- createFlash({
+ createAlert({
message: __(
'An error occurred while dismissing the alert. Refresh the page and try again.',
),
@@ -94,7 +94,7 @@ export default class PersistentUserCallout {
window.location.assign(href);
})
.catch(() => {
- createFlash({
+ createAlert({
message: __(
'An error occurred while acknowledging the notification. Refresh the page and try again.',
),
diff --git a/app/assets/javascripts/projects/settings/access_dropdown.js b/app/assets/javascripts/projects/settings/access_dropdown.js
index 060178a3cfb..335545c802a 100644
--- a/app/assets/javascripts/projects/settings/access_dropdown.js
+++ b/app/assets/javascripts/projects/settings/access_dropdown.js
@@ -1,7 +1,7 @@
/* eslint-disable no-underscore-dangle, class-methods-use-this */
import { escape, find, countBy } from 'lodash';
import initDeprecatedJQueryDropdown from '~/deprecated_jquery_dropdown';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { n__, s__, __, sprintf } from '~/locale';
import { getUsers, getGroups, getDeployKeys } from './api/access_dropdown_api';
import { LEVEL_TYPES, LEVEL_ID_PROP, ACCESS_LEVELS, ACCESS_LEVEL_NONE } from './constants';
@@ -326,12 +326,12 @@ export default class AccessDropdown {
);
})
.catch(() => {
- createFlash({ message: __('Failed to load groups, users and deploy keys.') });
+ createAlert({ message: __('Failed to load groups, users and deploy keys.') });
});
} else {
getDeployKeys(query)
.then((deployKeysResponse) => callback(this.consolidateData(deployKeysResponse.data)))
- .catch(() => createFlash({ message: __('Failed to load deploy keys.') }));
+ .catch(() => createAlert({ message: __('Failed to load deploy keys.') }));
}
}
diff --git a/app/assets/javascripts/projects/settings/components/access_dropdown.vue b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
index 2209172c06d..cc47496971d 100644
--- a/app/assets/javascripts/projects/settings/components/access_dropdown.vue
+++ b/app/assets/javascripts/projects/settings/components/access_dropdown.vue
@@ -9,7 +9,7 @@ import {
GlSprintf,
} from '@gitlab/ui';
import { debounce, intersectionWith, groupBy, differenceBy, intersectionBy } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { __, s__, n__ } from '~/locale';
import { getUsers, getGroups, getDeployKeys } from '../api/access_dropdown_api';
import { LEVEL_TYPES, ACCESS_LEVELS } from '../constants';
@@ -163,7 +163,7 @@ export default {
this.setSelected({ initial });
})
.catch(() =>
- createFlash({ message: __('Failed to load groups, users and deploy keys.') }),
+ createAlert({ message: __('Failed to load groups, users and deploy keys.') }),
)
.finally(() => {
this.initialLoading = false;
@@ -175,7 +175,7 @@ export default {
this.consolidateData(deployKeysResponse.data);
this.setSelected({ initial });
})
- .catch(() => createFlash({ message: __('Failed to load deploy keys.') }))
+ .catch(() => createAlert({ message: __('Failed to load deploy keys.') }))
.finally(() => {
this.initialLoading = false;
this.loading = false;
diff --git a/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue b/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
index e8eaf0a70b2..65e0c87e3f3 100644
--- a/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
+++ b/app/assets/javascripts/projects/settings/repository/branch_rules/app.vue
@@ -1,6 +1,6 @@
<script>
import { s__ } from '~/locale';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import branchRulesQuery from './graphql/queries/branch_rules.query.graphql';
import BranchRule from './components/branch_rule.vue';
@@ -31,7 +31,7 @@ export default {
return data.project?.branchRules?.nodes || [];
},
error() {
- createFlash({ message: this.$options.i18n.queryError });
+ createAlert({ message: this.$options.i18n.queryError });
},
},
},
diff --git a/app/assets/javascripts/projects/star.js b/app/assets/javascripts/projects/star.js
index 62d6590a3a3..55c3d68cd11 100644
--- a/app/assets/javascripts/projects/star.js
+++ b/app/assets/javascripts/projects/star.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { spriteIcon } from '~/lib/utils/common_utils';
import { __, s__ } from '~/locale';
@@ -34,7 +34,7 @@ export default class Star {
}
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Star toggle failed. Try again later.'),
}),
);
diff --git a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
index 6b14ebadacc..9f9b6424125 100644
--- a/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
+++ b/app/assets/javascripts/projects/tree/components/commit_pipeline_status_component.vue
@@ -1,7 +1,7 @@
<script>
import { GlLoadingIcon, GlTooltipDirective } from '@gitlab/ui';
import Visibility from 'visibilityjs';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import Poll from '~/lib/utils/poll';
import { __, s__, sprintf } from '~/locale';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
@@ -57,7 +57,7 @@ export default {
group: 'notfound',
};
this.isLoading = false;
- createFlash({
+ createAlert({
message: __('Something went wrong on our end'),
});
},
diff --git a/app/assets/javascripts/protected_branches/protected_branch_create.js b/app/assets/javascripts/protected_branches/protected_branch_create.js
index 16eb5c3de32..f232cb2709a 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_create.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_create.js
@@ -1,6 +1,6 @@
import $ from 'jquery';
import CreateItemDropdown from '~/create_item_dropdown';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import AccessorUtilities from '~/lib/utils/accessor';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
@@ -130,7 +130,7 @@ export default class ProtectedBranchCreate {
window.location.reload();
})
.catch(() =>
- createFlash({
+ createAlert({
message: __('Failed to protect the branch'),
}),
);
diff --git a/app/assets/javascripts/protected_branches/protected_branch_edit.js b/app/assets/javascripts/protected_branches/protected_branch_edit.js
index 15e706e38c6..1693d869b54 100644
--- a/app/assets/javascripts/protected_branches/protected_branch_edit.js
+++ b/app/assets/javascripts/protected_branches/protected_branch_edit.js
@@ -1,5 +1,5 @@
import { find } from 'lodash';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale';
import AccessDropdown from '~/projects/settings/access_dropdown';
@@ -74,7 +74,7 @@ export default class ProtectedBranchEdit {
})
.then(callback)
.catch(() => {
- createFlash({ message: __('Failed to update branch!') });
+ createAlert({ message: __('Failed to update branch!') });
});
}
@@ -141,7 +141,7 @@ export default class ProtectedBranchEdit {
.catch(() => {
this.$allowedToMergeDropdown.enable();
this.$allowedToPushDropdown.enable();
- createFlash({ message: __('Failed to update branch!') });
+ createAlert({ message: __('Failed to update branch!') });
});
}
diff --git a/app/assets/javascripts/protected_tags/protected_tag_edit.js b/app/assets/javascripts/protected_tags/protected_tag_edit.js
index 1fe9a753e1e..40c52eba99e 100644
--- a/app/assets/javascripts/protected_tags/protected_tag_edit.js
+++ b/app/assets/javascripts/protected_tags/protected_tag_edit.js
@@ -1,4 +1,4 @@
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '../lib/utils/axios_utils';
import { FAILED_TO_UPDATE_TAG_MESSAGE } from './constants';
import ProtectedTagAccessDropdown from './protected_tag_access_dropdown';
@@ -49,7 +49,7 @@ export default class ProtectedTagEdit {
this.$allowedToCreateDropdownButton.enable();
window.scrollTo({ top: 0, behavior: 'smooth' });
- createFlash({
+ createAlert({
message: FAILED_TO_UPDATE_TAG_MESSAGE,
});
});
diff --git a/app/assets/javascripts/related_issues/components/related_issues_root.vue b/app/assets/javascripts/related_issues/components/related_issues_root.vue
index ae40232df6f..38e1d6e9d4f 100644
--- a/app/assets/javascripts/related_issues/components/related_issues_root.vue
+++ b/app/assets/javascripts/related_issues/components/related_issues_root.vue
@@ -23,7 +23,7 @@ Your caret can stop touching a `rawReference` can happen in a variety of ways:
and hide the `AddIssuableForm` area.
*/
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { getIdFromGraphQLId, isGid } from '~/graphql_shared/utils';
import { __ } from '~/locale';
import {
@@ -141,11 +141,11 @@ export default {
})
.catch((res) => {
if (res && res.status !== 404) {
- createFlash({ message: relatedIssuesRemoveErrorMap[this.issuableType] });
+ createAlert({ message: relatedIssuesRemoveErrorMap[this.issuableType] });
}
});
} else {
- createFlash({ message: pathIndeterminateErrorMap[this.issuableType] });
+ createAlert({ message: pathIndeterminateErrorMap[this.issuableType] });
}
},
onToggleAddRelatedIssuesForm() {
@@ -174,7 +174,7 @@ export default {
if (response && response.data && response.data.message) {
errorMessage = response.data.message;
}
- createFlash({ message: errorMessage });
+ createAlert({ message: errorMessage });
})
.finally(() => {
this.isSubmitting = false;
@@ -195,7 +195,7 @@ export default {
})
.catch(() => {
this.store.setRelatedIssues([]);
- createFlash({ message: __('An error occurred while fetching issues.') });
+ createAlert({ message: __('An error occurred while fetching issues.') });
})
.finally(() => {
this.isFetching = false;
@@ -216,7 +216,7 @@ export default {
}
})
.catch(() => {
- createFlash({ message: __('An error occurred while reordering issues.') });
+ createAlert({ message: __('An error occurred while reordering issues.') });
});
}
},
diff --git a/app/assets/javascripts/releases/components/app_index.vue b/app/assets/javascripts/releases/components/app_index.vue
index d63a83d1a08..6dc8240e680 100644
--- a/app/assets/javascripts/releases/components/app_index.vue
+++ b/app/assets/javascripts/releases/components/app_index.vue
@@ -1,6 +1,6 @@
<script>
import { GlButton } from '@gitlab/ui';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { historyPushState } from '~/lib/utils/common_utils';
import { scrollUp } from '~/lib/utils/scroll_utils';
import { setUrlParams, getParameterByName } from '~/lib/utils/url_utility';
@@ -71,7 +71,7 @@ export default {
error(error) {
this.fullRequestError = true;
- createFlash({
+ createAlert({
message: this.$options.i18n.errorMessage,
captureError: true,
error,
diff --git a/app/assets/javascripts/releases/components/app_show.vue b/app/assets/javascripts/releases/components/app_show.vue
index fdb0f99b735..7147cfa01c8 100644
--- a/app/assets/javascripts/releases/components/app_show.vue
+++ b/app/assets/javascripts/releases/components/app_show.vue
@@ -1,5 +1,5 @@
<script>
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { s__ } from '~/locale';
import oneReleaseQuery from '../graphql/queries/one_release.query.graphql';
import { convertGraphQLRelease } from '../util';
@@ -51,7 +51,7 @@ export default {
},
methods: {
showFlash(error) {
- createFlash({
+ createAlert({
message: s__('Release|Something went wrong while getting the release details.'),
captureError: true,
error,
diff --git a/app/assets/javascripts/releases/stores/modules/edit_new/actions.js b/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
index 0b82a59be6b..42ceed81c00 100644
--- a/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
+++ b/app/assets/javascripts/releases/stores/modules/edit_new/actions.js
@@ -1,5 +1,5 @@
import { getTag } from '~/rest_api';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import createReleaseMutation from '~/releases/graphql/mutations/create_release.mutation.graphql';
@@ -48,7 +48,7 @@ export const fetchRelease = async ({ commit, state }) => {
commit(types.RECEIVE_RELEASE_SUCCESS, release);
} catch (error) {
commit(types.RECEIVE_RELEASE_ERROR, error);
- createFlash({
+ createAlert({
message: s__('Release|Something went wrong while getting the release details.'),
});
}
@@ -136,11 +136,11 @@ export const createRelease = async ({ commit, dispatch, getters }) => {
} catch (error) {
commit(types.RECEIVE_SAVE_RELEASE_ERROR, error);
if (error instanceof GraphQLError) {
- createFlash({
+ createAlert({
message: error.message,
});
} else {
- createFlash({
+ createAlert({
message: s__('Release|Something went wrong while creating a new release.'),
});
}
@@ -222,7 +222,7 @@ export const updateRelease = async ({ commit, dispatch, state, getters }) => {
dispatch('receiveSaveReleaseSuccess', state.release._links.self);
} catch (error) {
commit(types.RECEIVE_SAVE_RELEASE_ERROR, error);
- createFlash({
+ createAlert({
message: s__('Release|Something went wrong while saving the release details.'),
});
}
@@ -236,7 +236,7 @@ export const fetchTagNotes = ({ commit, state }, tagName) => {
commit(types.RECEIVE_TAG_NOTES_SUCCESS, data);
})
.catch((error) => {
- createFlash({
+ createAlert({
message: s__('Release|Unable to fetch the tag notes.'),
});
@@ -269,7 +269,7 @@ export const deleteRelease = ({ commit, getters, dispatch, state }) => {
})
.catch((error) => {
commit(types.RECEIVE_SAVE_RELEASE_ERROR, error);
- createFlash({
+ createAlert({
message: s__('Release|Something went wrong while deleting the release.'),
});
});
diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue
index f344155395b..4d6a27f61ac 100644
--- a/app/assets/javascripts/work_items/components/work_item_assignees.vue
+++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue
@@ -142,9 +142,6 @@ export default {
property: `type_${this.workItemType}`,
};
},
- assigneeListEmpty() {
- return this.assignees.length === 0;
- },
containerClass() {
return !this.isEditing ? 'gl-shadow-none!' : '';
},
diff --git a/app/assets/javascripts/work_items/components/work_item_labels.vue b/app/assets/javascripts/work_items/components/work_item_labels.vue
index 0beb1a0df69..a06c90468de 100644
--- a/app/assets/javascripts/work_items/components/work_item_labels.vue
+++ b/app/assets/javascripts/work_items/components/work_item_labels.vue
@@ -102,9 +102,6 @@ export default {
allowScopedLabels() {
return this.labelsWidget.allowScopedLabels;
},
- listEmpty() {
- return this.labels.length === 0;
- },
containerClass() {
return !this.isEditing ? 'gl-shadow-none!' : '';
},
diff --git a/app/assets/javascripts/work_items/pages/create_work_item.vue b/app/assets/javascripts/work_items/pages/create_work_item.vue
index 3b7257591e2..4908b99e5b0 100644
--- a/app/assets/javascripts/work_items/pages/create_work_item.vue
+++ b/app/assets/javascripts/work_items/pages/create_work_item.vue
@@ -6,7 +6,6 @@ import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { sprintfWorkItem, I18N_WORK_ITEM_ERROR_CREATING } from '../constants';
import workItemQuery from '../graphql/work_item.query.graphql';
import createWorkItemMutation from '../graphql/create_work_item.mutation.graphql';
-import createWorkItemFromTaskMutation from '../graphql/create_work_item_from_task.mutation.graphql';
import projectWorkItemTypesQuery from '../graphql/project_work_item_types.query.graphql';
import ItemTitle from '../components/item_title.vue';
@@ -29,26 +28,6 @@ export default {
required: false,
default: '',
},
- issueGid: {
- type: String,
- required: false,
- default: '',
- },
- lockVersion: {
- type: Number,
- required: false,
- default: null,
- },
- lineNumberStart: {
- type: String,
- required: false,
- default: null,
- },
- lineNumberEnd: {
- type: String,
- required: false,
- default: null,
- },
},
data() {
return {
@@ -136,28 +115,6 @@ export default {
this.error = this.createErrorText;
}
},
- async createWorkItemFromTask() {
- try {
- const { data } = await this.$apollo.mutate({
- mutation: createWorkItemFromTaskMutation,
- variables: {
- input: {
- id: this.issueGid,
- workItemData: {
- lockVersion: this.lockVersion,
- title: this.title,
- lineNumberStart: Number(this.lineNumberStart),
- lineNumberEnd: Number(this.lineNumberEnd),
- workItemTypeId: this.selectedWorkItemType,
- },
- },
- },
- });
- this.$emit('onCreate', data.workItemCreateFromTask.workItem.descriptionHtml);
- } catch {
- this.error = this.createErrorText;
- }
- },
handleTitleInput(title) {
this.title = title;
},
diff --git a/app/models/bulk_imports/entity.rb b/app/models/bulk_imports/entity.rb
index 21f424817b4..a3d70124625 100644
--- a/app/models/bulk_imports/entity.rb
+++ b/app/models/bulk_imports/entity.rb
@@ -116,8 +116,20 @@ class BulkImports::Entity < ApplicationRecord
"/#{pluralized_name}/#{encoded_source_full_path}"
end
+ def base_xid_resource_url_path
+ "/#{pluralized_name}/#{source_xid}"
+ end
+
+ def base_resource_path
+ if source_xid.present?
+ base_xid_resource_url_path
+ else
+ base_resource_url_path
+ end
+ end
+
def export_relations_url_path
- "#{base_resource_url_path}/export_relations"
+ "#{base_resource_path}/export_relations"
end
def relation_download_url_path(relation)
@@ -125,7 +137,7 @@ class BulkImports::Entity < ApplicationRecord
end
def wikis_url_path
- "#{base_resource_url_path}/wikis"
+ "#{base_resource_path}/wikis"
end
def project?
diff --git a/app/views/admin/application_settings/_network_rate_limits.html.haml b/app/views/admin/application_settings/_network_rate_limits.html.haml
index f1857a9749a..300180f7b9a 100644
--- a/app/views/admin/application_settings/_network_rate_limits.html.haml
+++ b/app/views/admin/application_settings/_network_rate_limits.html.haml
@@ -30,4 +30,4 @@
= f.label :"throttle_authenticated_#{setting_fragment}_period_in_seconds", _('Authenticated API rate limit period in seconds'), class: 'label-bold'
= f.number_field :"throttle_authenticated_#{setting_fragment}_period_in_seconds", class: 'form-control gl-form-input'
- = f.submit _('Save changes'), class: "gl-button btn btn-confirm", data: { qa_selector: 'save_changes_button' }
+ = f.submit _('Save changes'), pajamas_button: true, data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_outbound.html.haml b/app/views/admin/application_settings/_outbound.html.haml
index bacfe056683..3505a3bf3ee 100644
--- a/app/views/admin/application_settings/_outbound.html.haml
+++ b/app/views/admin/application_settings/_outbound.html.haml
@@ -22,4 +22,4 @@
s_('OutboundRequests|Enforce DNS rebinding attack protection'),
help_text: _('OutboundRequests|Resolve IP addresses once and uses them to submit requests.')
- = f.submit _('Save changes'), class: "gl-button btn btn-confirm", data: { qa_selector: 'save_changes_button' }
+ = f.submit _('Save changes'), pajamas_button: true, data: { qa_selector: 'save_changes_button' }
diff --git a/app/views/admin/application_settings/_prometheus.html.haml b/app/views/admin/application_settings/_prometheus.html.haml
index 982531e9a2f..3db1272c77b 100644
--- a/app/views/admin/application_settings/_prometheus.html.haml
+++ b/app/views/admin/application_settings/_prometheus.html.haml
@@ -18,4 +18,4 @@
.form-text.text-muted
Only track method calls that take longer to complete than the given duration.
- = f.submit _('Save changes'), class: "gl-button btn btn-confirm"
+ = f.submit _('Save changes'), pajamas_button: true
diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 53eb6f4c63b..5b7f9c4226c 100644
--- a/app/views/shared/issuable/_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -62,9 +62,9 @@
= sanitize(html_escape(_('Please review the %{linkStart}contribution guidelines%{linkEnd} for this project.')) % { linkStart: contribution_guidelines_start, linkEnd: contribution_guidelines_end })
- if issuable.new_record?
- = form.submit "#{_('Create')} #{issuable.class.model_name.human.downcase}", class: 'gl-button btn btn-confirm gl-mr-2', data: { qa_selector: 'issuable_create_button', track_experiment: 'promote_mr_approvals_in_free', track_action: 'click_button', track_label: 'submit_mr', track_value: 0 }
+ = form.submit "#{_('Create')} #{issuable.class.model_name.human.downcase}", class: 'gl-button btn btn-confirm gl-mr-2', data: { qa_selector: 'issuable_create_button', track_action: 'click_button', track_label: 'submit_mr', track_value: 0 }
- else
- = form.submit _('Save changes'), class: 'gl-button btn btn-confirm gl-mr-2', data: { track_experiment: 'promote_mr_approvals_in_free', track_action: 'click_button', track_label: 'submit_mr', track_value: 0 }
+ = form.submit _('Save changes'), class: 'gl-button btn btn-confirm gl-mr-2', data: { track_action: 'click_button', track_label: 'submit_mr', track_value: 0 }
- if issuable.new_record?
= link_to _('Cancel'), polymorphic_path([@project, issuable.class]), class: 'btn gl-button btn-default js-reset-autosave'
diff --git a/app/views/shared/web_hooks/_index.html.haml b/app/views/shared/web_hooks/_index.html.haml
index 5ec82ad6702..27c2fd5bf8b 100644
--- a/app/views/shared/web_hooks/_index.html.haml
+++ b/app/views/shared/web_hooks/_index.html.haml
@@ -1,14 +1,13 @@
%hr
-.card#webhooks-index
- .card-header
- %h5
- = hook_class.underscore.humanize.titleize.pluralize
- (#{hooks.size})
-
- - if hooks.any?
- %ul.content-list
- - hooks.each do |hook|
- = render 'shared/web_hooks/hook', hook: hook
- - else
- %p.text-center.gl-mt-3.gl-mb-3
- = _('No webhooks enabled. Select trigger events above.')
+= render Pajamas::CardComponent.new(card_options: { id: 'webhooks-index' }) do |c|
+ - c.header do
+ = hook_class.underscore.humanize.titleize.pluralize
+ (#{hooks.size})
+ - c.body do
+ - if hooks.any?
+ %ul.content-list
+ - hooks.each do |hook|
+ = render 'shared/web_hooks/hook', hook: hook
+ - else
+ %p.text-center.gl-mt-3.gl-mb-3
+ = _('No webhooks enabled. Select trigger events above.')
diff --git a/app/workers/bulk_import_worker.rb b/app/workers/bulk_import_worker.rb
index c7efc92b25e..d5eca86744e 100644
--- a/app/workers/bulk_import_worker.rb
+++ b/app/workers/bulk_import_worker.rb
@@ -22,10 +22,9 @@ class BulkImportWorker # rubocop:disable Scalability/IdempotentWorker
created_entities.find_each do |entity|
BulkImports::CreatePipelineTrackersService.new(entity).execute!
- BulkImports::ExportRequestWorker.perform_async(entity.id)
- BulkImports::EntityWorker.perform_async(entity.id)
-
entity.start!
+
+ BulkImports::ExportRequestWorker.perform_async(entity.id)
end
re_enqueue
diff --git a/app/workers/bulk_imports/export_request_worker.rb b/app/workers/bulk_imports/export_request_worker.rb
index 0d3e4f013dd..4f8f0996bef 100644
--- a/app/workers/bulk_imports/export_request_worker.rb
+++ b/app/workers/bulk_imports/export_request_worker.rb
@@ -13,7 +13,11 @@ module BulkImports
def perform(entity_id)
entity = BulkImports::Entity.find(entity_id)
+ entity.update!(source_xid: entity_source_xid(entity)) if entity.source_xid.nil?
+
request_export(entity)
+
+ BulkImports::EntityWorker.perform_async(entity_id)
rescue BulkImports::NetworkError => e
log_export_failure(e, entity)
@@ -23,35 +27,76 @@ module BulkImports
private
def request_export(entity)
- http_client(entity.bulk_import.configuration).post(entity.export_relations_url_path)
+ http_client(entity).post(entity.export_relations_url_path)
end
- def http_client(configuration)
+ def http_client(entity)
@client ||= Clients::HTTP.new(
- url: configuration.url,
- token: configuration.access_token
+ url: entity.bulk_import.configuration.url,
+ token: entity.bulk_import.configuration.access_token
)
end
def log_export_failure(exception, entity)
- attributes = {
+ Gitlab::Import::Logger.error(
+ structured_payload(
+ log_attributes(exception, entity).merge(
+ bulk_import_id: entity.bulk_import.id,
+ bulk_import_entity_type: entity.source_type
+ )
+ )
+ )
+
+ BulkImports::Failure.create(log_attributes(exception, entity))
+ end
+
+ def log_attributes(exception, entity)
+ {
bulk_import_entity_id: entity.id,
pipeline_class: 'ExportRequestWorker',
exception_class: exception.class.to_s,
exception_message: exception.message.truncate(255),
correlation_id_value: Labkit::Correlation::CorrelationId.current_or_new_id
}
+ end
+
+ def graphql_client(entity)
+ @graphql_client ||= BulkImports::Clients::Graphql.new(
+ url: entity.bulk_import.configuration.url,
+ token: entity.bulk_import.configuration.access_token
+ )
+ end
+
+ def entity_source_xid(entity)
+ query = entity_query(entity)
+ client = graphql_client(entity)
+
+ response = client.execute(
+ client.parse(query.to_s),
+ { full_path: entity.source_full_path }
+ ).original_hash
+ ::GlobalID.parse(response.dig(*query.data_path, 'id')).model_id
+ rescue StandardError => e
Gitlab::Import::Logger.error(
structured_payload(
- attributes.merge(
+ log_attributes(e, entity).merge(
+ message: 'Failed to fetch source entity id',
bulk_import_id: entity.bulk_import.id,
bulk_import_entity_type: entity.source_type
)
)
)
- BulkImports::Failure.create(attributes)
+ nil
+ end
+
+ def entity_query(entity)
+ if entity.group?
+ BulkImports::Groups::Graphql::GetGroupQuery.new(context: nil)
+ else
+ BulkImports::Projects::Graphql::GetProjectQuery.new(context: nil)
+ end
end
end
end
diff --git a/doc/administration/auth/atlassian.md b/doc/administration/auth/atlassian.md
index e3c52d8b4c4..b02ac06b67f 100644
--- a/doc/administration/auth/atlassian.md
+++ b/doc/administration/auth/atlassian.md
@@ -11,7 +11,7 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
## Atlassian application registration
-1. Go to <https://developer.atlassian.com/console/myapps/> and sign-in with the Atlassian
+1. Go to the [Atlassian developer console](https://developer.atlassian.com/console/myapps/) and sign-in with the Atlassian
account to administer the application.
1. Select **Create a new app**.
1. Choose an App Name, such as 'GitLab', and select **Create**.
@@ -51,8 +51,8 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
{
name: "atlassian_oauth2",
# label: "Provider name", # optional label for login button, defaults to "Atlassian"
- app_id: "YOUR_CLIENT_ID",
- app_secret: "YOUR_CLIENT_SECRET",
+ app_id: "<your_client_id>",
+ app_secret: "<your_client_secret>",
args: { scope: "offline_access read:jira-user read:jira-work", prompt: "consent" }
}
]
@@ -63,13 +63,13 @@ To enable the Atlassian OmniAuth provider for passwordless authentication you mu
```yaml
- { name: "atlassian_oauth2",
# label: "Provider name", # optional label for login button, defaults to "Atlassian"
- app_id: "YOUR_CLIENT_ID",
- app_secret: "YOUR_CLIENT_SECRET",
+ app_id: "<your_client_id>",
+ app_secret: "<your_client_secret>",
args: { scope: "offline_access read:jira-user read:jira-work", prompt: "consent" }
}
```
-1. Change `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET` to the Client credentials you received in [application registration](#atlassian-application-registration) steps.
+1. Change `<your_client_id>` and `<your_client_secret>` to the Client credentials you received during [application registration](#atlassian-application-registration).
1. Save the configuration file.
1. For the changes to take effect:
diff --git a/doc/administration/auth/authentiq.md b/doc/administration/auth/authentiq.md
index 1c4cc58b66f..1ac62b06fe7 100644
--- a/doc/administration/auth/authentiq.md
+++ b/doc/administration/auth/authentiq.md
@@ -7,7 +7,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Authentiq OmniAuth Provider **(FREE SELF)**
-To enable the Authentiq OmniAuth provider for passwordless authentication you must register an application with Authentiq.
+To enable the Authentiq OmniAuth provider for passwordless authentication, you must register an application with Authentiq.
Authentiq generates a Client ID and the accompanying Client Secret for you to use.
@@ -38,8 +38,8 @@ Authentiq generates a Client ID and the accompanying Client Secret for you to us
{
name: "authentiq",
# label: "Provider name", # optional label for login button, defaults to "Authentiq"
- app_id: "YOUR_CLIENT_ID",
- app_secret: "YOUR_CLIENT_SECRET",
+ app_id: "<your_client_id>",
+ app_secret: "<your_client_secret>",
args: {
"scope": 'aq:name email~rs address aq:push'
}
@@ -52,22 +52,28 @@ Authentiq generates a Client ID and the accompanying Client Secret for you to us
```yaml
- { name: 'authentiq',
# label: 'Provider name', # optional label for login button, defaults to "Authentiq"
- app_id: 'YOUR_CLIENT_ID',
- app_secret: 'YOUR_CLIENT_SECRET',
+ app_id: '<your_client_id>',
+ app_secret: '<your_client_secret>',
args: {
scope: 'aq:name email~rs address aq:push'
}
}
```
-1. The `scope` is set to request the user's name, email (required and signed), and permission to send push notifications to sign in on subsequent visits.
+1. The `scope` is set to request the:
+ - User's name.
+ - Required and signed email.
+ - Permission to send push notifications to sign in on subsequent visits.
+
See [OmniAuth Authentiq strategy](https://github.com/AuthentiqID/omniauth-authentiq/wiki/Scopes,-callback-url-configuration-and-responses) for more information on scopes and modifiers.
-1. Change `YOUR_CLIENT_ID` and `YOUR_CLIENT_SECRET` to the Client credentials you received in step 1.
+1. Change `<your_client_id>` and `<your_client_secret>` to the Client credentials you received from Authentiq.
1. Save the configuration file.
-1. [Reconfigure](../restart_gitlab.md#omnibus-gitlab-reconfigure) or [restart GitLab](../restart_gitlab.md#installations-from-source) for the changes to take effect if you installed GitLab via Omnibus or from source respectively.
+1. For the changes to take effect:
+ - [Reconfigure GitLab](../restart_gitlab.md#omnibus-gitlab-reconfigure) if you installed GitLab using Omnibus.
+ - [Restart GitLab](../restart_gitlab.md#installations-from-source) if you installed GitLab from source.
On the sign in page there should now be an Authentiq icon below the regular sign in form. Select the
icon to begin the authentication process. If the user:
@@ -77,7 +83,7 @@ icon to begin the authentication process. If the user:
1. Decide what personal details to share.
1. Sign in to your GitLab installation.
- Does not have the app installed, they are prompted to download the app and then follow the
- procedure above.
+ previous procedure.
If everything works, the user is returned to GitLab and is signed in.
diff --git a/doc/administration/sidekiq/index.md b/doc/administration/sidekiq/index.md
index 7a34d821ba4..f17c248e60e 100644
--- a/doc/administration/sidekiq/index.md
+++ b/doc/administration/sidekiq/index.md
@@ -377,6 +377,10 @@ To enable LDAP with the synchronization worker for Sidekiq:
sudo gitlab-ctl reconfigure
```
+## Configure SAML Groups for SAML Group Sync
+
+If you use [SAML Group Sync](../../user/group/saml_sso/group_sync.md), you must configure [SAML Groups](../../integration/saml.md#saml-groups) on all your Sidekiq nodes.
+
## Disable Rugged
Calls into Rugged, Ruby bindings for `libgit2`, [lock the Sidekiq processes's GVL](https://silverhammermba.github.io/emberb/c/#c-in-ruby-threads),
diff --git a/doc/architecture/blueprints/work_items/index.md b/doc/architecture/blueprints/work_items/index.md
new file mode 100644
index 00000000000..f86e8775e52
--- /dev/null
+++ b/doc/architecture/blueprints/work_items/index.md
@@ -0,0 +1,130 @@
+---
+stage: Plan
+group: Project Management
+comments: false
+description: 'Work Items'
+---
+
+# Work Items
+
+DISCLAIMER:
+This page may contain information related to upcoming products, features and functionality. It is important to note that the information presented is for informational purposes only, so please do not rely on the information for purchasing or planning purposes. Just like with all projects, the items mentioned on the page are subject to change or delay, and the development, release, and timing of any products, features, or functionality remain at the sole discretion of GitLab Inc.
+
+This document is a work-in-progress. Some aspects are not documented, though we expect to add them in the future.
+
+## Summary
+
+Work Items is a new architecture created to support the various types of built and planned entities throughout the product, such as issues, requirements, and incidents. It will make these types easy to extend and customize while sharing the same core functionality.
+
+## Terminology
+
+We use the following terms to describe components and properties of the Work items architecture.
+
+### Work Item
+
+Base type for issue, requirement, test case, incident and task (this list is planned to extend in the future). Different work items have the same set of base properties but their [widgets](#work-item-widgets) list is different.
+
+### Work Item types
+
+A set of predefined types for different categories of work items. Currently, the available types are:
+
+- Issue
+- Incident
+- Test case
+- Requirement
+- Task
+
+#### Work Item properties
+
+Every Work Item type has the following common properties:
+
+- `id` - a unique Work Item global identifier;
+- `iid` - internal ID of the Work Item, relative to the parent workspace (currently workspace can only be a project)
+- Work Item type;
+- properties related to Work Item modification time: `createdAt`, `updatedAt`, `closedAt`;
+- title string;
+- Work Item confidentiality state;
+- Work Item state (can be open or closed);
+- lock version, incremented each time the work item is updated;
+- permissions for the current user on the resource
+- a list of [Work Item widgets](#work-item-widgets)
+
+### Work Item widgets
+
+All Work Item types share the same pool of predefined widgets and are customized by which widgets are active on a specific type. The list of widgets for any certain Work Item type is currently predefined and is not customizable. However, in the future we plan to allow users to create new Work Item types and define a set of widgets for them.
+
+### Work Item widget types (updating)
+
+- assignees
+- description
+- hierarchy
+- iteration
+- labels
+- start and due date
+- verification status
+- weight
+
+### Work Item view
+
+The new frontend view that renders Work Items of any type using global Work Item `id` as an identifier.
+
+### Task
+
+Task is a special Work Item type. Tasks can be added to issues as child items and can be displayed in the modal on the issue view.
+
+## Motivation
+
+Work Items main goal is to enhance the planning toolset in order to become the most popular collaboration tool for knowledge workers in any industry.
+
+- Puts all like-items (issues, incidents, epics, test cases etc.) on a standard platform in order to simplify maintenance and increase consistency in experience
+- Enables first-class support of common planning concepts in order to lower complexity and allow users to plan without learning GitLab-specific nuances.
+
+## Goals
+
+### Scalability
+
+Currently, different entities like issues, epics, merge requests etc share many similar features but these features are implemented separately for every entity type. This makes implementing new features or refactoring existing ones problematic: for example, if we plan to add new feature to issues and incidents, we would need to implement it separately on issue and incident types respectively. With work items, any new feature is implemented via widgets for all existing types which makes the architecture more scalable.
+
+### Flexibility
+
+With existing implementation, we have a rigid structure for issuables, merge requests, epics etc. This structure is defined on both backend and frontend, so any change requires a coordinated effort. Also, it would be very hard to make this structure customizable for the user without introducing a set of flags to enable/disable any existing feature. Work Item architecture allows frontend to display Work Item widgets in a flexible way: whatever is present in Work Item widgets, will be rendered on the page. This allows us to make changes fast and makes the structure way more flexible. For example, if we want to stop displaying labels on the Incident page, we simply remove labels widget from Incident Work Item type on the backend. Also, in the future this will allow users to define the set of widgets they want to see on custom Work Item types.
+
+### A consistent experience
+
+As much as we try to have consistent behavior for similar features on different entities, we still have differences in the implementation. For example, updating labels on merge request via GraphQL API can be done with dedicated `setMergeRequestLabels` mutation, while for the issue we call more coarse-grained `updateIssue`. This provides inconsistent experience for both frontend and external API users. As a result, epics, issues, requirements, and others all have similar but just subtle enough differences in common interactions that the user needs to hold a complicated mental model of how they each behave.
+
+Work Item architecture is designed with making all the features for all the types consistent, implemented as Work Item widgets.
+
+## High-level architecture problems to solve
+
+- how can we bypass groups and projects consolidation to migrate epics to Work Item type;
+- dealing with parent-child relationships for certain Work Item types: epic > issue > task, and to the same Work Item types: issue > issue.
+- [implementing custom Work Item types and custom widgets](https://gitlab.com/gitlab-org/gitlab/-/issues/335110)
+
+### Links
+
+- [Work items initiative epic](https://gitlab.com/groups/gitlab-org/-/epics/6033)
+- [Tasks roadmap](https://gitlab.com/groups/gitlab-org/-/epics/7103?_gl=1*zqatx*_ga*NzUyOTc3NTc1LjE2NjEzNDcwMDQ.*_ga_ENFH3X7M5Y*MTY2MjU0MDQ0MC43LjEuMTY2MjU0MDc2MC4wLjAuMA..)
+- [Work Item "Vision" Prototype](https://gitlab.com/gitlab-org/gitlab/-/issues/368607)
+- [Work Item Discussions](https://gitlab.com/groups/gitlab-org/-/epics/7060)
+
+### Who
+
+| Role | Who
+|------------------------------|-----------------------------|
+| Author | Natalia Tepluhina |
+| Architecture Evolution Coach | Kamil Trzciński |
+| Engineering Leader | TBD |
+| Product Manager | Gabe Weaver |
+| Domain Expert / Frontend | Natalia Tepluhina |
+| Domain Expert / Backend | Heinrich Lee Yu |
+| Domain Expert / Backend | Jan Provaznik |
+| Domain Expert / Backend | Mario Celi |
+
+DRIs:
+
+| Role | Who
+|------------------------------|------------------------|
+| Leadership | TBD |
+| Product | Gabe Weaver |
+| Engineering | TBD |
diff --git a/doc/development/gitlab_flavored_markdown/specification_guide/index.md b/doc/development/gitlab_flavored_markdown/specification_guide/index.md
index 53ef468556a..0765f502b9b 100644
--- a/doc/development/gitlab_flavored_markdown/specification_guide/index.md
+++ b/doc/development/gitlab_flavored_markdown/specification_guide/index.md
@@ -206,6 +206,9 @@ of specification-driven testing referred to in this documentation and elsewhere.
#### Markdown conformance testing
+NOTE:
+Markdown conformance testing for GLFM is not yet implemented.
+
_Markdown conformance testing_ refers to the standard testing method used by
all CommonMark Markdown dialects to verify that a specific implementation conforms
to the CommonMark Markdown specification. It is enforced by running the standard
@@ -804,36 +807,35 @@ consists of the manually updated Markdown+HTML examples for the
`glfm_specification/input/gitlab_flavored_markdown/glfm_official_specification_examples.md` sample entries:
-NOTE:
-All lines in this example are prefixed with a `|` character. This prefix helps avoid false
-errors when this file is checked by `markdownlint`, and possible errors in other Markdown editors.
-The actual file should not have these prefixed `|` characters.
+<!-- markdownlint-disable MD048 -->
-```plaintext
-|# Section with GLFM official specification examples
-|
-|## Strong
-|
-|### Strong with two asterisks
-|
-|```````````````````````````````` example
-|**bold**
-|.
-|<p><strong>bold</strong></p>
-|````````````````````````````````
-|
-|### Strong with HTML
-|
-|```````````````````````````````` example
-|<strong>
-|bold
-|</strong>
-|.
-|<p><strong>
-|bold
-|</strong></p>
-|````````````````````````````````
-```
+~~~plaintext
+# Section with GLFM official specification examples
+
+## Strong
+
+### Strong with two asterisks
+
+```````````````````````````````` example
+**bold**
+.
+<p><strong>bold</strong></p>
+````````````````````````````````
+
+### Strong with HTML
+
+```````````````````````````````` example
+<strong>
+bold
+</strong>
+.
+<p><strong>
+bold
+</strong></p>
+````````````````````````````````
+~~~
+
+<!-- markdownlint-enable MD048 -->
##### `glfm_internal_extension_examples.md`
@@ -1231,7 +1233,7 @@ This section describes how the scripts can be used to manage the GLFM specificat
1. Run [`update-specification.rb`](#update-specificationrb-script) to update the GLFM specification [output specification files](#output-specification-files).
1. Visually inspect and confirm any resulting changes to the [output specification files](#output-specification-files).
-1. Run [`run-spec-tests.sh`](http://gdk.test:3005/ee/development/gitlab_flavored_markdown/specification_guide/index.html#run-spec-testssh-script) to run the conformance tests against the canonicalized GLFM specification.
+1. Run [`run-spec-tests.sh`](#run-spec-testssh-script) to run the conformance tests against the canonicalized GLFM specification.
1. Commit any changes to the [output specification files](#output-specification-files).
### Update the example snapshots and run snapshot tests
diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md
index 8515474f025..0a12f551588 100644
--- a/doc/user/group/epics/manage_epics.md
+++ b/doc/user/group/epics/manage_epics.md
@@ -488,6 +488,8 @@ When you add an epic that's already linked to a parent epic, the link to its cur
Epics can contain multiple nested child epics, up to a total of seven levels deep.
+Maximum number of direct child epics is 100.
+
### Add a child epic to an epic
Prerequisites:
diff --git a/doc/user/markdown.md b/doc/user/markdown.md
index 250aa2a82f3..1a743ae99bb 100644
--- a/doc/user/markdown.md
+++ b/doc/user/markdown.md
@@ -1764,6 +1764,7 @@ If JSON is invalid, an error occurs.
## References
+- The [GitLab Flavored Markdown (GLFM) Specification Guide](../development/gitlab_flavored_markdown/index.md) is a developer-facing document that describes in detail the various goals, tools, implementations, and terms related to the GLFM specification.
- This document leveraged heavily from the [Markdown-Cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet).
- The original [Markdown Syntax Guide](https://daringfireball.net/projects/markdown/syntax)
at Daring Fireball is an excellent resource for a detailed explanation of standard Markdown.
diff --git a/lib/bulk_imports/common/rest/get_badges_query.rb b/lib/bulk_imports/common/rest/get_badges_query.rb
index 60b2ebcc552..6e7cb7504ba 100644
--- a/lib/bulk_imports/common/rest/get_badges_query.rb
+++ b/lib/bulk_imports/common/rest/get_badges_query.rb
@@ -7,11 +7,8 @@ module BulkImports
extend self
def to_h(context)
- resource = context.entity.pluralized_name
- encoded_full_path = ERB::Util.url_encode(context.entity.source_full_path)
-
{
- resource: [resource, encoded_full_path, 'badges'].join('/'),
+ resource: [context.entity.base_resource_path, 'badges'].join('/'),
query: {
page: context.tracker.next_page
}
diff --git a/lib/bulk_imports/groups/extractors/subgroups_extractor.rb b/lib/bulk_imports/groups/extractors/subgroups_extractor.rb
index 1140beef48c..029b6f0f729 100644
--- a/lib/bulk_imports/groups/extractors/subgroups_extractor.rb
+++ b/lib/bulk_imports/groups/extractors/subgroups_extractor.rb
@@ -5,10 +5,8 @@ module BulkImports
module Extractors
class SubgroupsExtractor
def extract(context)
- encoded_parent_path = ERB::Util.url_encode(context.entity.source_full_path)
-
response = http_client(context.configuration)
- .each_page(:get, "groups/#{encoded_parent_path}/subgroups")
+ .each_page(:get, "#{context.entity.base_resource_path}/subgroups")
.flat_map(&:itself)
BulkImports::Pipeline::ExtractedData.new(data: response)
diff --git a/lib/bulk_imports/groups/graphql/get_group_query.rb b/lib/bulk_imports/groups/graphql/get_group_query.rb
index 911b2b67d8c..0e73a7fb4b9 100644
--- a/lib/bulk_imports/groups/graphql/get_group_query.rb
+++ b/lib/bulk_imports/groups/graphql/get_group_query.rb
@@ -14,9 +14,9 @@ module BulkImports
<<-'GRAPHQL'
query($full_path: ID!) {
group(fullPath: $full_path) {
+ id
name
path
- full_path: fullPath
description
visibility
emails_disabled: emailsDisabled
diff --git a/lib/bulk_imports/groups/graphql/get_projects_query.rb b/lib/bulk_imports/groups/graphql/get_projects_query.rb
index 3f74bbb8cce..4784baf225c 100644
--- a/lib/bulk_imports/groups/graphql/get_projects_query.rb
+++ b/lib/bulk_imports/groups/graphql/get_projects_query.rb
@@ -20,6 +20,7 @@ module BulkImports
has_next_page: hasNextPage
}
nodes {
+ id
name
full_path: fullPath
}
diff --git a/lib/bulk_imports/groups/pipelines/project_entities_pipeline.rb b/lib/bulk_imports/groups/pipelines/project_entities_pipeline.rb
index c318675e649..026b2e55713 100644
--- a/lib/bulk_imports/groups/pipelines/project_entities_pipeline.rb
+++ b/lib/bulk_imports/groups/pipelines/project_entities_pipeline.rb
@@ -15,7 +15,8 @@ module BulkImports
source_full_path: data['full_path'],
destination_name: data['name'],
destination_namespace: context.entity.group.full_path,
- parent_id: context.entity.id
+ parent_id: context.entity.id,
+ source_xid: GlobalID.parse(data['id']).model_id
}
end
diff --git a/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb b/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb
index d9efcdb1ba5..83b442458dc 100644
--- a/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb
+++ b/lib/bulk_imports/groups/transformers/group_attributes_transformer.rb
@@ -4,6 +4,7 @@ module BulkImports
module Groups
module Transformers
class GroupAttributesTransformer
+ # rubocop: disable Style/IfUnlessModifier
def transform(context, data)
import_entity = context.entity
@@ -11,74 +12,64 @@ module BulkImports
namespace = Namespace.find_by_full_path(import_entity.destination_namespace)
end
- data
- .then { |data| transform_name(import_entity, namespace, data) }
- .then { |data| transform_path(import_entity, data) }
- .then { |data| transform_full_path(data) }
- .then { |data| transform_parent(context, import_entity, namespace, data) }
- .then { |data| transform_visibility_level(data) }
- .then { |data| transform_project_creation_level(data) }
- .then { |data| transform_subgroup_creation_level(data) }
- end
-
- private
+ params = {
+ 'name' => group_name(namespace, data),
+ 'path' => import_entity.destination_slug.parameterize,
+ 'description' => data['description'],
+ 'lfs_enabled' => data['lfs_enabled'],
+ 'emails_disabled' => data['emails_disabled'],
+ 'mentions_disabled' => data['mentions_disabled'],
+ 'share_with_group_lock' => data['share_with_group_lock']
+ }
- def transform_name(import_entity, namespace, data)
if namespace.present?
- namespace_children_names = namespace.children.pluck(:name) # rubocop: disable CodeReuse/ActiveRecord
-
- if namespace_children_names.include?(data['name'])
- data['name'] = Uniquify.new(1).string(-> (counter) { "#{data['name']}(#{counter})" }) do |base|
- namespace_children_names.include?(base)
- end
- end
+ params['parent_id'] = namespace.id
end
- data
- end
-
- def transform_path(import_entity, data)
- data['path'] = import_entity.destination_slug.parameterize
- data
- end
+ if data.has_key?('two_factor_grace_period')
+ params['two_factor_grace_period'] = data['two_factor_grace_period']
+ end
- def transform_full_path(data)
- data.delete('full_path')
- data
- end
+ if data.has_key?('request_access_enabled')
+ params['request_access_enabled'] = data['request_access_enabled']
+ end
- def transform_parent(context, import_entity, namespace, data)
- data['parent_id'] = namespace.id if namespace.present?
+ if data.has_key?('require_two_factor_authentication')
+ params['require_two_factor_authentication'] = data['require_two_factor_authentication']
+ end
- data
- end
+ if data.has_key?('project_creation_level')
+ params['project_creation_level'] =
+ Gitlab::Access.project_creation_string_options[data['project_creation_level']]
+ end
- def transform_visibility_level(data)
- visibility = data['visibility']
+ if data.has_key?('subgroup_creation_level')
+ params['subgroup_creation_level'] =
+ Gitlab::Access.subgroup_creation_string_options[data['subgroup_creation_level']]
+ end
- return data unless visibility.present?
+ if data.has_key?('visibility')
+ params['visibility_level'] = Gitlab::VisibilityLevel.string_options[data['visibility']]
+ end
- data['visibility_level'] = Gitlab::VisibilityLevel.string_options[visibility]
- data.delete('visibility')
- data
+ params
end
+ # rubocop: enable Style/IfUnlessModifier
- def transform_project_creation_level(data)
- project_creation_level = data['project_creation_level']
-
- return data unless project_creation_level.present?
-
- data['project_creation_level'] = Gitlab::Access.project_creation_string_options[project_creation_level]
- data
- end
+ private
- def transform_subgroup_creation_level(data)
- subgroup_creation_level = data['subgroup_creation_level']
+ def group_name(namespace, data)
+ if namespace.present?
+ namespace_children_names = namespace.children.pluck(:name) # rubocop: disable CodeReuse/ActiveRecord
- return data unless subgroup_creation_level.present?
+ if namespace_children_names.include?(data['name'])
+ data['name'] = Uniquify.new(1).string(-> (counter) { "#{data['name']}(#{counter})" }) do |base|
+ namespace_children_names.include?(base)
+ end
+ end
+ end
- data['subgroup_creation_level'] = Gitlab::Access.subgroup_creation_string_options[subgroup_creation_level]
- data
+ data['name']
end
end
end
diff --git a/lib/bulk_imports/projects/graphql/get_project_query.rb b/lib/bulk_imports/projects/graphql/get_project_query.rb
index 76475893ac1..a2d7094d570 100644
--- a/lib/bulk_imports/projects/graphql/get_project_query.rb
+++ b/lib/bulk_imports/projects/graphql/get_project_query.rb
@@ -10,6 +10,7 @@ module BulkImports
<<-'GRAPHQL'
query($full_path: ID!) {
project(fullPath: $full_path) {
+ id
visibility
created_at: createdAt
}
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 5ee5ec90361..41f409092f8 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -45788,6 +45788,9 @@ msgstr ""
msgid "You cannot access the raw file. Please wait a minute."
msgstr ""
+msgid "You cannot add any more epics. This epic already has maximum number of child epics."
+msgstr ""
+
msgid "You cannot approve your own deployment."
msgstr ""
diff --git a/spec/factories/bulk_import/entities.rb b/spec/factories/bulk_import/entities.rb
index cf31ffec4f6..eeb4f8325ae 100644
--- a/spec/factories/bulk_import/entities.rb
+++ b/spec/factories/bulk_import/entities.rb
@@ -9,6 +9,7 @@ FactoryBot.define do
sequence(:destination_namespace) { |n| "destination-path-#{n}" }
destination_name { 'Imported Entity' }
+ sequence(:source_xid)
trait(:group_entity) do
source_type { :group_entity }
diff --git a/spec/frontend/commit/commit_pipeline_status_component_spec.js b/spec/frontend/commit/commit_pipeline_status_component_spec.js
index 73720c1cc88..e75fb697a7b 100644
--- a/spec/frontend/commit/commit_pipeline_status_component_spec.js
+++ b/spec/frontend/commit/commit_pipeline_status_component_spec.js
@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import Visibility from 'visibilityjs';
import { nextTick } from 'vue';
import fixture from 'test_fixtures/pipelines/pipelines.json';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import Poll from '~/lib/utils/poll';
import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
@@ -170,7 +170,7 @@ describe('Commit pipeline status component', () => {
});
it('displays flash error message', () => {
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/error_tracking/components/error_details_spec.js b/spec/frontend/error_tracking/components/error_details_spec.js
index 732eff65495..9d6e46be8c4 100644
--- a/spec/frontend/error_tracking/components/error_details_spec.js
+++ b/spec/frontend/error_tracking/components/error_details_spec.js
@@ -18,7 +18,7 @@ import {
trackErrorDetailsViewsOptions,
trackErrorStatusUpdateOptions,
} from '~/error_tracking/utils';
-import createFlash from '~/flash';
+import { createAlert, VARIANT_WARNING } from '~/flash';
import { __ } from '~/locale';
import Tracking from '~/tracking';
@@ -144,7 +144,7 @@ describe('ErrorDetails', () => {
await nextTick();
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true);
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
expect(mocks.$apollo.queries.error.stopPolling).not.toHaveBeenCalled();
});
@@ -156,9 +156,9 @@ describe('ErrorDetails', () => {
await nextTick();
expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false);
expect(wrapper.findComponent(GlLink).exists()).toBe(false);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Could not connect to Sentry. Refresh the page to try again.',
- type: 'warning',
+ variant: VARIANT_WARNING,
});
expect(mocks.$apollo.queries.error.stopPolling).toHaveBeenCalled();
});
diff --git a/spec/frontend/error_tracking/store/actions_spec.js b/spec/frontend/error_tracking/store/actions_spec.js
index 6bac21341a7..8f085282f80 100644
--- a/spec/frontend/error_tracking/store/actions_spec.js
+++ b/spec/frontend/error_tracking/store/actions_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/error_tracking/store/actions';
import * as types from '~/error_tracking/store/mutation_types';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { visitUrl } from '~/lib/utils/url_utility';
@@ -20,7 +20,7 @@ describe('Sentry common store actions', () => {
afterEach(() => {
mock.restore();
- createFlash.mockClear();
+ createAlert.mockClear();
});
const endpoint = '123/stacktrace';
const redirectUrl = '/list';
@@ -49,7 +49,7 @@ describe('Sentry common store actions', () => {
mock.onPut().reply(400, {});
await testAction(actions.updateStatus, params, {}, [], []);
expect(visitUrl).not.toHaveBeenCalled();
- expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledTimes(1);
});
});
diff --git a/spec/frontend/error_tracking/store/details/actions_spec.js b/spec/frontend/error_tracking/store/details/actions_spec.js
index a3a6f7cc309..1893d226270 100644
--- a/spec/frontend/error_tracking/store/details/actions_spec.js
+++ b/spec/frontend/error_tracking/store/details/actions_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/error_tracking/store/details/actions';
import * as types from '~/error_tracking/store/details/mutation_types';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import Poll from '~/lib/utils/poll';
@@ -19,7 +19,7 @@ describe('Sentry error details store actions', () => {
afterEach(() => {
mockedAdapter.restore();
- createFlash.mockClear();
+ createAlert.mockClear();
if (mockedRestart) {
mockedRestart.mockRestore();
mockedRestart = null;
@@ -53,7 +53,7 @@ describe('Sentry error details store actions', () => {
[{ type: types.SET_LOADING_STACKTRACE, payload: false }],
[],
);
- expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledTimes(1);
});
it('should not restart polling when receiving an empty 204 response', async () => {
diff --git a/spec/frontend/error_tracking/store/list/actions_spec.js b/spec/frontend/error_tracking/store/list/actions_spec.js
index 7173f68bb96..2809bbe834e 100644
--- a/spec/frontend/error_tracking/store/list/actions_spec.js
+++ b/spec/frontend/error_tracking/store/list/actions_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import * as actions from '~/error_tracking/store/list/actions';
import * as types from '~/error_tracking/store/list/mutation_types';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import httpStatusCodes from '~/lib/utils/http_status';
@@ -51,7 +51,7 @@ describe('error tracking actions', () => {
],
[],
);
- expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledTimes(1);
});
});
diff --git a/spec/frontend/feature_highlight/feature_highlight_helper_spec.js b/spec/frontend/feature_highlight/feature_highlight_helper_spec.js
index b87571830ca..22bac3fca15 100644
--- a/spec/frontend/feature_highlight/feature_highlight_helper_spec.js
+++ b/spec/frontend/feature_highlight/feature_highlight_helper_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import { dismiss } from '~/feature_highlight/feature_highlight_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import httpStatusCodes from '~/lib/utils/http_status';
@@ -32,7 +32,7 @@ describe('feature highlight helper', () => {
await dismiss(endpoint, highlightId);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message:
'An error occurred while dismissing the feature highlight. Refresh the page and try dismissing again.',
});
diff --git a/spec/frontend/grafana_integration/components/grafana_integration_spec.js b/spec/frontend/grafana_integration/components/grafana_integration_spec.js
index d2111194097..021a3aa41ed 100644
--- a/spec/frontend/grafana_integration/components/grafana_integration_spec.js
+++ b/spec/frontend/grafana_integration/components/grafana_integration_spec.js
@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import { TEST_HOST } from 'helpers/test_constants';
import { mountExtended } from 'helpers/vue_test_utils_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import GrafanaIntegration from '~/grafana_integration/components/grafana_integration.vue';
import { createStore } from '~/grafana_integration/store';
import axios from '~/lib/utils/axios_utils';
@@ -30,7 +30,7 @@ describe('grafana integration component', () => {
afterEach(() => {
if (wrapper.destroy) {
wrapper.destroy();
- createFlash.mockReset();
+ createAlert.mockReset();
refreshCurrentPage.mockReset();
}
});
@@ -113,7 +113,7 @@ describe('grafana integration component', () => {
await nextTick();
await jest.runAllTicks();
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: `There was an error saving your changes. ${message}`,
});
});
diff --git a/spec/frontend/groups/components/app_spec.js b/spec/frontend/groups/components/app_spec.js
index a4a7530184d..33d76a8571d 100644
--- a/spec/frontend/groups/components/app_spec.js
+++ b/spec/frontend/groups/components/app_spec.js
@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import appComponent from '~/groups/components/app.vue';
import groupFolderComponent from '~/groups/components/group_folder.vue';
import groupItemComponent from '~/groups/components/group_item.vue';
@@ -115,7 +115,7 @@ describe('AppComponent', () => {
return vm.fetchGroups({}).then(() => {
expect(vm.isLoading).toBe(false);
expect(window.scrollTo).toHaveBeenCalledWith({ behavior: 'smooth', top: 0 });
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred. Please try again.',
});
});
@@ -326,7 +326,7 @@ describe('AppComponent', () => {
expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath);
return waitForPromises().then(() => {
expect(vm.store.removeGroup).not.toHaveBeenCalled();
- expect(createFlash).toHaveBeenCalledWith({ message });
+ expect(createAlert).toHaveBeenCalledWith({ message });
expect(vm.targetGroup.isBeingRemoved).toBe(false);
});
});
@@ -341,7 +341,7 @@ describe('AppComponent', () => {
expect(vm.service.leaveGroup).toHaveBeenCalledWith(childGroupItem.leavePath);
return waitForPromises().then(() => {
expect(vm.store.removeGroup).not.toHaveBeenCalled();
- expect(createFlash).toHaveBeenCalledWith({ message });
+ expect(createAlert).toHaveBeenCalledWith({ message });
expect(vm.targetGroup.isBeingRemoved).toBe(false);
});
});
diff --git a/spec/frontend/ide/components/new_dropdown/modal_spec.js b/spec/frontend/ide/components/new_dropdown/modal_spec.js
index 68cc08d2ebc..c6f9fd0c4ea 100644
--- a/spec/frontend/ide/components/new_dropdown/modal_spec.js
+++ b/spec/frontend/ide/components/new_dropdown/modal_spec.js
@@ -1,6 +1,6 @@
import { GlButton, GlModal } from '@gitlab/ui';
import { nextTick } from 'vue';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import Modal from '~/ide/components/new_dropdown/modal.vue';
import { createStore } from '~/ide/stores';
import { stubComponent } from 'helpers/stub_component';
@@ -341,7 +341,7 @@ describe('new file modal component', () => {
});
it('does not trigger flash', () => {
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
});
@@ -360,7 +360,7 @@ describe('new file modal component', () => {
});
it('does not trigger flash', () => {
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
});
});
@@ -380,7 +380,7 @@ describe('new file modal component', () => {
});
it('creates flash', () => {
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'The name "src" is already taken in this directory.',
fadeTransition: false,
addBodyClass: true,
@@ -405,7 +405,7 @@ describe('new file modal component', () => {
});
it('does not create flash', () => {
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
it('dispatches event', () => {
diff --git a/spec/frontend/ide/stores/actions/merge_request_spec.js b/spec/frontend/ide/stores/actions/merge_request_spec.js
index abc3ba5b0a2..f1b2a7b881a 100644
--- a/spec/frontend/ide/stores/actions/merge_request_spec.js
+++ b/spec/frontend/ide/stores/actions/merge_request_spec.js
@@ -3,7 +3,7 @@ import { range } from 'lodash';
import { stubPerformanceWebAPI } from 'helpers/performance';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { leftSidebarViews, PERMISSION_READ_MR, MAX_MR_FILES_AUTO_OPEN } from '~/ide/constants';
import service from '~/ide/services';
import { createStore } from '~/ide/stores';
@@ -139,8 +139,8 @@ describe('IDE store merge request actions', () => {
branchId: 'bar',
})
.catch(() => {
- expect(createFlash).toHaveBeenCalled();
- expect(createFlash.mock.calls[0][0].message).toBe(
+ expect(createAlert).toHaveBeenCalled();
+ expect(createAlert.mock.calls[0][0].message).toBe(
'Error fetching merge requests for bar',
);
});
@@ -520,7 +520,7 @@ describe('IDE store merge request actions', () => {
store.dispatch.mockRejectedValue();
return openMergeRequest(store, mr).catch(() => {
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: expect.any(String),
});
});
diff --git a/spec/frontend/ide/stores/actions/project_spec.js b/spec/frontend/ide/stores/actions/project_spec.js
index cc7d39b4d43..5a5ead4c544 100644
--- a/spec/frontend/ide/stores/actions/project_spec.js
+++ b/spec/frontend/ide/stores/actions/project_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import testAction from 'helpers/vuex_action_helper';
import api from '~/api';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import service from '~/ide/services';
import { createStore } from '~/ide/stores';
import {
@@ -97,7 +97,7 @@ describe('IDE store project actions', () => {
});
afterEach(() => {
- createFlash.mockRestore();
+ createAlert.mockRestore();
});
it.each`
@@ -122,7 +122,7 @@ describe('IDE store project actions', () => {
if (!responseSuccess) {
expect(logError).toHaveBeenCalled();
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
}
});
});
diff --git a/spec/frontend/ide/stores/actions_spec.js b/spec/frontend/ide/stores/actions_spec.js
index 21480ef873f..fd2c3d18813 100644
--- a/spec/frontend/ide/stores/actions_spec.js
+++ b/spec/frontend/ide/stores/actions_spec.js
@@ -4,6 +4,7 @@ import testAction from 'helpers/vuex_action_helper';
import eventHub from '~/ide/eventhub';
import { createRouter } from '~/ide/ide_router';
import { createStore } from '~/ide/stores';
+import { createAlert } from '~/flash';
import {
init,
stageAllChanges,
@@ -29,6 +30,7 @@ jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn(),
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
}));
+jest.mock('~/flash');
describe('Multi-file store actions', () => {
let store;
@@ -158,7 +160,7 @@ describe('Multi-file store actions', () => {
type: 'tree',
});
expect(store.state.entries[tree.path].tempFile).toEqual(false);
- expect(document.querySelector('.flash-alert')).not.toBeNull();
+ expect(createAlert).toHaveBeenCalled();
});
});
@@ -216,8 +218,10 @@ describe('Multi-file store actions', () => {
name: 'test',
type: 'blob',
});
- expect(document.querySelector('.flash-alert')?.textContent.trim()).toEqual(
- `The name "${f.name}" is already taken in this directory.`,
+ expect(createAlert).toHaveBeenCalledWith(
+ expect.objectContaining({
+ message: `The name "${f.name}" is already taken in this directory.`,
+ }),
);
});
});
@@ -930,7 +934,7 @@ describe('Multi-file store actions', () => {
);
expect(dispatch.mock.calls).toHaveLength(0);
- expect(document.querySelector('.flash-alert')).not.toBeNull();
+ expect(createAlert).toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js b/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js
index ecda7f304ba..f48797415df 100644
--- a/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js
+++ b/spec/frontend/ide/stores/modules/terminal/actions/session_controls_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import * as actions from '~/ide/stores/modules/terminal/actions/session_controls';
import { STARTING, PENDING, STOPPING, STOPPED } from '~/ide/stores/modules/terminal/constants';
import * as messages from '~/ide/stores/modules/terminal/messages';
@@ -89,7 +89,7 @@ describe('IDE store terminal session controls actions', () => {
it('flashes message', () => {
actions.receiveStartSessionError({ dispatch });
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: messages.UNEXPECTED_ERROR_STARTING,
});
});
@@ -163,7 +163,7 @@ describe('IDE store terminal session controls actions', () => {
it('flashes message', () => {
actions.receiveStopSessionError({ dispatch });
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: messages.UNEXPECTED_ERROR_STOPPING,
});
});
diff --git a/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js b/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js
index eabc69b23aa..fe2328f25c2 100644
--- a/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js
+++ b/spec/frontend/ide/stores/modules/terminal/actions/session_status_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import * as actions from '~/ide/stores/modules/terminal/actions/session_status';
import { PENDING, RUNNING, STOPPING, STOPPED } from '~/ide/stores/modules/terminal/constants';
import * as messages from '~/ide/stores/modules/terminal/messages';
@@ -115,7 +115,7 @@ describe('IDE store terminal session controls actions', () => {
it('flashes message', () => {
actions.receiveSessionStatusError({ dispatch });
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: messages.UNEXPECTED_ERROR_STATUS,
});
});
diff --git a/spec/frontend/import_entities/import_groups/components/import_table_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
index f97ea046cbe..cb967267b7f 100644
--- a/spec/frontend/import_entities/import_groups/components/import_table_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
@@ -5,7 +5,7 @@ import VueApollo from 'vue-apollo';
import MockAdapter from 'axios-mock-adapter';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import httpStatus from '~/lib/utils/http_status';
import axios from '~/lib/utils/axios_utils';
import { STATUSES } from '~/import_entities/constants';
@@ -246,7 +246,7 @@ describe('import table', () => {
await findImportButtons()[0].trigger('click');
await waitForPromises();
- expect(createFlash).toHaveBeenCalledWith(
+ expect(createAlert).toHaveBeenCalledWith(
expect.objectContaining({
message: i18n.ERROR_IMPORT,
}),
diff --git a/spec/frontend/import_entities/import_groups/services/status_poller_spec.js b/spec/frontend/import_entities/import_groups/services/status_poller_spec.js
index 01f976562c6..13d2a95ca14 100644
--- a/spec/frontend/import_entities/import_groups/services/status_poller_spec.js
+++ b/spec/frontend/import_entities/import_groups/services/status_poller_spec.js
@@ -1,6 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import Visibility from 'visibilityjs';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { STATUSES } from '~/import_entities/constants';
import { StatusPoller } from '~/import_entities/import_groups/services/status_poller';
import axios from '~/lib/utils/axios_utils';
@@ -83,7 +83,7 @@ describe('Bulk import status poller', () => {
it('when error occurs shows flash with error', () => {
const [[pollConfig]] = Poll.mock.calls;
pollConfig.errorCallback();
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
});
it('when success response arrives updates relevant group status', () => {
diff --git a/spec/frontend/import_entities/import_projects/store/actions_spec.js b/spec/frontend/import_entities/import_projects/store/actions_spec.js
index 0ebe8525b5a..f6b34f4e4ca 100644
--- a/spec/frontend/import_entities/import_projects/store/actions_spec.js
+++ b/spec/frontend/import_entities/import_projects/store/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import { TEST_HOST } from 'helpers/test_constants';
import testAction from 'helpers/vuex_action_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { STATUSES } from '~/import_entities/constants';
import actionsFactory from '~/import_entities/import_projects/store/actions';
import { getImportTarget } from '~/import_entities/import_projects/store/getters';
@@ -155,7 +155,7 @@ describe('import_projects store actions', () => {
[],
);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Provider rate limit exceeded. Try again later',
});
});
@@ -234,7 +234,7 @@ describe('import_projects store actions', () => {
[],
);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Importing the project failed',
});
});
@@ -257,7 +257,7 @@ describe('import_projects store actions', () => {
[],
);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: `Importing the project failed: ${ERROR_MESSAGE}`,
});
});
@@ -358,7 +358,7 @@ describe('import_projects store actions', () => {
[],
);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Requesting namespaces failed',
});
});
diff --git a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
index b518d2fbdec..680dbd68493 100644
--- a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
+++ b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
@@ -7,7 +7,7 @@ import {
issuable1,
issuable2,
} from 'jest/issuable/components/related_issuable_mock_data';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { linkedIssueTypesMap } from '~/related_issues/constants';
import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue';
@@ -136,7 +136,7 @@ describe('RelatedIssuesRoot', () => {
await createComponent();
jest.spyOn(wrapper.vm, 'processAllReferences');
jest.spyOn(wrapper.vm.service, 'addRelatedIssues');
- createFlash.mockClear();
+ createAlert.mockClear();
});
it('processes references before submitting', () => {
@@ -207,12 +207,12 @@ describe('RelatedIssuesRoot', () => {
mock.onPost(defaultProps.endpoint).reply(409, { message });
wrapper.vm.store.setPendingReferences([issuable1.reference, issuable2.reference]);
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', input);
await waitForPromises();
- expect(createFlash).toHaveBeenCalledWith({ message });
+ expect(createAlert).toHaveBeenCalledWith({ message });
});
});
diff --git a/spec/frontend/milestones/components/promote_milestone_modal_spec.js b/spec/frontend/milestones/components/promote_milestone_modal_spec.js
index 11eaa92f2b0..60657fbc9b8 100644
--- a/spec/frontend/milestones/components/promote_milestone_modal_spec.js
+++ b/spec/frontend/milestones/components/promote_milestone_modal_spec.js
@@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import { setHTMLFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'helpers/wait_for_promises';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import * as urlUtils from '~/lib/utils/url_utility';
import PromoteMilestoneModal from '~/milestones/components/promote_milestone_modal.vue';
@@ -103,7 +103,7 @@ describe('Promote milestone modal', () => {
wrapper.findComponent(GlModal).vm.$emit('primary');
await waitForPromises();
- expect(createFlash).toHaveBeenCalledWith({ message: dummyError });
+ expect(createAlert).toHaveBeenCalledWith({ message: dummyError });
});
});
});
diff --git a/spec/frontend/monitoring/components/dashboard_spec.js b/spec/frontend/monitoring/components/dashboard_spec.js
index 1de6b6e3e98..1d17a9116df 100644
--- a/spec/frontend/monitoring/components/dashboard_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_spec.js
@@ -4,7 +4,7 @@ import { nextTick } from 'vue';
import setWindowLocation from 'helpers/set_window_location_helper';
import { TEST_HOST } from 'helpers/test_constants';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import { ESC_KEY } from '~/lib/utils/keys';
import { objectToQuery } from '~/lib/utils/url_utility';
@@ -198,7 +198,7 @@ describe('Dashboard', () => {
);
await nextTick();
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
});
it('does not display a warning if there are no validation warnings', async () => {
@@ -210,7 +210,7 @@ describe('Dashboard', () => {
);
await nextTick();
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
});
@@ -275,7 +275,7 @@ describe('Dashboard', () => {
setupStoreWithData(store);
await nextTick();
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
expect(store.dispatch).not.toHaveBeenCalledWith(
'monitoringDashboard/setExpandedPanel',
expect.anything(),
diff --git a/spec/frontend/monitoring/components/dashboard_url_time_spec.js b/spec/frontend/monitoring/components/dashboard_url_time_spec.js
index a327e234581..9873654bdda 100644
--- a/spec/frontend/monitoring/components/dashboard_url_time_spec.js
+++ b/spec/frontend/monitoring/components/dashboard_url_time_spec.js
@@ -1,7 +1,7 @@
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import {
queryToObject,
@@ -115,7 +115,7 @@ describe('dashboard invalid url parameters', () => {
createMountedWrapper();
await nextTick();
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
expect(findDateTimePicker().props('value')).toEqual(defaultTimeRange);
diff --git a/spec/frontend/monitoring/store/actions_spec.js b/spec/frontend/monitoring/store/actions_spec.js
index a872a7780eb..ca66768c3cc 100644
--- a/spec/frontend/monitoring/store/actions_spec.js
+++ b/spec/frontend/monitoring/store/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import { backoffMockImplementation } from 'helpers/backoff_helper';
import testAction from 'helpers/vuex_action_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import * as commonUtils from '~/lib/utils/common_utils';
import statusCodes from '~/lib/utils/http_status';
@@ -82,7 +82,7 @@ describe('Monitoring store actions', () => {
mock.reset();
commonUtils.backOff.mockReset();
- createFlash.mockReset();
+ createAlert.mockReset();
});
// Setup
@@ -241,7 +241,7 @@ describe('Monitoring store actions', () => {
'receiveMetricsDashboardFailure',
new Error('Request failed with status code 500'),
);
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
});
it('dispatches a failure action when a message is returned', async () => {
@@ -250,7 +250,7 @@ describe('Monitoring store actions', () => {
'receiveMetricsDashboardFailure',
new Error('Request failed with status code 500'),
);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: expect.stringContaining(mockDashboardsErrorResponse.message),
});
});
@@ -263,7 +263,7 @@ describe('Monitoring store actions', () => {
'receiveMetricsDashboardFailure',
new Error('Request failed with status code 500'),
);
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
});
});
@@ -328,7 +328,7 @@ describe('Monitoring store actions', () => {
},
});
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
it('dispatches fetchPrometheusMetric for each panel query', async () => {
@@ -385,7 +385,7 @@ describe('Monitoring store actions', () => {
defaultQueryParams,
});
- expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledTimes(1);
});
});
@@ -570,7 +570,7 @@ describe('Monitoring store actions', () => {
[],
[{ type: 'receiveDeploymentsDataFailure' }],
() => {
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
},
);
});
@@ -1084,8 +1084,8 @@ describe('Monitoring store actions', () => {
return testAction(fetchVariableMetricLabelValues, { defaultQueryParams }, state, [], []).then(
() => {
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: expect.stringContaining('error getting options for variable "label1"'),
});
},
diff --git a/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
index 1a88aebae32..f6d3957115f 100644
--- a/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
+++ b/spec/frontend/pages/projects/forks/new/components/project_namespace_spec.js
@@ -10,7 +10,7 @@ import { mount, shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import searchQuery from '~/pages/projects/forks/new/queries/search_forkable_namespaces.query.graphql';
import ProjectNamespace from '~/pages/projects/forks/new/components/project_namespace.vue';
@@ -167,7 +167,7 @@ describe('ProjectNamespace component', () => {
});
it('creates a flash message and captures the error', () => {
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while loading data. Please refresh the page to try again.',
captureError: true,
error: expect.any(Error),
diff --git a/spec/frontend/persistent_user_callout_spec.js b/spec/frontend/persistent_user_callout_spec.js
index 9cd5bb9e9a1..c9574208900 100644
--- a/spec/frontend/persistent_user_callout_spec.js
+++ b/spec/frontend/persistent_user_callout_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import PersistentUserCallout from '~/persistent_user_callout';
@@ -108,7 +108,7 @@ describe('PersistentUserCallout', () => {
await waitForPromises();
expect(persistentUserCallout.container.remove).not.toHaveBeenCalled();
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred while dismissing the alert. Refresh the page and try again.',
});
});
@@ -214,7 +214,7 @@ describe('PersistentUserCallout', () => {
await waitForPromises();
expect(window.location.assign).not.toHaveBeenCalled();
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message:
'An error occurred while acknowledging the notification. Refresh the page and try again.',
});
diff --git a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
index e920cd48163..117e106e15b 100644
--- a/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
+++ b/spec/frontend/projects/settings/repository/branch_rules/app_spec.js
@@ -6,7 +6,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import BranchRules, { i18n } from '~/projects/settings/repository/branch_rules/app.vue';
import BranchRule from '~/projects/settings/repository/branch_rules/components/branch_rule.vue';
import branchRulesQuery from '~/projects/settings/repository/branch_rules/graphql/queries/branch_rules.query.graphql';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { branchRulesMockResponse, propsDataMock } from './mock_data';
jest.mock('~/flash');
@@ -39,7 +39,7 @@ describe('Branch rules app', () => {
it('displays an error if branch rules query fails', async () => {
await createComponent({ queryHandler: jest.fn().mockRejectedValue() });
- expect(createFlash).toHaveBeenCalledWith({ message: i18n.queryError });
+ expect(createAlert).toHaveBeenCalledWith({ message: i18n.queryError });
});
it('displays an empty state if no branch rules are present', async () => {
diff --git a/spec/frontend/protected_branches/protected_branch_edit_spec.js b/spec/frontend/protected_branches/protected_branch_edit_spec.js
index 6ef1b58a956..0aec4fbc037 100644
--- a/spec/frontend/protected_branches/protected_branch_edit_spec.js
+++ b/spec/frontend/protected_branches/protected_branch_edit_spec.js
@@ -2,7 +2,7 @@ import MockAdapter from 'axios-mock-adapter';
import $ from 'jquery';
import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures';
import { TEST_HOST } from 'helpers/test_constants';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
import ProtectedBranchEdit from '~/protected_branches/protected_branch_edit';
@@ -136,7 +136,7 @@ describe('ProtectedBranchEdit', () => {
expect(toggle).not.toHaveClass(IS_DISABLED_CLASS);
expect(toggle.querySelector(IS_LOADING_SELECTOR)).toBe(null);
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
});
@@ -149,7 +149,7 @@ describe('ProtectedBranchEdit', () => {
it('flashes error', async () => {
await axios.waitForAll();
- expect(createFlash).toHaveBeenCalled();
+ expect(createAlert).toHaveBeenCalled();
});
});
});
diff --git a/spec/frontend/releases/components/app_index_spec.js b/spec/frontend/releases/components/app_index_spec.js
index f64f07de90e..48589a54ec4 100644
--- a/spec/frontend/releases/components/app_index_spec.js
+++ b/spec/frontend/releases/components/app_index_spec.js
@@ -6,7 +6,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { historyPushState } from '~/lib/utils/common_utils';
import { sprintf, __ } from '~/locale';
import ReleasesIndexApp from '~/releases/components/app_index.vue';
@@ -161,13 +161,13 @@ describe('app_index.vue', () => {
it(`${toDescription(flashMessage)} show a flash message`, async () => {
await waitForPromises();
if (flashMessage) {
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: ReleasesIndexApp.i18n.errorMessage,
captureError: true,
error: expect.any(Error),
});
} else {
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
}
});
diff --git a/spec/frontend/releases/components/app_show_spec.js b/spec/frontend/releases/components/app_show_spec.js
index 9ca25b3b69a..c5cb8589ee8 100644
--- a/spec/frontend/releases/components/app_show_spec.js
+++ b/spec/frontend/releases/components/app_show_spec.js
@@ -4,7 +4,7 @@ import VueApollo from 'vue-apollo';
import oneReleaseQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release.query.graphql.json';
import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import ReleaseShowApp from '~/releases/components/app_show.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue';
@@ -53,13 +53,13 @@ describe('Release show component', () => {
const expectNoFlash = () => {
it('does not show a flash message', () => {
- expect(createFlash).not.toHaveBeenCalled();
+ expect(createAlert).not.toHaveBeenCalled();
});
};
const expectFlashWithMessage = (message) => {
it(`shows a flash message that reads "${message}"`, () => {
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message,
captureError: true,
error: expect.any(Error),
diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js
index 67a07e82532..eeee6747349 100644
--- a/spec/frontend/releases/stores/modules/detail/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js
@@ -2,7 +2,7 @@ import { cloneDeep } from 'lodash';
import originalOneReleaseForEditingQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release_for_editing.query.graphql.json';
import testAction from 'helpers/vuex_action_helper';
import { getTag } from '~/api/tags_api';
-import createFlash from '~/flash';
+import { createAlert } from '~/flash';
import { redirectTo } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import { ASSET_LINK_TYPE } from '~/releases/constants';
@@ -59,7 +59,7 @@ describe('Release edit/new actions', () => {
releaseResponse = cloneDeep(originalOneReleaseForEditingQueryResponse);
gon.api_version = 'v4';
error = new Error('Yikes!');
- createFlash.mockClear();
+ createAlert.mockClear();
});
describe('when creating a new release', () => {
@@ -151,8 +151,8 @@ describe('Release edit/new actions', () => {
it(`shows a flash message`, () => {
return actions.fetchRelease({ commit: jest.fn(), state, rootState: state }).then(() => {
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while getting the release details.',
});
});
@@ -379,8 +379,8 @@ describe('Release edit/new actions', () => {
return actions
.createRelease({ commit: jest.fn(), dispatch: jest.fn(), state, getters: {} })
.then(() => {
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Yikes!',
});
});
@@ -405,8 +405,8 @@ describe('Release edit/new actions', () => {
return actions
.createRelease({ commit: jest.fn(), dispatch: jest.fn(), state, getters: {} })
.then(() => {
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while creating a new release.',
});
});
@@ -536,8 +536,8 @@ describe('Release edit/new actions', () => {
it('shows a flash message', async () => {
await actions.updateRelease({ commit, dispatch, state, getters });
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while saving the release details.',
});
});
@@ -556,8 +556,8 @@ describe('Release edit/new actions', () => {
it('shows a flash message', async () => {
await actions.updateRelease({ commit, dispatch, state, getters });
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while saving the release details.',
});
});
@@ -709,8 +709,8 @@ describe('Release edit/new actions', () => {
it('shows a flash message', async () => {
await actions.deleteRelease({ commit, dispatch, state, getters });
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while deleting the release.',
});
});
@@ -745,8 +745,8 @@ describe('Release edit/new actions', () => {
it('shows a flash message', async () => {
await actions.deleteRelease({ commit, dispatch, state, getters });
- expect(createFlash).toHaveBeenCalledTimes(1);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledTimes(1);
+ expect(createAlert).toHaveBeenCalledWith({
message: 'Something went wrong while deleting the release.',
});
});
@@ -788,7 +788,7 @@ describe('Release edit/new actions', () => {
[],
);
- expect(createFlash).toHaveBeenCalledWith({
+ expect(createAlert).toHaveBeenCalledWith({
message: s__('Release|Unable to fetch the tag notes.'),
});
expect(getTag).toHaveBeenCalledWith(state.projectId, tagName);
diff --git a/spec/frontend/work_items/components/work_item_assignees_spec.js b/spec/frontend/work_items/components/work_item_assignees_spec.js
index 901b2ba63c6..1b204b6fd60 100644
--- a/spec/frontend/work_items/components/work_item_assignees_spec.js
+++ b/spec/frontend/work_items/components/work_item_assignees_spec.js
@@ -160,7 +160,9 @@ describe('WorkItemAssignees component', () => {
it('has a label', () => {
createComponent();
- expect(findTokenSelector().props('ariaLabelledby')).toContain('assignees-title-');
+ expect(findTokenSelector().props('ariaLabelledby')).toEqual(
+ findAssigneesTitle().attributes('id'),
+ );
});
describe('when clicking outside the token selector', () => {
diff --git a/spec/frontend/work_items/components/work_item_labels_spec.js b/spec/frontend/work_items/components/work_item_labels_spec.js
index f59d512d610..e8173997ac1 100644
--- a/spec/frontend/work_items/components/work_item_labels_spec.js
+++ b/spec/frontend/work_items/components/work_item_labels_spec.js
@@ -21,8 +21,8 @@ describe('WorkItemLabels component', () => {
const findTokenSelector = () => wrapper.findComponent(GlTokenSelector);
const findSkeletonLoader = () => wrapper.findComponent(GlSkeletonLoader);
-
const findEmptyState = () => wrapper.findByTestId('empty-state');
+ const findLabelsTitle = () => wrapper.findByTestId('labels-title');
const successSearchQueryHandler = jest.fn().mockResolvedValue(projectLabelsResponse);
const errorHandler = jest.fn().mockRejectedValue('Houston, we have a problem');
@@ -63,7 +63,7 @@ describe('WorkItemLabels component', () => {
it('has a label', () => {
createComponent();
- expect(findTokenSelector().props('ariaLabelledby')).toContain('labels-title-');
+ expect(findTokenSelector().props('ariaLabelledby')).toEqual(findLabelsTitle().attributes('id'));
});
it('focuses token selector on token selector input event', async () => {
diff --git a/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb b/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb
index f0b461e518e..5220b9d37e5 100644
--- a/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/common/pipelines/lfs_objects_pipeline_spec.rb
@@ -7,7 +7,7 @@ RSpec.describe BulkImports::Common::Pipelines::LfsObjectsPipeline do
let_it_be(:oid) { 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' }
let(:tmpdir) { Dir.mktmpdir }
- let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test') }
+ let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test', source_xid: nil) }
let(:tracker) { create(:bulk_import_tracker, entity: entity) }
let(:context) { BulkImports::Pipeline::Context.new(tracker) }
let(:lfs_dir_path) { tmpdir }
diff --git a/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb b/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb
index f650e931dc7..7a93365d098 100644
--- a/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/common/pipelines/uploads_pipeline_spec.rb
@@ -152,14 +152,14 @@ RSpec.describe BulkImports::Common::Pipelines::UploadsPipeline do
context 'when importing to group' do
let(:portable) { group }
- let(:entity) { create(:bulk_import_entity, :group_entity, group: group, source_full_path: 'test') }
+ let(:entity) { create(:bulk_import_entity, :group_entity, group: group, source_full_path: 'test', source_xid: nil) }
include_examples 'uploads import'
end
context 'when importing to project' do
let(:portable) { project }
- let(:entity) { create(:bulk_import_entity, :project_entity, project: project, source_full_path: 'test') }
+ let(:entity) { create(:bulk_import_entity, :project_entity, project: project, source_full_path: 'test', source_xid: nil) }
include_examples 'uploads import'
end
diff --git a/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb b/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb
index 0a04c0a2243..fabef50af8b 100644
--- a/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb
+++ b/spec/lib/bulk_imports/common/rest/get_badges_query_spec.rb
@@ -9,15 +9,32 @@ RSpec.describe BulkImports::Common::Rest::GetBadgesQuery do
let(:context) { BulkImports::Pipeline::Context.new(tracker) }
let(:encoded_full_path) { ERB::Util.url_encode(entity.source_full_path) }
- it 'returns correct query and page info' do
- expected = {
- resource: [entity.pluralized_name, encoded_full_path, 'badges'].join('/'),
- query: {
- page: context.tracker.next_page
+ context 'when source id is present' do
+ it 'returns correct query using source id and page info' do
+ expected = {
+ resource: [entity.base_resource_path, 'badges'].join('/'),
+ query: {
+ page: context.tracker.next_page
+ }
}
- }
- expect(described_class.to_h(context)).to eq(expected)
+ expect(described_class.to_h(context)).to eq(expected)
+ end
+ end
+
+ context 'when source id is missing' do
+ it 'returns correct query using source full path' do
+ entity.update!(source_xid: nil)
+
+ expected = {
+ resource: ["/#{entity.pluralized_name}", encoded_full_path, 'badges'].join('/'),
+ query: {
+ page: context.tracker.next_page
+ }
+ }
+
+ expect(described_class.to_h(context)).to eq(expected)
+ end
end
end
diff --git a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb
index 441a34b0c74..36b425f4f12 100644
--- a/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/groups/pipelines/group_pipeline_spec.rb
@@ -13,7 +13,7 @@ RSpec.describe BulkImports::Groups::Pipelines::GroupPipeline do
:bulk_import_entity,
bulk_import: bulk_import,
source_full_path: 'source/full/path',
- destination_name: 'My Destination Group',
+ destination_slug: 'my-destination-group',
destination_namespace: parent.full_path
)
end
diff --git a/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb b/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb
index 5b6c93e695f..c07d27e973f 100644
--- a/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/groups/pipelines/project_entities_pipeline_spec.rb
@@ -19,6 +19,7 @@ RSpec.describe BulkImports::Groups::Pipelines::ProjectEntitiesPipeline do
let(:extracted_data) do
BulkImports::Pipeline::ExtractedData.new(data: {
+ 'id' => 'gid://gitlab/Project/1234567',
'name' => 'project',
'full_path' => 'group/project'
})
@@ -44,6 +45,7 @@ RSpec.describe BulkImports::Groups::Pipelines::ProjectEntitiesPipeline do
expect(project_entity.source_full_path).to eq('group/project')
expect(project_entity.destination_name).to eq('project')
expect(project_entity.destination_namespace).to eq(destination_group.full_path)
+ expect(project_entity.source_xid).to eq(1234567)
end
end
diff --git a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb
index 896af865c56..32d8dc8e207 100644
--- a/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb
+++ b/spec/lib/bulk_imports/groups/transformers/group_attributes_transformer_spec.rb
@@ -24,59 +24,67 @@ RSpec.describe BulkImports::Groups::Transformers::GroupAttributesTransformer do
let(:data) do
{
'name' => 'Source Group Name',
+ 'description' => 'Source Group Description',
'path' => 'source-group-path',
'full_path' => 'source/full/path',
'visibility' => 'private',
'project_creation_level' => 'developer',
- 'subgroup_creation_level' => 'maintainer'
+ 'subgroup_creation_level' => 'maintainer',
+ 'emails_disabled' => true,
+ 'lfs_enabled' => false,
+ 'mentions_disabled' => true,
+ 'share_with_group_lock' => false,
+ 'require_two_factor_authentication' => false,
+ 'two_factor_grace_period' => 100,
+ 'request_access_enabled' => false
}
end
subject { described_class.new }
it 'returns original data with some keys transformed' do
- transformed_data = subject.transform(context, { 'name' => 'Name', 'description' => 'Description' })
+ transformed_data = subject.transform(context, data)
expect(transformed_data).to eq({
- 'name' => 'Name',
- 'description' => 'Description',
+ 'name' => 'Source Group Name',
+ 'description' => 'Source Group Description',
'parent_id' => parent.id,
- 'path' => 'destination-slug-path'
+ 'path' => entity.destination_slug,
+ 'visibility_level' => Gitlab::VisibilityLevel.string_options[data['visibility']],
+ 'project_creation_level' => Gitlab::Access.project_creation_string_options[data['project_creation_level']],
+ 'subgroup_creation_level' => Gitlab::Access.subgroup_creation_string_options[data['subgroup_creation_level']],
+ 'emails_disabled' => true,
+ 'lfs_enabled' => false,
+ 'mentions_disabled' => true,
+ 'share_with_group_lock' => false,
+ 'require_two_factor_authentication' => false,
+ 'two_factor_grace_period' => 100,
+ 'request_access_enabled' => false
})
end
- it 'transforms path from destination_slug' do
- transformed_data = subject.transform(context, data)
-
- expect(transformed_data['path']).to eq(entity.destination_slug)
- end
-
- it 'removes full path' do
- transformed_data = subject.transform(context, data)
-
- expect(transformed_data).not_to have_key('full_path')
- end
-
- it 'transforms visibility level' do
- visibility = data['visibility']
- transformed_data = subject.transform(context, data)
-
- expect(transformed_data).not_to have_key('visibility')
- expect(transformed_data['visibility_level']).to eq(Gitlab::VisibilityLevel.string_options[visibility])
- end
-
- it 'transforms project creation level' do
- level = data['project_creation_level']
- transformed_data = subject.transform(context, data)
+ context 'when some fields are not present' do
+ it 'does not include those fields' do
+ data = {
+ 'name' => 'Source Group Name',
+ 'description' => 'Source Group Description',
+ 'path' => 'source-group-path',
+ 'full_path' => 'source/full/path'
+ }
- expect(transformed_data['project_creation_level']).to eq(Gitlab::Access.project_creation_string_options[level])
- end
-
- it 'transforms subgroup creation level' do
- level = data['subgroup_creation_level']
- transformed_data = subject.transform(context, data)
+ transformed_data = subject.transform(context, data)
- expect(transformed_data['subgroup_creation_level']).to eq(Gitlab::Access.subgroup_creation_string_options[level])
+ expect(transformed_data).to eq({
+ 'name' => 'Source Group Name',
+ 'path' => 'destination-slug-path',
+ 'description' => 'Source Group Description',
+ 'parent_id' => parent.id,
+ 'share_with_group_lock' => nil,
+ 'emails_disabled' => nil,
+ 'lfs_enabled' => nil,
+ 'mentions_disabled' => nil
+ })
+ end
end
describe 'parent group transformation' do
diff --git a/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb
index 39b539ece21..6a509ca7f14 100644
--- a/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/projects/pipelines/design_bundle_pipeline_spec.rb
@@ -8,7 +8,10 @@ RSpec.describe BulkImports::Projects::Pipelines::DesignBundlePipeline do
let(:portable) { create(:project) }
let(:tmpdir) { Dir.mktmpdir }
let(:design_bundle_path) { File.join(tmpdir, 'design.bundle') }
- let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test') }
+ let(:entity) do
+ create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test', source_xid: nil)
+ end
+
let(:tracker) { create(:bulk_import_tracker, entity: entity) }
let(:context) { BulkImports::Pipeline::Context.new(tracker) }
diff --git a/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb b/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb
index 712c37ee578..b8c21feb05d 100644
--- a/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb
+++ b/spec/lib/bulk_imports/projects/pipelines/repository_bundle_pipeline_spec.rb
@@ -8,7 +8,10 @@ RSpec.describe BulkImports::Projects::Pipelines::RepositoryBundlePipeline do
let(:portable) { create(:project) }
let(:tmpdir) { Dir.mktmpdir }
let(:bundle_path) { File.join(tmpdir, 'repository.bundle') }
- let(:entity) { create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test') }
+ let(:entity) do
+ create(:bulk_import_entity, :project_entity, project: portable, source_full_path: 'test', source_xid: nil)
+ end
+
let(:tracker) { create(:bulk_import_tracker, entity: entity) }
let(:context) { BulkImports::Pipeline::Context.new(tracker) }
diff --git a/spec/models/bulk_imports/entity_spec.rb b/spec/models/bulk_imports/entity_spec.rb
index 47d355de1d8..fab32af5bd4 100644
--- a/spec/models/bulk_imports/entity_spec.rb
+++ b/spec/models/bulk_imports/entity_spec.rb
@@ -236,7 +236,7 @@ RSpec.describe BulkImports::Entity, type: :model do
it 'returns group export relations url' do
entity = build(:bulk_import_entity, :group_entity)
- expect(entity.export_relations_url_path).to eq("/groups/#{entity.encoded_source_full_path}/export_relations")
+ expect(entity.export_relations_url_path).to eq("/groups/#{entity.source_xid}/export_relations")
end
end
@@ -244,7 +244,7 @@ RSpec.describe BulkImports::Entity, type: :model do
it 'returns project export relations url' do
entity = build(:bulk_import_entity, :project_entity)
- expect(entity.export_relations_url_path).to eq("/projects/#{entity.encoded_source_full_path}/export_relations")
+ expect(entity.export_relations_url_path).to eq("/projects/#{entity.source_xid}/export_relations")
end
end
end
@@ -254,7 +254,7 @@ RSpec.describe BulkImports::Entity, type: :model do
entity = build(:bulk_import_entity)
expect(entity.relation_download_url_path('test'))
- .to eq("/groups/#{entity.encoded_source_full_path}/export_relations/download?relation=test")
+ .to eq("/groups/#{entity.source_xid}/export_relations/download?relation=test")
end
end
@@ -290,15 +290,15 @@ RSpec.describe BulkImports::Entity, type: :model do
describe '#base_resource_url_path' do
it 'returns base entity url path' do
- entity = build(:bulk_import_entity)
+ entity = build(:bulk_import_entity, source_xid: nil)
- expect(entity.base_resource_url_path).to eq("/groups/#{entity.encoded_source_full_path}")
+ expect(entity.base_resource_path).to eq("/groups/#{entity.encoded_source_full_path}")
end
end
describe '#wiki_url_path' do
it 'returns entity wiki url path' do
- entity = build(:bulk_import_entity)
+ entity = build(:bulk_import_entity, source_xid: nil)
expect(entity.wikis_url_path).to eq("/groups/#{entity.encoded_source_full_path}/wikis")
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 0128b32aadb..6f659b3a41d 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -181,6 +181,8 @@ RSpec.configure do |config|
config.include RSpec::Benchmark::Matchers, type: :benchmark
config.include DetailedErrorHelpers
+ config.include_context 'when rendered has no HTML escapes', type: :view
+
include StubFeatureFlags
include StubSnowplow
include StubMember
diff --git a/spec/support/helpers/html_escaped_helpers.rb b/spec/support/helpers/html_escaped_helpers.rb
index 7f6825e9598..7cbea7e7428 100644
--- a/spec/support/helpers/html_escaped_helpers.rb
+++ b/spec/support/helpers/html_escaped_helpers.rb
@@ -21,4 +21,35 @@ module HtmlEscapedHelpers
match_data
end
+
+ # Checks if +content+ contains HTML escaped tags and raises an exception
+ # if it does.
+ #
+ # See #match_html_escaped_tags for details.
+ def ensure_no_html_escaped_tags!(content, example)
+ match_data = match_html_escaped_tags(content)
+ return unless match_data
+
+ # Truncate
+ pre_match = match_data.pre_match.last(50)
+ match = match_data[0]
+ post_match = match_data.post_match.first(50)
+
+ string = "#{pre_match}«#{match}»#{post_match}"
+
+ raise <<~MESSAGE
+ The following string contains HTML escaped tags:
+
+ #{string}
+
+ Please consider using `.html_safe`.
+
+ This check can be disabled via:
+
+ it #{example.description.inspect}, :skip_html_escaped_tags_check do
+ ...
+ end
+
+ MESSAGE
+ end
end
diff --git a/spec/support/shared_contexts/html_safe_shared_context.rb b/spec/support/shared_contexts/html_safe_shared_context.rb
new file mode 100644
index 00000000000..9bdaea9fe64
--- /dev/null
+++ b/spec/support/shared_contexts/html_safe_shared_context.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+RSpec.shared_context 'when rendered has no HTML escapes' do
+ # Check once per example if `rendered` contains HTML escapes.
+ let(:rendered) do |example|
+ super().tap do |rendered|
+ next if example.metadata[:skip_html_escaped_tags_check]
+
+ HtmlEscapedHelpers.ensure_no_html_escaped_tags!(rendered, example)
+ end
+ end
+end
+
+RSpec.shared_context 'when page has no HTML escapes' do
+ # Check once per example if `page` contains HTML escapes.
+ let(:page) do |example|
+ super().tap do |page|
+ next if example.metadata[:skip_html_escaped_tags_check]
+
+ HtmlEscapedHelpers.ensure_no_html_escaped_tags!(page.native.to_s, example)
+ end
+ end
+end
diff --git a/spec/support/shared_contexts/views/html_safe_render_shared_context.rb b/spec/support/shared_contexts/views/html_safe_render_shared_context.rb
deleted file mode 100644
index 3acca60c901..00000000000
--- a/spec/support/shared_contexts/views/html_safe_render_shared_context.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.shared_context 'when rendered view has no HTML escapes', type: :view do
- # Check once per example if `rendered` contains HTML escapes.
- let(:rendered) do |example|
- super().tap do |rendered|
- next if example.metadata[:skip_html_escaped_tags_check]
-
- ensure_no_html_escaped_tags!(rendered, example)
- end
- end
-
- def ensure_no_html_escaped_tags!(content, example)
- match_data = HtmlEscapedHelpers.match_html_escaped_tags(content)
- return unless match_data
-
- # Truncate
- pre_match = match_data.pre_match.last(50)
- match = match_data[0]
- post_match = match_data.post_match.first(50)
-
- string = "#{pre_match}«#{match}»#{post_match}"
-
- raise <<~MESSAGE
- The following string contains HTML escaped tags:
-
- #{string}
-
- Please consider using `.html_safe`.
-
- This check can be disabled via:
-
- it #{example.description.inspect}, :skip_html_escaped_tags_check do
- ...
- end
-
- MESSAGE
- end
-end
diff --git a/spec/support/view_component.rb b/spec/support/view_component.rb
index 9166a06fc8c..912bfda6d33 100644
--- a/spec/support/view_component.rb
+++ b/spec/support/view_component.rb
@@ -4,4 +4,11 @@ require 'view_component/test_helpers'
RSpec.configure do |config|
config.include ViewComponent::TestHelpers, type: :component
config.include Capybara::RSpecMatchers, type: :component
+ config.include Devise::Test::ControllerHelpers, type: :component
+
+ config.before(:each, type: :component) do
+ @request = controller.request
+ end
+
+ config.include_context 'when page has no HTML escapes', type: :component
end
diff --git a/spec/support_specs/helpers/html_escaped_helpers_spec.rb b/spec/support_specs/helpers/html_escaped_helpers_spec.rb
index 337f7ecc659..77ca6231881 100644
--- a/spec/support_specs/helpers/html_escaped_helpers_spec.rb
+++ b/spec/support_specs/helpers/html_escaped_helpers_spec.rb
@@ -40,4 +40,33 @@ RSpec.describe HtmlEscapedHelpers do
specify { expect(actual_match).to eq(expected_match) }
end
end
+
+ describe '#ensure_no_html_escaped_tags!' do
+ subject { |example| described_class.ensure_no_html_escaped_tags!(content, example) }
+
+ context 'when content contains HTML escaped chars' do
+ let(:content) { 'See &lt;a href=""&gt;Link&lt;/a&gt;' }
+
+ it 'raises an exception' do
+ parts = [
+ 'The following string contains HTML escaped tags:',
+ 'See «&lt;a» href=""&gt;Link&lt;/a&gt;',
+ 'This check can be disabled via:',
+ %(it "raises an exception", :skip_html_escaped_tags_check do)
+ ]
+
+ regexp = Regexp.new(parts.join('.*'), Regexp::MULTILINE)
+
+ expect { subject }.to raise_error(regexp)
+ end
+ end
+
+ context 'when content does not contain HTML escaped tags' do
+ let(:content) { 'See <a href="">Link</a>' }
+
+ it 'does not raise anything' do
+ expect(subject).to be_nil
+ end
+ end
+ end
end
diff --git a/spec/workers/bulk_import_worker_spec.rb b/spec/workers/bulk_import_worker_spec.rb
index 7e301efe708..0d0b81d2ec0 100644
--- a/spec/workers/bulk_import_worker_spec.rb
+++ b/spec/workers/bulk_import_worker_spec.rb
@@ -87,7 +87,6 @@ RSpec.describe BulkImportWorker do
create(:bulk_import_entity, :created, bulk_import: bulk_import)
expect(described_class).to receive(:perform_in).with(described_class::PERFORM_DELAY, bulk_import.id)
- expect(BulkImports::EntityWorker).to receive(:perform_async).twice
expect(BulkImports::ExportRequestWorker).to receive(:perform_async).twice
subject.perform(bulk_import.id)
@@ -111,7 +110,7 @@ RSpec.describe BulkImportWorker do
bulk_import = create(:bulk_import, :created)
create(:bulk_import_entity, :created, bulk_import: bulk_import)
- allow(BulkImports::EntityWorker).to receive(:perform_async).and_raise(StandardError)
+ allow(BulkImports::ExportRequestWorker).to receive(:perform_async).and_raise(StandardError)
expect(Gitlab::ErrorTracking).to receive(:track_exception).with(kind_of(StandardError), bulk_import_id: bulk_import.id)
diff --git a/spec/workers/bulk_imports/export_request_worker_spec.rb b/spec/workers/bulk_imports/export_request_worker_spec.rb
index a7f7aaa7dba..8d78c2ca35c 100644
--- a/spec/workers/bulk_imports/export_request_worker_spec.rb
+++ b/spec/workers/bulk_imports/export_request_worker_spec.rb
@@ -21,11 +21,13 @@ RSpec.describe BulkImports::ExportRequestWorker do
shared_examples 'requests relations export for api resource' do
include_examples 'an idempotent worker' do
- it 'requests relations export' do
+ it 'requests relations export & schedules entity worker' do
expect_next_instance_of(BulkImports::Clients::HTTP) do |client|
expect(client).to receive(:post).with(expected).twice
end
+ expect(BulkImports::EntityWorker).to receive(:perform_async).twice
+
perform_multiple(job_args)
end
@@ -55,19 +57,78 @@ RSpec.describe BulkImports::ExportRequestWorker do
expect(failure.exception_message).to eq('Export error')
end
end
+
+ context 'when source id is nil' do
+ let(:entity_source_id) { 'gid://gitlab/Model/1234567' }
+
+ before do
+ graphql_client = instance_double(BulkImports::Clients::Graphql)
+ response = double(original_hash: { 'data' => { entity.entity_type => { 'id' => entity_source_id } } })
+
+ allow(BulkImports::Clients::Graphql).to receive(:new).and_return(graphql_client)
+ allow(graphql_client).to receive(:parse)
+ allow(graphql_client).to receive(:execute).and_return(response)
+ end
+
+ it 'updates entity source id & requests export using source id' do
+ expect_next_instance_of(BulkImports::Clients::HTTP) do |client|
+ expect(client)
+ .to receive(:post)
+ .with("/#{entity.pluralized_name}/1234567/export_relations")
+ .twice
+ end
+
+ entity.update!(source_xid: nil)
+
+ perform_multiple(job_args)
+
+ expect(entity.reload.source_xid).to eq(1234567)
+ end
+
+ context 'when something goes wrong during source id fetch' do
+ let(:entity_source_id) { 'invalid' }
+
+ it 'logs the error & requests relations export using full path url' do
+ expect_next_instance_of(BulkImports::Clients::HTTP) do |client|
+ expect(client).to receive(:post).with(full_path_url).twice
+ end
+
+ entity.update!(source_xid: nil)
+
+ expect(Gitlab::Import::Logger).to receive(:error).with(
+ a_hash_including(
+ 'message' => 'Failed to fetch source entity id',
+ 'bulk_import_entity_id' => entity.id,
+ 'pipeline_class' => 'ExportRequestWorker',
+ 'exception_class' => 'NoMethodError',
+ 'exception_message' => "undefined method `model_id' for nil:NilClass",
+ 'correlation_id_value' => anything,
+ 'bulk_import_id' => bulk_import.id,
+ 'bulk_import_entity_type' => entity.source_type
+ )
+ ).twice
+
+ perform_multiple(job_args)
+
+ expect(entity.source_xid).to be_nil
+ end
+ end
+ end
end
end
context 'when entity is group' do
let(:entity) { create(:bulk_import_entity, :group_entity, source_full_path: 'foo/bar', bulk_import: bulk_import) }
- let(:expected) { '/groups/foo%2Fbar/export_relations' }
+ let(:expected) { "/groups/#{entity.source_xid}/export_relations" }
+ let(:full_path_url) { '/groups/foo%2Fbar/export_relations' }
include_examples 'requests relations export for api resource'
end
context 'when entity is project' do
let(:entity) { create(:bulk_import_entity, :project_entity, source_full_path: 'foo/bar', bulk_import: bulk_import) }
- let(:expected) { '/projects/foo%2Fbar/export_relations' }
+ let(:expected) { "/projects/#{entity.source_xid}/export_relations" }
+ let(:full_path_url) { '/projects/foo%2Fbar/export_relations' }
include_examples 'requests relations export for api resource'
end