From 054afda323ace57bb33504dd1c7ed8d492160f23 Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Thu, 12 Aug 2021 14:50:09 +0300 Subject: [PATCH 01/10] Introduce last_import_target field for bulk imports * Save last target of import to this field --- .../import_groups/graphql/typedefs.graphql | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql b/app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql index c830aaa75e695b..6ef4bbafec09d0 100644 --- a/app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql +++ b/app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql @@ -30,6 +30,7 @@ type ClientBulkImportSourceGroup { full_name: String! progress: ClientBulkImportProgress! import_target: ClientBulkImportTarget! + last_import_target: ClientBulkImportTarget validation_errors: [ClientBulkImportValidationError!]! } @@ -50,11 +51,21 @@ extend type Query { availableNamespaces: [ClientBulkImportAvailableNamespace!]! } +input InputTargetInput { + target_namespace: String! + new_name: String! +} + extend type Mutation { setNewName(newName: String, sourceGroupId: ID!): ClientBulkImportSourceGroup! setTargetNamespace(targetNamespace: String, sourceGroupId: ID!): ClientBulkImportSourceGroup! importGroups(sourceGroupIds: [ID!]!): [ClientBulkImportSourceGroup!]! - setImportProgress(id: ID, status: String!): ClientBulkImportSourceGroup! + setImportProgress( + id: ID + status: String! + jobId: String + importTarget: ImportTargetInput! + ): ClientBulkImportSourceGroup! updateImportProgress(id: ID, status: String!): ClientBulkImportProgress addValidationError( sourceGroupId: ID! -- GitLab From c44040bbfe8e17c41dd0cc048a48114386834007 Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Thu, 12 Aug 2021 14:51:17 +0300 Subject: [PATCH 02/10] Fix source groups manager for bulk imports * remove prefixing of state with url since ids are global for entire instance * reverse saved state when searching since now we might have multiple imports matching same group * introduce ability to get affected groups for specific job id --- .../graphql/services/source_groups_manager.js | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js b/app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js index 97dbdbf518a1c4..fbc6de1ba6b794 100644 --- a/app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js +++ b/app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js @@ -35,15 +35,21 @@ export class SourceGroupsManager { } createImportState(importId, jobConfig) { - this.importStates[this.getStorageKey(importId)] = { + this.importStates[importId] = { status: jobConfig.status, - groups: jobConfig.groups.map((g) => ({ importTarget: g.import_target, id: g.id })), + groups: jobConfig.groups.map((g) => ({ + importTarget: { + target_namespace: g.import_target.target_namespace, + new_name: g.import_target.new_name, + }, + id: g.id, + })), }; this.saveImportStatesToStorage(); } updateImportProgress(importId, status) { - const currentState = this.importStates[this.getStorageKey(importId)]; + const currentState = this.importStates[importId]; if (!currentState) { return; } @@ -52,12 +58,15 @@ export class SourceGroupsManager { this.saveImportStatesToStorage(); } + getImportedGroupsByJobId(jobId) { + return this.importStates[jobId]?.groups ?? []; + } + getImportStateFromStorageByGroupId(groupId) { - const PREFIX = this.getStorageKey(''); const [jobId, importState] = - Object.entries(this.importStates).find( - ([key, state]) => key.startsWith(PREFIX) && state.groups.some((g) => g.id === groupId), - ) ?? []; + Object.entries(this.importStates) + .reverse() + .find(([, state]) => state.groups.some((g) => g.id === groupId)) ?? []; if (!jobId) { return null; @@ -67,10 +76,6 @@ export class SourceGroupsManager { return { jobId, importState: { ...group, status: importState.status } }; } - getStorageKey(importId) { - return `${this.sourceUrl}|${importId}`; - } - saveImportStatesToStorage = debounce(() => { try { // storage might be changed in other tab so fetch first -- GitLab From 03274a7e9a4d2b7e37ed49ac0eecdf560ab73f60 Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Thu, 12 Aug 2021 14:53:29 +0300 Subject: [PATCH 03/10] Consume last_import_target in queries * query last_import_target on source group fragment * query last_import_target on set_import_progress mutation --- ...k_import_source_group_item.fragment.graphql | 4 ++++ .../set_import_progress.mutation.graphql | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/fragments/bulk_import_source_group_item.fragment.graphql b/app/assets/javascripts/import_entities/import_groups/graphql/fragments/bulk_import_source_group_item.fragment.graphql index 47675cd1bd0559..089340b3c48d2c 100644 --- a/app/assets/javascripts/import_entities/import_groups/graphql/fragments/bulk_import_source_group_item.fragment.graphql +++ b/app/assets/javascripts/import_entities/import_groups/graphql/fragments/bulk_import_source_group_item.fragment.graphql @@ -12,6 +12,10 @@ fragment BulkImportSourceGroupItem on ClientBulkImportSourceGroup { target_namespace new_name } + last_import_target { + target_namespace + new_name + } validation_errors { field message diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/mutations/set_import_progress.mutation.graphql b/app/assets/javascripts/import_entities/import_groups/graphql/mutations/set_import_progress.mutation.graphql index 2ec1269932a14e..43301554de3aaf 100644 --- a/app/assets/javascripts/import_entities/import_groups/graphql/mutations/set_import_progress.mutation.graphql +++ b/app/assets/javascripts/import_entities/import_groups/graphql/mutations/set_import_progress.mutation.graphql @@ -1,9 +1,23 @@ -mutation setImportProgress($status: String!, $sourceGroupId: String!, $jobId: String) { - setImportProgress(status: $status, sourceGroupId: $sourceGroupId, jobId: $jobId) @client { +mutation setImportProgress( + $status: String! + $sourceGroupId: String! + $jobId: String + $importTarget: ImportTargetInput! +) { + setImportProgress( + status: $status + sourceGroupId: $sourceGroupId + jobId: $jobId + importTarget: $importTarget + ) @client { id progress { id status } + last_import_target { + target_namespace + new_name + } } } -- GitLab From c551577860a4b9d0af7e8136c08c87d1d9af333b Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Thu, 12 Aug 2021 14:54:31 +0300 Subject: [PATCH 04/10] Move reusable utils to helper file These are reused in multiple places --- .../javascripts/import_entities/import_groups/utils.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/assets/javascripts/import_entities/import_groups/utils.js b/app/assets/javascripts/import_entities/import_groups/utils.js index b451008b6f9331..a1baeaf39dd9ab 100644 --- a/app/assets/javascripts/import_entities/import_groups/utils.js +++ b/app/assets/javascripts/import_entities/import_groups/utils.js @@ -1,3 +1,4 @@ +import { STATUSES } from '../constants'; import { NEW_NAME_FIELD } from './constants'; export function isNameValid(group, validationRegex) { @@ -11,3 +12,11 @@ export function getInvalidNameValidationMessage(group) { export function isInvalid(group, validationRegex) { return Boolean(!isNameValid(group, validationRegex) || getInvalidNameValidationMessage(group)); } + +export function isFinished(group) { + return group.progress.status === STATUSES.FINISHED; +} + +export function isAvailableForImport(group) { + return [STATUSES.NONE, STATUSES.FINISHED].some((status) => group.progress.status === status); +} -- GitLab From 1ec2e8bb9301978e97804bb6228759ed6e3d7b22 Mon Sep 17 00:00:00 2001 From: Illya Klymov Date: Thu, 12 Aug 2021 14:56:35 +0300 Subject: [PATCH 05/10] Update import_target cell for re-import * always render dropdown ui * complete state behavior should be equal to not started behavior - replace all isAlreadyImported checks with isAvailableForImport and negate them --- .../components/import_target_cell.vue | 57 ++++++------------- .../components/import_target_cell_spec.js | 29 +--------- 2 files changed, 19 insertions(+), 67 deletions(-) diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue b/app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue index 7359d4f239e7e5..daced740c94edf 100644 --- a/app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue +++ b/app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue @@ -3,14 +3,16 @@ import { GlDropdownDivider, GlDropdownItem, GlDropdownSectionHeader, - GlLink, GlFormInput, } from '@gitlab/ui'; -import { joinPaths } from '~/lib/utils/url_utility'; import { s__ } from '~/locale'; import ImportGroupDropdown from '../../components/group_dropdown.vue'; -import { STATUSES } from '../../constants'; -import { isInvalid, getInvalidNameValidationMessage, isNameValid } from '../utils'; +import { + isInvalid, + getInvalidNameValidationMessage, + isNameValid, + isAvailableForImport, +} from '../utils'; export default { components: { @@ -18,7 +20,6 @@ export default { GlDropdownDivider, GlDropdownItem, GlDropdownSectionHeader, - GlLink, GlFormInput, }, props: { @@ -61,20 +62,8 @@ export default { return isNameValid(this.group, this.groupPathRegex); }, - isAlreadyImported() { - return this.group.progress.status !== STATUSES.NONE; - }, - - isFinished() { - return this.group.progress.status === STATUSES.FINISHED; - }, - - fullPath() { - return `${this.importTarget.target_namespace}/${this.importTarget.new_name}`; - }, - - absolutePath() { - return joinPaths(gon.relative_url_root || '/', this.fullPath); + isAvailableForImport() { + return isAvailableForImport(this.group); }, }, @@ -85,25 +74,11 @@ export default { @@ -360,18 +360,12 @@ export default { -