Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-28 09:09:28 +00:00
parent f8184e504b
commit f3cfb235c7
133 changed files with 856 additions and 561 deletions

View File

@ -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'

View File

@ -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,
});
}
},

View File

@ -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'),
}),
);

View File

@ -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.'),
});
},

View File

@ -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.'),
});
},

View File

@ -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);

View File

@ -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.'),
});
});

View File

@ -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.'),
});
})

View File

@ -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!'),
});
};

View File

@ -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.',
),

View File

@ -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.'),
});
},

View File

@ -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.'),
});
},

View File

@ -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.'),
});
},

View File

@ -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

View File

@ -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'),
}),
);

View File

@ -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'),
});

View File

@ -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}`,
});
};

View File

@ -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.'),
});
});

View File

@ -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;
});
},

View File

@ -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;

View File

@ -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,
}),

View File

@ -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,
}),
);

View File

@ -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,

View File

@ -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;
}
};

View File

@ -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,

View File

@ -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,

View File

@ -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');
};

View File

@ -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');
};

View File

@ -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,

View File

@ -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'),
}),
});

View File

@ -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'),
});

View File

@ -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,
});
})

View File

@ -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'),
}),
);

View File

@ -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.'),
}),
);

View File

@ -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,
});

View File

@ -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.',
),

View File

@ -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;
});
});

View File

@ -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,
}),

View File

@ -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.',
),

View File

@ -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'),
}),
);

View File

@ -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'),
}),
);

View File

@ -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'),
}),
);

View File

@ -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'),
}),
);

View File

@ -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,
}),
);

View File

@ -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'),
}),
);

View File

@ -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.',
),

View File

@ -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.') }));
}
}

View File

@ -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;

View File

@ -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 });
},
},
},

View File

@ -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.'),
}),
);

View File

@ -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'),
});
},

View File

@ -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'),
}),
);

View File

@ -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!') });
});
}

View File

@ -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,
});
});

View File

@ -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.') });
});
}
},

View File

@ -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,

View File

@ -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,

View File

@ -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.'),
});
});

View File

@ -142,9 +142,6 @@ export default {
property: `type_${this.workItemType}`,
};
},
assigneeListEmpty() {
return this.assignees.length === 0;
},
containerClass() {
return !this.isEditing ? 'gl-shadow-none!' : '';
},

View File

@ -102,9 +102,6 @@ export default {
allowScopedLabels() {
return this.labelsWidget.allowScopedLabels;
},
listEmpty() {
return this.labels.length === 0;
},
containerClass() {
return !this.isEditing ? 'gl-shadow-none!' : '';
},

View File

@ -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;
},

View File

@ -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?

View File

@ -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' }

View File

@ -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' }

View File

@ -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

View File

@ -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'

View File

@ -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.')

View File

@ -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

View File

@ -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 = {
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
}
Gitlab::Import::Logger.error(
structured_payload(
attributes.merge(
log_attributes(exception, entity).merge(
bulk_import_id: entity.bulk_import.id,
bulk_import_entity_type: entity.source_type
)
)
)
BulkImports::Failure.create(attributes)
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(
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
)
)
)
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

View File

@ -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:

View File

@ -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.

View File

@ -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),

View File

@ -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 |

View File

@ -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

View File

@ -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:

View File

@ -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.

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -20,6 +20,7 @@ module BulkImports
has_next_page: hasNextPage
}
nodes {
id
name
full_path: fullPath
}

View File

@ -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

View File

@ -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,19 +12,53 @@ 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) }
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']
}
if namespace.present?
params['parent_id'] = namespace.id
end
if data.has_key?('two_factor_grace_period')
params['two_factor_grace_period'] = data['two_factor_grace_period']
end
if data.has_key?('request_access_enabled')
params['request_access_enabled'] = data['request_access_enabled']
end
if data.has_key?('require_two_factor_authentication')
params['require_two_factor_authentication'] = data['require_two_factor_authentication']
end
if data.has_key?('project_creation_level')
params['project_creation_level'] =
Gitlab::Access.project_creation_string_options[data['project_creation_level']]
end
if data.has_key?('subgroup_creation_level')
params['subgroup_creation_level'] =
Gitlab::Access.subgroup_creation_string_options[data['subgroup_creation_level']]
end
if data.has_key?('visibility')
params['visibility_level'] = Gitlab::VisibilityLevel.string_options[data['visibility']]
end
params
end
# rubocop: enable Style/IfUnlessModifier
private
def transform_name(import_entity, namespace, data)
def group_name(namespace, data)
if namespace.present?
namespace_children_names = namespace.children.pluck(:name) # rubocop: disable CodeReuse/ActiveRecord
@ -34,51 +69,7 @@ module BulkImports
end
end
data
end
def transform_path(import_entity, data)
data['path'] = import_entity.destination_slug.parameterize
data
end
def transform_full_path(data)
data.delete('full_path')
data
end
def transform_parent(context, import_entity, namespace, data)
data['parent_id'] = namespace.id if namespace.present?
data
end
def transform_visibility_level(data)
visibility = data['visibility']
return data unless visibility.present?
data['visibility_level'] = Gitlab::VisibilityLevel.string_options[visibility]
data.delete('visibility')
data
end
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
def transform_subgroup_creation_level(data)
subgroup_creation_level = data['subgroup_creation_level']
return data unless subgroup_creation_level.present?
data['subgroup_creation_level'] = Gitlab::Access.subgroup_creation_string_options[subgroup_creation_level]
data
data['name']
end
end
end

View File

@ -10,6 +10,7 @@ module BulkImports
<<-'GRAPHQL'
query($full_path: ID!) {
project(fullPath: $full_path) {
id
visibility
created_at: createdAt
}

View File

@ -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 ""

View File

@ -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 }

View File

@ -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();
});
});
});

View File

@ -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();
});

View File

@ -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);
});
});

View File

@ -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 () => {

View File

@ -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);
});
});

View File

@ -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.',
});

View File

@ -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}`,
});
});

View File

@ -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);
});
});

View File

@ -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', () => {

View File

@ -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),
});
});

View File

@ -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();
}
});
});

View File

@ -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();
});
});
});

View File

@ -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,
});
});

View File

@ -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,
});
});

View File

@ -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,
}),

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