diff options
Diffstat (limited to 'app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js')
-rw-r--r-- | app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js | 244 |
1 files changed, 196 insertions, 48 deletions
diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js index d444cc77aa7..2cde3781a6a 100644 --- a/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js +++ b/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js @@ -4,40 +4,83 @@ import axios from '~/lib/utils/axios_utils'; import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; import { s__ } from '~/locale'; import { STATUSES } from '../../constants'; +import bulkImportSourceGroupItemFragment from './fragments/bulk_import_source_group_item.fragment.graphql'; +import setImportProgressMutation from './mutations/set_import_progress.mutation.graphql'; +import updateImportStatusMutation from './mutations/update_import_status.mutation.graphql'; import availableNamespacesQuery from './queries/available_namespaces.query.graphql'; +import bulkImportSourceGroupQuery from './queries/bulk_import_source_group.query.graphql'; import { SourceGroupsManager } from './services/source_groups_manager'; import { StatusPoller } from './services/status_poller'; +import typeDefs from './typedefs.graphql'; export const clientTypenames = { BulkImportSourceGroupConnection: 'ClientBulkImportSourceGroupConnection', BulkImportSourceGroup: 'ClientBulkImportSourceGroup', AvailableNamespace: 'ClientAvailableNamespace', BulkImportPageInfo: 'ClientBulkImportPageInfo', + BulkImportTarget: 'ClientBulkImportTarget', + BulkImportProgress: 'ClientBulkImportProgress', + BulkImportValidationError: 'ClientBulkImportValidationError', }; -export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGroupsManager }) { - let statusPoller; +function makeGroup(data) { + const result = { + __typename: clientTypenames.BulkImportSourceGroup, + ...data, + }; + const NESTED_OBJECT_FIELDS = { + import_target: clientTypenames.BulkImportTarget, + progress: clientTypenames.BulkImportProgress, + }; - let sourceGroupManager; - const getGroupsManager = (client) => { - if (!sourceGroupManager) { - sourceGroupManager = new GroupsManager({ client, sourceUrl }); + Object.entries(NESTED_OBJECT_FIELDS).forEach(([field, type]) => { + if (!data[field]) { + return; } - return sourceGroupManager; - }; + result[field] = { + __typename: type, + ...data[field], + }; + }); + + return result; +} + +const localProgressId = (id) => `not-started-${id}`; + +export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGroupsManager }) { + const groupsManager = new GroupsManager({ + sourceUrl, + }); + + let statusPoller; return { Query: { + async bulkImportSourceGroup(_, { id }, { client, getCacheKey }) { + return client.readFragment({ + fragment: bulkImportSourceGroupItemFragment, + fragmentName: 'BulkImportSourceGroupItem', + id: getCacheKey({ + __typename: clientTypenames.BulkImportSourceGroup, + id, + }), + }); + }, + async bulkImportSourceGroups(_, vars, { client }) { if (!statusPoller) { statusPoller = new StatusPoller({ - groupManager: getGroupsManager(client), + updateImportStatus: ({ id, status_name: status }) => + client.mutate({ + mutation: updateImportStatusMutation, + variables: { id, status }, + }), pollPath: endpoints.jobs, }); statusPoller.startPolling(); } - const groupsManager = getGroupsManager(client); return Promise.all([ axios.get(endpoints.status, { params: { @@ -59,19 +102,21 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr return { __typename: clientTypenames.BulkImportSourceGroupConnection, nodes: data.importable_data.map((group) => { - const cachedImportState = groupsManager.getImportStateFromStorageByGroupId( - group.id, - ); + const { jobId, importState: cachedImportState } = + groupsManager.getImportStateFromStorageByGroupId(group.id) ?? {}; - return { - __typename: clientTypenames.BulkImportSourceGroup, + return makeGroup({ ...group, - status: cachedImportState?.status ?? STATUSES.NONE, + validation_errors: [], + progress: { + id: jobId ?? localProgressId(group.id), + status: cachedImportState?.status ?? STATUSES.NONE, + }, import_target: cachedImportState?.importTarget ?? { new_name: group.full_path, target_namespace: availableNamespaces[0]?.full_path ?? '', }, - }; + }); }), pageInfo: { __typename: clientTypenames.BulkImportPageInfo, @@ -91,46 +136,149 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr ), }, Mutation: { - setTargetNamespace(_, { targetNamespace, sourceGroupId }, { client }) { - getGroupsManager(client).updateById(sourceGroupId, (sourceGroup) => { - // eslint-disable-next-line no-param-reassign - sourceGroup.import_target.target_namespace = targetNamespace; + setTargetNamespace: (_, { targetNamespace, sourceGroupId }) => + makeGroup({ + id: sourceGroupId, + import_target: { + target_namespace: targetNamespace, + }, + }), + + setNewName: (_, { newName, sourceGroupId }) => + makeGroup({ + id: sourceGroupId, + import_target: { + new_name: newName, + }, + }), + + async setImportProgress(_, { sourceGroupId, status, jobId }) { + if (jobId) { + groupsManager.updateImportProgress(jobId, status); + } + + return makeGroup({ + id: sourceGroupId, + progress: { + id: jobId ?? localProgressId(sourceGroupId), + status, + }, }); }, - setNewName(_, { newName, sourceGroupId }, { client }) { - getGroupsManager(client).updateById(sourceGroupId, (sourceGroup) => { - // eslint-disable-next-line no-param-reassign - sourceGroup.import_target.new_name = newName; + async updateImportStatus(_, { id, status }) { + groupsManager.updateImportProgress(id, status); + + return { + __typename: clientTypenames.BulkImportProgress, + id, + status, + }; + }, + + async addValidationError(_, { sourceGroupId, field, message }, { client }) { + const { + data: { + bulkImportSourceGroup: { validation_errors: validationErrors, ...group }, + }, + } = await client.query({ + query: bulkImportSourceGroupQuery, + variables: { id: sourceGroupId }, }); + + return { + ...group, + validation_errors: [ + ...validationErrors.filter(({ field: f }) => f !== field), + { + __typename: clientTypenames.BulkImportValidationError, + field, + message, + }, + ], + }; }, - async importGroup(_, { sourceGroupId }, { client }) { - const groupManager = getGroupsManager(client); - const group = groupManager.findById(sourceGroupId); - groupManager.setImportStatus(group, STATUSES.SCHEDULING); - try { - const response = await axios.post(endpoints.createBulkImport, { - bulk_import: [ - { - source_type: 'group_entity', - source_full_path: group.full_path, - destination_namespace: group.import_target.target_namespace, - destination_name: group.import_target.new_name, - }, - ], - }); - groupManager.startImport({ group, importId: response.data.id }); - } catch (e) { - const message = e?.response?.data?.error ?? s__('BulkImport|Importing the group failed'); - createFlash({ message }); - groupManager.setImportStatus(group, STATUSES.NONE); - throw e; - } + async removeValidationError(_, { sourceGroupId, field }, { client }) { + const { + data: { + bulkImportSourceGroup: { validation_errors: validationErrors, ...group }, + }, + } = await client.query({ + query: bulkImportSourceGroupQuery, + variables: { id: sourceGroupId }, + }); + + return { + ...group, + validation_errors: validationErrors.filter(({ field: f }) => f !== field), + }; + }, + + async importGroups(_, { sourceGroupIds }, { client }) { + const groups = await Promise.all( + sourceGroupIds.map((id) => + client + .query({ + query: bulkImportSourceGroupQuery, + variables: { id }, + }) + .then(({ data }) => data.bulkImportSourceGroup), + ), + ); + + const GROUPS_BEING_SCHEDULED = sourceGroupIds.map((sourceGroupId) => + makeGroup({ + id: sourceGroupId, + progress: { + id: localProgressId(sourceGroupId), + status: STATUSES.SCHEDULING, + }, + }), + ); + + const defaultErrorMessage = s__('BulkImport|Importing the group failed'); + axios + .post(endpoints.createBulkImport, { + bulk_import: groups.map((group) => ({ + source_type: 'group_entity', + source_full_path: group.full_path, + destination_namespace: group.import_target.target_namespace, + destination_name: group.import_target.new_name, + })), + }) + .then(({ data: { id: jobId } }) => { + groupsManager.createImportState(jobId, { + status: STATUSES.CREATED, + groups, + }); + + return { status: STATUSES.CREATED, jobId }; + }) + .catch((e) => { + const message = e?.response?.data?.error ?? defaultErrorMessage; + createFlash({ message }); + return { status: STATUSES.NONE }; + }) + .then((newStatus) => + sourceGroupIds.forEach((sourceGroupId) => + client.mutate({ + mutation: setImportProgressMutation, + variables: { sourceGroupId, ...newStatus }, + }), + ), + ) + .catch(() => createFlash({ message: defaultErrorMessage })); + + return GROUPS_BEING_SCHEDULED; }, }, }; } export const createApolloClient = ({ sourceUrl, endpoints }) => - createDefaultClient(createResolvers({ sourceUrl, endpoints }), { assumeImmutableResults: true }); + createDefaultClient( + createResolvers({ sourceUrl, endpoints }), + { assumeImmutableResults: true }, + typeDefs, + ); |