summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js
diff options
context:
space:
mode:
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.js406
1 files changed, 100 insertions, 306 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 c08cf909a00..bce6e7bcb1f 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
@@ -1,23 +1,10 @@
-import createFlash from '~/flash';
import createDefaultClient from '~/lib/graphql';
import axios from '~/lib/utils/axios_utils';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
-import { s__ } from '~/locale';
import { STATUSES } from '../../constants';
-import { i18n, NEW_NAME_FIELD } from '../constants';
-import { isAvailableForImport } from '../utils';
import bulkImportSourceGroupItemFragment from './fragments/bulk_import_source_group_item.fragment.graphql';
import bulkImportSourceGroupProgressFragment from './fragments/bulk_import_source_group_progress.fragment.graphql';
-import addValidationErrorMutation from './mutations/add_validation_error.mutation.graphql';
-import removeValidationErrorMutation from './mutations/remove_validation_error.mutation.graphql';
-import setImportProgressMutation from './mutations/set_import_progress.mutation.graphql';
-import setImportTargetMutation from './mutations/set_import_target.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 groupAndProjectQuery from './queries/group_and_project.query.graphql';
-import { SourceGroupsManager } from './services/source_groups_manager';
-import { StatusPoller } from './services/status_poller';
+import { LocalStorageCache } from './services/local_storage_cache';
import typeDefs from './typedefs.graphql';
export const clientTypenames = {
@@ -27,221 +14,99 @@ export const clientTypenames = {
BulkImportPageInfo: 'ClientBulkImportPageInfo',
BulkImportTarget: 'ClientBulkImportTarget',
BulkImportProgress: 'ClientBulkImportProgress',
- BulkImportValidationError: 'ClientBulkImportValidationError',
};
-function makeGroup(data) {
- const result = {
- __typename: clientTypenames.BulkImportSourceGroup,
+function makeLastImportTarget(data) {
+ return {
+ __typename: clientTypenames.BulkImportTarget,
...data,
};
- const NESTED_OBJECT_FIELDS = {
- import_target: clientTypenames.BulkImportTarget,
- last_import_target: clientTypenames.BulkImportTarget,
- progress: clientTypenames.BulkImportProgress,
- };
-
- Object.entries(NESTED_OBJECT_FIELDS).forEach(([field, type]) => {
- if (!data[field]) {
- return;
- }
- result[field] = {
- __typename: type,
- ...data[field],
- };
- });
-
- return result;
}
-async function checkImportTargetIsValid({ client, newName, targetNamespace, sourceGroupId }) {
- const {
- data: { existingGroup, existingProject },
- } = await client.query({
- query: groupAndProjectQuery,
- fetchPolicy: 'no-cache',
- variables: {
- fullPath: `${targetNamespace}/${newName}`,
- },
- });
-
- const variables = {
- field: NEW_NAME_FIELD,
- sourceGroupId,
+function makeProgress(data) {
+ return {
+ __typename: clientTypenames.BulkImportProgress,
+ ...data,
};
-
- if (!existingGroup && !existingProject) {
- client.mutate({
- mutation: removeValidationErrorMutation,
- variables,
- });
- } else {
- client.mutate({
- mutation: addValidationErrorMutation,
- variables: {
- ...variables,
- message: i18n.NAME_ALREADY_EXISTS,
- },
- });
- }
}
-const localProgressId = (id) => `not-started-${id}`;
-const nextName = (name) => `${name}-1`;
+function makeGroup(data) {
+ return {
+ __typename: clientTypenames.BulkImportSourceGroup,
+ ...data,
+ progress: data.progress
+ ? makeProgress({
+ id: `LOCAL-PROGRESS-${data.id}`,
+ ...data.progress,
+ })
+ : null,
+ lastImportTarget: data.lastImportTarget
+ ? makeLastImportTarget({
+ id: data.id,
+ ...data.lastImportTarget,
+ })
+ : null,
+ };
+}
-export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGroupsManager }) {
- const groupsManager = new GroupsManager({
- sourceUrl,
+function getGroupFromCache({ client, id, getCacheKey }) {
+ return client.readFragment({
+ fragment: bulkImportSourceGroupItemFragment,
+ fragmentName: 'BulkImportSourceGroupItem',
+ id: getCacheKey({
+ __typename: clientTypenames.BulkImportSourceGroup,
+ id,
+ }),
});
+}
- let statusPoller;
+export function createResolvers({ endpoints }) {
+ const localStorageCache = new LocalStorageCache();
return {
Query: {
- async bulkImportSourceGroup(_, { id }, { client, getCacheKey }) {
- return client.readFragment({
- fragment: bulkImportSourceGroupItemFragment,
- fragmentName: 'BulkImportSourceGroupItem',
- id: getCacheKey({
- __typename: clientTypenames.BulkImportSourceGroup,
- id,
- }),
+ async bulkImportSourceGroups(_, vars) {
+ const { headers, data } = await axios.get(endpoints.status, {
+ params: {
+ page: vars.page,
+ per_page: vars.perPage,
+ filter: vars.filter,
+ },
});
- },
- async bulkImportSourceGroups(_, vars, { client }) {
- if (!statusPoller) {
- statusPoller = new StatusPoller({
- updateImportStatus: ({ id, status_name: status }) =>
- client.mutate({
- mutation: updateImportStatusMutation,
- variables: { id, status },
- }),
- pollPath: endpoints.jobs,
- });
- statusPoller.startPolling();
- }
-
- return Promise.all([
- axios.get(endpoints.status, {
- params: {
- page: vars.page,
- per_page: vars.perPage,
- filter: vars.filter,
- },
- }),
- client.query({ query: availableNamespacesQuery }),
- ]).then(
- ([
- { headers, data },
- {
- data: { availableNamespaces },
- },
- ]) => {
- const pagination = parseIntPagination(normalizeHeaders(headers));
-
- const response = {
- __typename: clientTypenames.BulkImportSourceGroupConnection,
- nodes: data.importable_data.map((group) => {
- const { jobId, importState: cachedImportState } =
- groupsManager.getImportStateFromStorageByGroupId(group.id) ?? {};
-
- const status = cachedImportState?.status ?? STATUSES.NONE;
-
- const importTarget =
- status === STATUSES.FINISHED && cachedImportState.importTarget
- ? {
- target_namespace: cachedImportState.importTarget.target_namespace,
- new_name: nextName(cachedImportState.importTarget.new_name),
- }
- : cachedImportState?.importTarget ?? {
- new_name: group.full_path,
- target_namespace: availableNamespaces[0]?.full_path ?? '',
- };
-
- return makeGroup({
- ...group,
- validation_errors: [],
- progress: {
- id: jobId ?? localProgressId(group.id),
- status,
- },
- import_target: importTarget,
- last_import_target: cachedImportState?.importTarget ?? null,
- });
- }),
- pageInfo: {
- __typename: clientTypenames.BulkImportPageInfo,
- ...pagination,
- },
- };
-
- setTimeout(() => {
- response.nodes.forEach((group) => {
- if (isAvailableForImport(group)) {
- checkImportTargetIsValid({
- client,
- newName: group.import_target.new_name,
- targetNamespace: group.import_target.target_namespace,
- sourceGroupId: group.id,
- });
- }
- });
+ const pagination = parseIntPagination(normalizeHeaders(headers));
+
+ const response = {
+ __typename: clientTypenames.BulkImportSourceGroupConnection,
+ nodes: data.importable_data.map((group) => {
+ return makeGroup({
+ id: group.id,
+ webUrl: group.web_url,
+ fullPath: group.full_path,
+ fullName: group.full_name,
+ ...group,
+ ...localStorageCache.get(group.web_url),
});
-
- return response;
+ }),
+ pageInfo: {
+ __typename: clientTypenames.BulkImportPageInfo,
+ ...pagination,
},
- );
+ };
+ return response;
},
availableNamespaces: () =>
axios.get(endpoints.availableNamespaces).then(({ data }) =>
data.map((namespace) => ({
__typename: clientTypenames.AvailableNamespace,
- ...namespace,
+ id: namespace.id,
+ fullPath: namespace.full_path,
})),
),
},
Mutation: {
- setImportTarget(_, { targetNamespace, newName, sourceGroupId }, { client }) {
- checkImportTargetIsValid({
- client,
- sourceGroupId,
- targetNamespace,
- newName,
- });
-
- return makeGroup({
- id: sourceGroupId,
- import_target: {
- target_namespace: targetNamespace,
- new_name: newName,
- id: sourceGroupId,
- },
- });
- },
-
- async setImportProgress(_, { sourceGroupId, status, jobId, importTarget }) {
- if (jobId) {
- groupsManager.updateImportProgress(jobId, status);
- }
-
- return makeGroup({
- id: sourceGroupId,
- progress: {
- id: jobId ?? localProgressId(sourceGroupId),
- status,
- },
- last_import_target: {
- __typename: clientTypenames.BulkImportTarget,
- ...importTarget,
- },
- });
- },
-
async updateImportStatus(_, { id, status: newStatus }, { client, getCacheKey }) {
- groupsManager.updateImportProgress(id, newStatus);
-
const progressItem = client.readFragment({
fragment: bulkImportSourceGroupProgressFragment,
fragmentName: 'BulkImportSourceGroupProgress',
@@ -251,133 +116,62 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
}),
});
- const isInProgress = Boolean(progressItem);
- const { status: currentStatus } = progressItem ?? {};
- if (newStatus === STATUSES.FINISHED && isInProgress && currentStatus !== newStatus) {
- const groups = groupsManager.getImportedGroupsByJobId(id);
+ if (!progressItem) return null;
- groups.forEach(async ({ id: groupId, importTarget }) => {
- client.mutate({
- mutation: setImportTargetMutation,
- variables: {
- sourceGroupId: groupId,
- targetNamespace: importTarget.target_namespace,
- newName: nextName(importTarget.new_name),
- },
- });
- });
- }
+ localStorageCache.updateStatusByJobId(id, newStatus);
return {
__typename: clientTypenames.BulkImportProgress,
+ ...progressItem,
id,
status: newStatus,
};
},
- async addValidationError(_, { sourceGroupId, field, message }, { client }) {
- const {
- data: {
- bulkImportSourceGroup: { validation_errors: validationErrors, ...group },
- },
- } = await client.query({
- query: bulkImportSourceGroupQuery,
- variables: { id: sourceGroupId },
- });
+ async importGroups(_, { importRequests }, { client, getCacheKey }) {
+ const importOperations = importRequests.map((importRequest) => {
+ const group = getGroupFromCache({
+ client,
+ getCacheKey,
+ id: importRequest.sourceGroupId,
+ });
- return {
- ...group,
- validation_errors: [
- ...validationErrors.filter(({ field: f }) => f !== field),
- {
- __typename: clientTypenames.BulkImportValidationError,
- field,
- message,
- },
- ],
- };
- },
+ return {
+ group,
+ ...importRequest,
+ };
+ });
- async removeValidationError(_, { sourceGroupId, field }, { client }) {
const {
- data: {
- bulkImportSourceGroup: { validation_errors: validationErrors, ...group },
- },
- } = await client.query({
- query: bulkImportSourceGroupQuery,
- variables: { id: sourceGroupId },
+ data: { id: jobId },
+ } = await axios.post(endpoints.createBulkImport, {
+ bulk_import: importOperations.map((op) => ({
+ source_type: 'group_entity',
+ source_full_path: op.group.fullPath,
+ destination_namespace: op.targetNamespace,
+ destination_name: op.newName,
+ })),
});
- 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),
- ),
- );
+ return importOperations.map((op) => {
+ const lastImportTarget = {
+ targetNamespace: op.targetNamespace,
+ newName: op.newName,
+ };
- 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,
- });
+ const progress = {
+ id: jobId,
+ status: STATUSES.CREATED,
+ };
- 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, idx) =>
- client.mutate({
- mutation: setImportProgressMutation,
- variables: { sourceGroupId, ...newStatus, importTarget: groups[idx].import_target },
- }),
- ),
- )
- .catch(() => createFlash({ message: defaultErrorMessage }));
+ localStorageCache.set(op.group.webUrl, { progress, lastImportTarget });
- return GROUPS_BEING_SCHEDULED;
+ return makeGroup({ ...op.group, progress, lastImportTarget });
+ });
},
},
};
}
export const createApolloClient = ({ sourceUrl, endpoints }) =>
- createDefaultClient(
- createResolvers({ sourceUrl, endpoints }),
- { assumeImmutableResults: true },
- typeDefs,
- );
+ createDefaultClient(createResolvers({ sourceUrl, endpoints }), { typeDefs });