From 8106ac487c3b52471e2ca894c65c13162c2fb1a8 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Thu, 14 Jan 2021 15:10:46 +0000 Subject: Add latest changes from gitlab-org/gitlab@master --- app/assets/javascripts/api.js | 40 ++++++++++++- app/assets/javascripts/api/api_utils.js | 5 ++ app/assets/javascripts/api/constants.js | 1 + app/assets/javascripts/api/groups_api.js | 22 ++++++++ app/assets/javascripts/api/projects_api.js | 27 +++++++++ app/assets/javascripts/api/user_api.js | 66 ++++++++++++++++++++++ .../components/project_select_deprecated.vue | 2 +- .../javascripts/commons/nav/user_merge_requests.js | 4 +- .../javascripts/frequent_items/store/actions.js | 8 ++- .../components/members_token_select.vue | 4 +- app/assets/javascripts/lib/utils/users_cache.js | 8 +-- app/assets/javascripts/notes/stores/actions.js | 9 +-- app/assets/javascripts/performance_bar/index.js | 23 ++------ app/assets/javascripts/rest_api.js | 15 +++++ .../set_status_modal/set_status_modal_wrapper.vue | 4 +- .../vue_merge_request_widget/mr_widget_options.vue | 10 +++- 16 files changed, 203 insertions(+), 45 deletions(-) create mode 100644 app/assets/javascripts/api/api_utils.js create mode 100644 app/assets/javascripts/api/constants.js create mode 100644 app/assets/javascripts/api/groups_api.js create mode 100644 app/assets/javascripts/api/projects_api.js create mode 100644 app/assets/javascripts/api/user_api.js create mode 100644 app/assets/javascripts/rest_api.js (limited to 'app/assets') diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js index 2f3a56ec046..e0b9643f509 100644 --- a/app/assets/javascripts/api.js +++ b/app/assets/javascripts/api.js @@ -5,6 +5,12 @@ import { __ } from '~/locale'; const DEFAULT_PER_PAGE = 20; +/** + * Slow deprecation Notice: Please rather use for new calls + * or during refactors /rest_api as this is doing named exports + * which support treeshaking + */ + const Api = { DEFAULT_PER_PAGE, groupsPath: '/api/:version/groups.json', @@ -152,7 +158,10 @@ const Api = { }); }, - // Return groups list. Filtered by query + /** + * @deprecated This method will be removed soon. Use the + * `getGroups` method in `~/rest_api` instead. + */ groups(query, options, callback = () => {}) { const url = Api.buildUrl(Api.groupsPath); return axios @@ -188,7 +197,10 @@ const Api = { .then(({ data }) => callback(data)); }, - // Return projects list. Filtered by query + /** + * @deprecated This method will be removed soon. Use the + * `getProjects` method in `~/rest_api` instead. + */ projects(query, options, callback = () => {}) { const url = Api.buildUrl(Api.projectsPath); const defaults = { @@ -521,6 +533,10 @@ const Api = { .replace(':namespace_path', namespacePath); }, + /** + * @deprecated This method will be removed soon. Use the + * `getUsers` method in `~/rest_api` instead. + */ users(query, options) { const url = Api.buildUrl(this.usersPath); return axios.get(url, { @@ -532,6 +548,10 @@ const Api = { }); }, + /** + * @deprecated This method will be removed soon. Use the + * `getUser` method in `~/rest_api` instead. + */ user(id, options) { const url = Api.buildUrl(this.userPath).replace(':id', encodeURIComponent(id)); return axios.get(url, { @@ -539,11 +559,19 @@ const Api = { }); }, + /** + * @deprecated This method will be removed soon. Use the + * `getUserCounts` method in `~/rest_api` instead. + */ userCounts() { const url = Api.buildUrl(this.userCountsPath); return axios.get(url); }, + /** + * @deprecated This method will be removed soon. Use the + * `getUserStatus` method in `~/rest_api` instead. + */ userStatus(id, options) { const url = Api.buildUrl(this.userStatusPath).replace(':id', encodeURIComponent(id)); return axios.get(url, { @@ -551,6 +579,10 @@ const Api = { }); }, + /** + * @deprecated This method will be removed soon. Use the + * `getUserProjects` method in `~/rest_api` instead. + */ userProjects(userId, query, options, callback) { const url = Api.buildUrl(Api.userProjectsPath).replace(':id', userId); const defaults = { @@ -586,6 +618,10 @@ const Api = { }); }, + /** + * @deprecated This method will be removed soon. Use the + * `updateUserStatus` method in `~/rest_api` instead. + */ postUserStatus({ emoji, message, availability }) { const url = Api.buildUrl(this.userPostStatusPath); diff --git a/app/assets/javascripts/api/api_utils.js b/app/assets/javascripts/api/api_utils.js new file mode 100644 index 00000000000..42eb5e7aaf3 --- /dev/null +++ b/app/assets/javascripts/api/api_utils.js @@ -0,0 +1,5 @@ +import { joinPaths } from '../lib/utils/url_utility'; + +export function buildApiUrl(url) { + return joinPaths('/', gon.relative_url_root || '', url.replace(':version', gon.api_version)); +} diff --git a/app/assets/javascripts/api/constants.js b/app/assets/javascripts/api/constants.js new file mode 100644 index 00000000000..b6c720a85f3 --- /dev/null +++ b/app/assets/javascripts/api/constants.js @@ -0,0 +1 @@ +export const DEFAULT_PER_PAGE = 20; diff --git a/app/assets/javascripts/api/groups_api.js b/app/assets/javascripts/api/groups_api.js new file mode 100644 index 00000000000..d4ba46656e6 --- /dev/null +++ b/app/assets/javascripts/api/groups_api.js @@ -0,0 +1,22 @@ +import axios from '../lib/utils/axios_utils'; +import { buildApiUrl } from './api_utils'; +import { DEFAULT_PER_PAGE } from './constants'; + +const GROUPS_PATH = '/api/:version/groups.json'; + +export function getGroups(query, options, callback = () => {}) { + const url = buildApiUrl(GROUPS_PATH); + return axios + .get(url, { + params: { + search: query, + per_page: DEFAULT_PER_PAGE, + ...options, + }, + }) + .then(({ data }) => { + callback(data); + + return data; + }); +} diff --git a/app/assets/javascripts/api/projects_api.js b/app/assets/javascripts/api/projects_api.js new file mode 100644 index 00000000000..d9a2467cff3 --- /dev/null +++ b/app/assets/javascripts/api/projects_api.js @@ -0,0 +1,27 @@ +import axios from '../lib/utils/axios_utils'; +import { buildApiUrl } from './api_utils'; +import { DEFAULT_PER_PAGE } from './constants'; + +const PROJECTS_PATH = '/api/:version/projects.json'; + +export function getProjects(query, options, callback = () => {}) { + const url = buildApiUrl(PROJECTS_PATH); + const defaults = { + search: query, + per_page: DEFAULT_PER_PAGE, + simple: true, + }; + + if (gon.current_user_id) { + defaults.membership = true; + } + + return axios + .get(url, { + params: Object.assign(defaults, options), + }) + .then(({ data, headers }) => { + callback(data); + return { data, headers }; + }); +} diff --git a/app/assets/javascripts/api/user_api.js b/app/assets/javascripts/api/user_api.js new file mode 100644 index 00000000000..e5983ec3c58 --- /dev/null +++ b/app/assets/javascripts/api/user_api.js @@ -0,0 +1,66 @@ +import axios from '../lib/utils/axios_utils'; +import { buildApiUrl } from './api_utils'; +import { DEFAULT_PER_PAGE } from './constants'; +import { deprecatedCreateFlash as flash } from '~/flash'; +import { __ } from '~/locale'; + +const USER_COUNTS_PATH = '/api/:version/user_counts'; +const USERS_PATH = '/api/:version/users.json'; +const USER_PATH = '/api/:version/users/:id'; +const USER_STATUS_PATH = '/api/:version/users/:id/status'; +const USER_PROJECTS_PATH = '/api/:version/users/:id/projects'; +const USER_POST_STATUS_PATH = '/api/:version/user/status'; + +export function getUsers(query, options) { + const url = buildApiUrl(USERS_PATH); + return axios.get(url, { + params: { + search: query, + per_page: DEFAULT_PER_PAGE, + ...options, + }, + }); +} + +export function getUser(id, options) { + const url = buildApiUrl(USER_PATH).replace(':id', encodeURIComponent(id)); + return axios.get(url, { + params: options, + }); +} + +export function getUserCounts() { + const url = buildApiUrl(USER_COUNTS_PATH); + return axios.get(url); +} + +export function getUserStatus(id, options) { + const url = buildApiUrl(USER_STATUS_PATH).replace(':id', encodeURIComponent(id)); + return axios.get(url, { + params: options, + }); +} + +export function getUserProjects(userId, query, options, callback) { + const url = buildApiUrl(USER_PROJECTS_PATH).replace(':id', userId); + const defaults = { + search: query, + per_page: DEFAULT_PER_PAGE, + }; + return axios + .get(url, { + params: { ...defaults, ...options }, + }) + .then(({ data }) => callback(data)) + .catch(() => flash(__('Something went wrong while fetching projects'))); +} + +export function updateUserStatus({ emoji, message, availability }) { + const url = buildApiUrl(USER_POST_STATUS_PATH); + + return axios.put(url, { + emoji, + message, + availability, + }); +} diff --git a/app/assets/javascripts/boards/components/project_select_deprecated.vue b/app/assets/javascripts/boards/components/project_select_deprecated.vue index f14db42d43c..a043dc575ca 100644 --- a/app/assets/javascripts/boards/components/project_select_deprecated.vue +++ b/app/assets/javascripts/boards/components/project_select_deprecated.vue @@ -33,13 +33,13 @@ export default { GlDropdownText, GlSearchBoxByType, }, + inject: ['groupId'], props: { list: { type: Object, required: true, }, }, - inject: ['groupId'], data() { return { initialLoading: true, diff --git a/app/assets/javascripts/commons/nav/user_merge_requests.js b/app/assets/javascripts/commons/nav/user_merge_requests.js index eab2b5a31d7..84ab728274f 100644 --- a/app/assets/javascripts/commons/nav/user_merge_requests.js +++ b/app/assets/javascripts/commons/nav/user_merge_requests.js @@ -1,4 +1,4 @@ -import Api from '~/api'; +import { getUserCounts } from '~/rest_api'; let channel; @@ -30,7 +30,7 @@ function updateMergeRequestCounts(newCount) { * Refresh user counts (and broadcast if open) */ export function refreshUserMergeRequestCounts() { - return Api.userCounts() + return getUserCounts() .then(({ data }) => { const assignedMergeRequests = data.assigned_merge_requests; const reviewerMergeRequests = data.review_requested_merge_requests; diff --git a/app/assets/javascripts/frequent_items/store/actions.js b/app/assets/javascripts/frequent_items/store/actions.js index b16501aeb09..f4156487625 100644 --- a/app/assets/javascripts/frequent_items/store/actions.js +++ b/app/assets/javascripts/frequent_items/store/actions.js @@ -1,7 +1,7 @@ -import Api from '~/api'; import AccessorUtilities from '~/lib/utils/accessor'; import * as types from './mutation_types'; import { getTopFrequentItems } from '../utils'; +import { getGroups, getProjects } from '~/rest_api'; export const setNamespace = ({ commit }, namespace) => { commit(types.SET_NAMESPACE, namespace); @@ -54,11 +54,15 @@ export const fetchSearchedItems = ({ state, dispatch }, searchQuery) => { membership: Boolean(gon.current_user_id), }; + let searchFunction; if (state.namespace === 'projects') { + searchFunction = getProjects; params.order_by = 'last_activity_at'; + } else { + searchFunction = getGroups; } - return Api[state.namespace](searchQuery, params) + return searchFunction(searchQuery, params) .then((results) => { dispatch('receiveSearchedItemsSuccess', results); }) diff --git a/app/assets/javascripts/invite_members/components/members_token_select.vue b/app/assets/javascripts/invite_members/components/members_token_select.vue index b54812dfd96..627d4ab2771 100644 --- a/app/assets/javascripts/invite_members/components/members_token_select.vue +++ b/app/assets/javascripts/invite_members/components/members_token_select.vue @@ -3,7 +3,7 @@ import { debounce } from 'lodash'; import { GlTokenSelector, GlAvatar, GlAvatarLabeled, GlSprintf } from '@gitlab/ui'; import { __ } from '~/locale'; import { USER_SEARCH_DELAY } from '../constants'; -import Api from '~/api'; +import { getUsers } from '~/rest_api'; export default { components: { @@ -54,7 +54,7 @@ export default { this.retrieveUsers(query); }, retrieveUsers: debounce(function debouncedRetrieveUsers() { - return Api.users(this.query, this.$options.queryOptions) + return getUsers(this.query, this.$options.queryOptions) .then((response) => { this.users = response.data.map((token) => ({ id: token.id, diff --git a/app/assets/javascripts/lib/utils/users_cache.js b/app/assets/javascripts/lib/utils/users_cache.js index 9f980fd4899..54f69ef8e1b 100644 --- a/app/assets/javascripts/lib/utils/users_cache.js +++ b/app/assets/javascripts/lib/utils/users_cache.js @@ -1,4 +1,4 @@ -import Api from '../../api'; +import { getUsers, getUser, getUserStatus } from '~/rest_api'; import Cache from './cache'; class UsersCache extends Cache { @@ -7,7 +7,7 @@ class UsersCache extends Cache { return Promise.resolve(this.get(username)); } - return Api.users('', { username }).then(({ data }) => { + return getUsers('', { username }).then(({ data }) => { if (!data.length) { throw new Error(`User "${username}" could not be found!`); } @@ -28,7 +28,7 @@ class UsersCache extends Cache { return Promise.resolve(this.get(userId)); } - return Api.user(userId).then(({ data }) => { + return getUser(userId).then(({ data }) => { this.internalStorage[userId] = data; return data; }); @@ -40,7 +40,7 @@ class UsersCache extends Cache { return Promise.resolve(this.get(userId).status); } - return Api.userStatus(userId).then(({ data }) => { + return getUserStatus(userId).then(({ data }) => { if (!this.hasData(userId)) { this.internalStorage[userId] = {}; } diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js index 2480ab82304..0ab781c13d3 100644 --- a/app/assets/javascripts/notes/stores/actions.js +++ b/app/assets/javascripts/notes/stores/actions.js @@ -559,7 +559,7 @@ export const updateResolvableDiscussionsCounts = ({ commit }) => export const submitSuggestion = ( { commit, dispatch }, - { discussionId, noteId, suggestionId, flashContainer }, + { discussionId, suggestionId, flashContainer }, ) => { const dispatchResolveDiscussion = () => dispatch('resolveDiscussion', { discussionId }).catch(() => {}); @@ -568,7 +568,6 @@ export const submitSuggestion = ( dispatch('stopPolling'); return Api.applySuggestion(suggestionId) - .then(() => commit(types.APPLY_SUGGESTION, { discussionId, noteId, suggestionId })) .then(dispatchResolveDiscussion) .catch((err) => { const defaultMessage = __( @@ -590,11 +589,6 @@ export const submitSuggestion = ( export const submitSuggestionBatch = ({ commit, dispatch, state }, { flashContainer }) => { const suggestionIds = state.batchSuggestionsInfo.map(({ suggestionId }) => suggestionId); - const applyAllSuggestions = () => - state.batchSuggestionsInfo.map((suggestionInfo) => - commit(types.APPLY_SUGGESTION, suggestionInfo), - ); - const resolveAllDiscussions = () => state.batchSuggestionsInfo.map((suggestionInfo) => { const { discussionId } = suggestionInfo; @@ -606,7 +600,6 @@ export const submitSuggestionBatch = ({ commit, dispatch, state }, { flashContai dispatch('stopPolling'); return Api.applySuggestionBatch(suggestionIds) - .then(() => Promise.all(applyAllSuggestions())) .then(() => Promise.all(resolveAllDiscussions())) .then(() => commit(types.CLEAR_SUGGESTION_BATCH)) .catch((err) => { diff --git a/app/assets/javascripts/performance_bar/index.js b/app/assets/javascripts/performance_bar/index.js index 8ecf5971392..0d5c294ea56 100644 --- a/app/assets/javascripts/performance_bar/index.js +++ b/app/assets/javascripts/performance_bar/index.js @@ -11,6 +11,9 @@ import initPerformanceBarLog from './performance_bar_log'; Vue.use(Translate); const initPerformanceBar = (el) => { + if (!el) { + return undefined; + } const performanceBarData = el.dataset; return new Vue({ @@ -126,25 +129,7 @@ const initPerformanceBar = (el) => { }); }; -let loadedPeekBar = false; -function loadBar() { - const jsPeek = document.querySelector('#js-peek'); - if (!loadedPeekBar && jsPeek) { - loadedPeekBar = true; - initPerformanceBar(jsPeek); - } -} - -// If js-peek is not loaded when this script is executed, this call will do nothing -// If this is the case, then it will loadBar on DOMContentLoaded. We would prefer it -// to be initialized before the DOMContetLoaded event in order to pick up all the -// requests sent from the page. -loadBar(); - -document.addEventListener('DOMContentLoaded', () => { - loadBar(); -}); - +initPerformanceBar(document.querySelector('#js-peek')); initPerformanceBarLog(); export default initPerformanceBar; diff --git a/app/assets/javascripts/rest_api.js b/app/assets/javascripts/rest_api.js new file mode 100644 index 00000000000..ea8f87001f0 --- /dev/null +++ b/app/assets/javascripts/rest_api.js @@ -0,0 +1,15 @@ +export * from './api/groups_api'; +export * from './api/projects_api'; +export * from './api/user_api'; + +// Note: It's not possible to spy on methods imported from this file in +// Jest tests. See https://stackoverflow.com/a/53307822/1063392. +// As a workaround, in Jest tests, import the methods from the file +// in which they are defined: +// +// import * as UserApi from '~/api/user_api'; +// vs... +// import * as UserApi from '~/rest_api'; +// +// // This will only work with option #2 above. +// jest.spyOn(UserApi, 'getUsers') diff --git a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue index 30e0e552165..c8efbd73b48 100644 --- a/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue +++ b/app/assets/javascripts/set_status_modal/set_status_modal_wrapper.vue @@ -6,7 +6,7 @@ import GfmAutoComplete from 'ee_else_ce/gfm_auto_complete'; import { GlToast, GlModal, GlTooltipDirective, GlIcon, GlFormCheckbox } from '@gitlab/ui'; import { deprecatedCreateFlash as createFlash } from '~/flash'; import { __, s__ } from '~/locale'; -import Api from '~/api'; +import { updateUserStatus } from '~/rest_api'; import EmojiMenuInModal from './emoji_menu_in_modal'; import { isUserBusy, isValidAvailibility } from './utils'; import * as Emoji from '~/emoji'; @@ -163,7 +163,7 @@ export default { setStatus() { const { emoji, message, availability } = this; - Api.postUserStatus({ + updateUserStatus({ emoji, message, availability: availability ? AVAILABILITY_STATUS.BUSY : AVAILABILITY_STATUS.NOT_SET, diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index 4beaa2509d9..2653e1351ed 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -191,9 +191,13 @@ export default { mergeError = mergeError.slice(0, -1); } - return sprintf(s__('mrWidget|Merge failed: %{mergeError}. Please try again.'), { - mergeError, - }); + return sprintf( + s__('mrWidget|Merge failed: %{mergeError}. Please try again.'), + { + mergeError, + }, + false, + ); }, shouldShowAccessibilityReport() { return this.mr.accessibilityReportPath; -- cgit v1.2.3