summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/import_entities/import_projects/store/actions.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/import_entities/import_projects/store/actions.js')
-rw-r--r--app/assets/javascripts/import_entities/import_projects/store/actions.js201
1 files changed, 201 insertions, 0 deletions
diff --git a/app/assets/javascripts/import_entities/import_projects/store/actions.js b/app/assets/javascripts/import_entities/import_projects/store/actions.js
new file mode 100644
index 00000000000..7b7afd13c55
--- /dev/null
+++ b/app/assets/javascripts/import_entities/import_projects/store/actions.js
@@ -0,0 +1,201 @@
+import Visibility from 'visibilityjs';
+import * as types from './mutation_types';
+import { isProjectImportable } from '../utils';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
+import Poll from '~/lib/utils/poll';
+import { visitUrl, objectToQuery } from '~/lib/utils/url_utility';
+import { deprecatedCreateFlash as createFlash } from '~/flash';
+import { s__, sprintf } from '~/locale';
+import axios from '~/lib/utils/axios_utils';
+import httpStatusCodes from '~/lib/utils/http_status';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+
+let eTagPoll;
+
+const hasRedirectInError = e => e?.response?.data?.error?.redirect;
+const redirectToUrlInError = e => visitUrl(e.response.data.error.redirect);
+const tooManyRequests = e => e.response.status === httpStatusCodes.TOO_MANY_REQUESTS;
+const pathWithParams = ({ path, ...params }) => {
+ const filteredParams = Object.fromEntries(
+ Object.entries(params).filter(([, value]) => value !== ''),
+ );
+ const queryString = objectToQuery(filteredParams);
+ return queryString ? `${path}?${queryString}` : path;
+};
+
+const isRequired = () => {
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ throw new Error('param is required');
+};
+
+const clearJobsEtagPoll = () => {
+ eTagPoll = null;
+};
+
+const stopJobsPolling = () => {
+ if (eTagPoll) eTagPoll.stop();
+};
+
+const restartJobsPolling = () => {
+ if (eTagPoll) eTagPoll.restart();
+};
+
+const setImportTarget = ({ commit }, { repoId, importTarget }) =>
+ commit(types.SET_IMPORT_TARGET, { repoId, importTarget });
+
+const importAll = ({ state, dispatch }) => {
+ return Promise.all(
+ state.repositories
+ .filter(isProjectImportable)
+ .map(r => dispatch('fetchImport', r.importSource.id)),
+ );
+};
+
+const fetchReposFactory = ({ reposPath = isRequired() }) => ({ state, commit }) => {
+ const nextPage = state.pageInfo.page + 1;
+ commit(types.SET_PAGE, nextPage);
+ commit(types.REQUEST_REPOS);
+
+ const { provider, filter } = state;
+
+ return axios
+ .get(
+ pathWithParams({
+ path: reposPath,
+ filter: filter ?? '',
+ page: nextPage === 1 ? '' : nextPage.toString(),
+ }),
+ )
+ .then(({ data }) => {
+ commit(types.RECEIVE_REPOS_SUCCESS, convertObjectPropsToCamelCase(data, { deep: true }));
+ })
+ .catch(e => {
+ commit(types.SET_PAGE, nextPage - 1);
+
+ if (hasRedirectInError(e)) {
+ redirectToUrlInError(e);
+ } else if (tooManyRequests(e)) {
+ createFlash(
+ sprintf(s__('ImportProjects|%{provider} rate limit exceeded. Try again later'), {
+ provider: capitalizeFirstCharacter(provider),
+ }),
+ );
+
+ commit(types.RECEIVE_REPOS_ERROR);
+ } else {
+ createFlash(
+ sprintf(s__('ImportProjects|Requesting your %{provider} repositories failed'), {
+ provider,
+ }),
+ );
+
+ commit(types.RECEIVE_REPOS_ERROR);
+ }
+ });
+};
+
+const fetchImportFactory = (importPath = isRequired()) => ({ state, commit, getters }, repoId) => {
+ const { ciCdOnly } = state;
+ const importTarget = getters.getImportTarget(repoId);
+
+ commit(types.REQUEST_IMPORT, { repoId, importTarget });
+
+ const { newName, targetNamespace } = importTarget;
+ return axios
+ .post(importPath, {
+ repo_id: repoId,
+ ci_cd_only: ciCdOnly,
+ new_name: newName,
+ target_namespace: targetNamespace,
+ })
+ .then(({ data }) => {
+ commit(types.RECEIVE_IMPORT_SUCCESS, {
+ importedProject: convertObjectPropsToCamelCase(data, { deep: true }),
+ repoId,
+ });
+ })
+ .catch(e => {
+ const serverErrorMessage = e?.response?.data?.errors;
+ const flashMessage = serverErrorMessage
+ ? sprintf(
+ s__('ImportProjects|Importing the project failed: %{reason}'),
+ {
+ reason: serverErrorMessage,
+ },
+ false,
+ )
+ : s__('ImportProjects|Importing the project failed');
+
+ createFlash(flashMessage);
+
+ commit(types.RECEIVE_IMPORT_ERROR, repoId);
+ });
+};
+
+export const fetchJobsFactory = (jobsPath = isRequired()) => ({ state, commit, dispatch }) => {
+ if (eTagPoll) {
+ stopJobsPolling();
+ clearJobsEtagPoll();
+ }
+
+ eTagPoll = new Poll({
+ resource: {
+ fetchJobs: () => axios.get(pathWithParams({ path: jobsPath, filter: state.filter })),
+ },
+ method: 'fetchJobs',
+ successCallback: ({ data }) =>
+ commit(types.RECEIVE_JOBS_SUCCESS, convertObjectPropsToCamelCase(data, { deep: true })),
+ errorCallback: e => {
+ if (hasRedirectInError(e)) {
+ redirectToUrlInError(e);
+ } else {
+ createFlash(s__('ImportProjects|Update of imported projects with realtime changes failed'));
+ }
+ },
+ });
+
+ if (!Visibility.hidden()) {
+ eTagPoll.makeRequest();
+ }
+
+ Visibility.change(() => {
+ if (!Visibility.hidden()) {
+ dispatch('restartJobsPolling');
+ } else {
+ dispatch('stopJobsPolling');
+ }
+ });
+};
+
+const fetchNamespacesFactory = (namespacesPath = isRequired()) => ({ commit }) => {
+ commit(types.REQUEST_NAMESPACES);
+ axios
+ .get(namespacesPath)
+ .then(({ data }) =>
+ commit(types.RECEIVE_NAMESPACES_SUCCESS, convertObjectPropsToCamelCase(data, { deep: true })),
+ )
+ .catch(() => {
+ createFlash(s__('ImportProjects|Requesting namespaces failed'));
+
+ commit(types.RECEIVE_NAMESPACES_ERROR);
+ });
+};
+
+const setFilter = ({ commit, dispatch }, filter) => {
+ commit(types.SET_FILTER, filter);
+
+ return dispatch('fetchRepos');
+};
+
+export default ({ endpoints = isRequired() }) => ({
+ clearJobsEtagPoll,
+ stopJobsPolling,
+ restartJobsPolling,
+ setFilter,
+ setImportTarget,
+ importAll,
+ fetchRepos: fetchReposFactory({ reposPath: endpoints.reposPath }),
+ fetchImport: fetchImportFactory(endpoints.importPath),
+ fetchJobs: fetchJobsFactory(endpoints.jobsPath),
+ fetchNamespaces: fetchNamespacesFactory(endpoints.namespacesPath),
+});