Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-09-13 09:11:29 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-09-13 09:11:29 +0300
commite4372ce2ee58813303e4ac906800fbfdd0d5bcf5 (patch)
treebdd15d7b1e97e8eff4aead62bab05d46b34ce061 /app/assets/javascripts/import_entities
parent395db070c9315441912258bfcbc2fac973f47e36 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/import_entities')
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue69
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_source_cell.vue53
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table.vue76
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue57
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js89
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/fragments/bulk_import_source_group_item.fragment.graphql4
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/mutations/set_import_progress.mutation.graphql18
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js24
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql13
-rw-r--r--app/assets/javascripts/import_entities/import_groups/utils.js9
10 files changed, 293 insertions, 119 deletions
diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue b/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue
new file mode 100644
index 00000000000..104c84173fc
--- /dev/null
+++ b/app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue
@@ -0,0 +1,69 @@
+<script>
+import { GlButton, GlIcon, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
+import { joinPaths } from '~/lib/utils/url_utility';
+import { isFinished, isInvalid, isAvailableForImport } from '../utils';
+
+export default {
+ components: {
+ GlIcon,
+ GlButton,
+ },
+ directives: {
+ GlTooltip,
+ },
+ props: {
+ group: {
+ type: Object,
+ required: true,
+ },
+ groupPathRegex: {
+ type: RegExp,
+ required: true,
+ },
+ },
+ computed: {
+ fullLastImportPath() {
+ return this.group.last_import_target
+ ? `${this.group.last_import_target.target_namespace}/${this.group.last_import_target.new_name}`
+ : null;
+ },
+ absoluteLastImportPath() {
+ return joinPaths(gon.relative_url_root || '/', this.fullLastImportPath);
+ },
+ isAvailableForImport() {
+ return isAvailableForImport(this.group);
+ },
+ isFinished() {
+ return isFinished(this.group);
+ },
+ isInvalid() {
+ return isInvalid(this.group, this.groupPathRegex);
+ },
+ },
+};
+</script>
+
+<template>
+ <span class="gl-white-space-nowrap gl-inline-flex gl-align-items-center">
+ <gl-button
+ v-if="isAvailableForImport"
+ :disabled="isInvalid"
+ variant="confirm"
+ category="secondary"
+ data-qa-selector="import_group_button"
+ @click="$emit('import-group')"
+ >
+ {{ isFinished ? __('Re-import') : __('Import') }}
+ </gl-button>
+ <gl-icon
+ v-if="isFinished"
+ v-gl-tooltip
+ :size="16"
+ name="information-o"
+ :title="
+ s__('BulkImports|Re-import creates a new group. It does not sync with the existing group.')
+ "
+ class="gl-ml-3"
+ />
+ </span>
+</template>
diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_source_cell.vue b/app/assets/javascripts/import_entities/import_groups/components/import_source_cell.vue
new file mode 100644
index 00000000000..2de9bd4f868
--- /dev/null
+++ b/app/assets/javascripts/import_entities/import_groups/components/import_source_cell.vue
@@ -0,0 +1,53 @@
+<script>
+import { GlLink, GlSprintf, GlIcon } from '@gitlab/ui';
+import { joinPaths } from '~/lib/utils/url_utility';
+import { isFinished } from '../utils';
+
+export default {
+ components: {
+ GlLink,
+ GlSprintf,
+ GlIcon,
+ },
+ props: {
+ group: {
+ type: Object,
+ required: true,
+ },
+ },
+ computed: {
+ fullLastImportPath() {
+ return this.group.last_import_target
+ ? `${this.group.last_import_target.target_namespace}/${this.group.last_import_target.new_name}`
+ : null;
+ },
+ absoluteLastImportPath() {
+ return joinPaths(gon.relative_url_root || '/', this.fullLastImportPath);
+ },
+ isFinished() {
+ return isFinished(this.group);
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <gl-link
+ :href="group.web_url"
+ target="_blank"
+ class="gl-display-inline-flex gl-align-items-center gl-h-7"
+ >
+ {{ group.full_path }} <gl-icon name="external-link" />
+ </gl-link>
+ <div v-if="isFinished && fullLastImportPath" class="gl-font-sm">
+ <gl-sprintf :message="s__('BulkImport|Last imported to %{link}')">
+ <template #link>
+ <gl-link :href="absoluteLastImportPath" class="gl-font-sm" target="_blank">{{
+ fullLastImportPath
+ }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
index db44be2bcd7..04b037ecc2b 100644
--- a/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
+++ b/app/assets/javascripts/import_entities/import_groups/components/import_table.vue
@@ -9,19 +9,19 @@ import {
GlLoadingIcon,
GlSearchBoxByClick,
GlSprintf,
- GlSafeHtmlDirective as SafeHtml,
GlTable,
GlFormCheckbox,
} from '@gitlab/ui';
import { s__, __, n__ } from '~/locale';
import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
-import ImportStatus from '../../components/import_status.vue';
-import { STATUSES } from '../../constants';
+import ImportStatusCell from '../../components/import_status.vue';
import importGroupsMutation from '../graphql/mutations/import_groups.mutation.graphql';
import setImportTargetMutation from '../graphql/mutations/set_import_target.mutation.graphql';
import availableNamespacesQuery from '../graphql/queries/available_namespaces.query.graphql';
import bulkImportSourceGroupsQuery from '../graphql/queries/bulk_import_source_groups.query.graphql';
-import { isInvalid } from '../utils';
+import { isInvalid, isFinished, isAvailableForImport } from '../utils';
+import ImportActionsCell from './import_actions_cell.vue';
+import ImportSourceCell from './import_source_cell.vue';
import ImportTargetCell from './import_target_cell.vue';
const PAGE_SIZES = [20, 50, 100];
@@ -43,13 +43,12 @@ export default {
GlFormCheckbox,
GlSprintf,
GlTable,
- ImportStatus,
+ ImportSourceCell,
ImportTargetCell,
+ ImportStatusCell,
+ ImportActionsCell,
PaginationLinks,
},
- directives: {
- SafeHtml,
- },
props: {
sourceUrl: {
@@ -136,7 +135,7 @@ export default {
},
availableGroupsForImport() {
- return this.groups.filter((g) => g.progress.status === STATUSES.NONE && !this.isInvalid(g));
+ return this.groups.filter((g) => isAvailableForImport(g) && !this.isInvalid(g));
},
humanizedTotal() {
@@ -190,6 +189,24 @@ export default {
},
methods: {
+ isUnselectable(group) {
+ return !this.isAvailableForImport(group) || this.isInvalid(group);
+ },
+
+ rowClasses(group) {
+ const DEFAULT_CLASSES = [
+ 'gl-border-gray-200',
+ 'gl-border-0',
+ 'gl-border-b-1',
+ 'gl-border-solid',
+ ];
+ const result = [...DEFAULT_CLASSES];
+ if (this.isUnselectable(group)) {
+ result.push('gl-cursor-default!');
+ }
+ return result;
+ },
+
qaRowAttributes(group, type) {
if (type === 'row') {
return {
@@ -201,10 +218,8 @@ export default {
return {};
},
- isAlreadyImported(group) {
- return group.progress.status !== STATUSES.NONE;
- },
-
+ isAvailableForImport,
+ isFinished,
isInvalid(group) {
return isInvalid(group, this.groupPathRegex);
},
@@ -253,7 +268,7 @@ export default {
const table = this.getTableRef();
this.groups.forEach((group, idx) => {
- if (table.isRowSelected(idx) && (this.isAlreadyImported(group) || this.isInvalid(group))) {
+ if (table.isRowSelected(idx) && this.isUnselectable(group)) {
table.unselectRow(idx);
}
});
@@ -291,7 +306,7 @@ export default {
<strong>{{ filter }}</strong>
</template>
<template #link>
- <gl-link class="gl-display-inline-block" :href="sourceUrl" target="_blank">
+ <gl-link :href="sourceUrl" target="_blank">
{{ sourceUrl }} <gl-icon name="external-link" class="vertical-align-middle" />
</gl-link>
</template>
@@ -338,7 +353,7 @@ export default {
ref="table"
class="gl-w-full"
data-qa-selector="import_table"
- tbody-tr-class="gl-border-gray-200 gl-border-0 gl-border-b-1 gl-border-solid"
+ :tbody-tr-class="rowClasses"
:tbody-tr-attr="qaRowAttributes"
:items="groups"
:fields="$options.fields"
@@ -360,18 +375,12 @@ export default {
<gl-form-checkbox
class="gl-h-7 gl-pt-3"
:checked="rowSelected"
- :disabled="isAlreadyImported(group) || isInvalid(group)"
+ :disabled="!isAvailableForImport(group) || isInvalid(group)"
@change="rowSelected ? unselectRow() : selectRow()"
/>
</template>
- <template #cell(web_url)="{ value: web_url, item: { full_path } }">
- <gl-link
- :href="web_url"
- target="_blank"
- class="gl-display-inline-flex gl-align-items-center gl-h-7"
- >
- {{ full_path }} <gl-icon name="external-link" />
- </gl-link>
+ <template #cell(web_url)="{ item: group }">
+ <import-source-cell :group="group" />
</template>
<template #cell(import_target)="{ item: group }">
<import-target-cell
@@ -388,19 +397,14 @@ export default {
/>
</template>
<template #cell(progress)="{ value: { status } }">
- <import-status :status="status" class="gl-line-height-32" />
+ <import-status-cell :status="status" class="gl-line-height-32" />
</template>
<template #cell(actions)="{ item: group }">
- <gl-button
- v-if="!isAlreadyImported(group)"
- :disabled="isInvalid(group)"
- variant="confirm"
- category="secondary"
- data-qa-selector="import_group_button"
- @click="importGroups([group.id])"
- >
- {{ __('Import') }}
- </gl-button>
+ <import-actions-cell
+ :group="group"
+ :group-path-regex="groupPathRegex"
+ @import-group="importGroups([group.id])"
+ />
</template>
</gl-table>
<div v-if="hasGroups" class="gl-display-flex gl-mt-3 gl-align-items-center">
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 7359d4f239e..daced740c94 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 {
</script>
<template>
- <gl-link
- v-if="isFinished"
- class="gl-display-inline-flex gl-align-items-center gl-h-7"
- :href="absolutePath"
- >
- {{ fullPath }}
- </gl-link>
-
- <div
- v-else
- class="gl-display-flex gl-align-items-stretch"
- :class="{
- disabled: isAlreadyImported,
- }"
- >
+ <div class="gl-display-flex gl-align-items-stretch">
<import-group-dropdown
#default="{ namespaces }"
:text="importTarget.target_namespace"
- :disabled="isAlreadyImported"
+ :disabled="!isAvailableForImport"
:namespaces="availableNamespaceNames"
toggle-class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
class="gl-h-7 gl-flex-grow-1"
@@ -131,8 +106,8 @@ export default {
<div
class="gl-h-7 gl-px-3 gl-display-flex gl-align-items-center gl-border-solid gl-border-0 gl-border-t-1 gl-border-b-1 gl-bg-gray-10"
:class="{
- 'gl-text-gray-400 gl-border-gray-100': isAlreadyImported,
- 'gl-border-gray-200': !isAlreadyImported,
+ 'gl-text-gray-400 gl-border-gray-100': !isAvailableForImport,
+ 'gl-border-gray-200': isAvailableForImport,
}"
>
/
@@ -141,11 +116,11 @@ export default {
<gl-form-input
class="gl-rounded-top-left-none gl-rounded-bottom-left-none"
:class="{
- 'gl-inset-border-1-gray-200!': !isAlreadyImported,
- 'gl-inset-border-1-gray-100!': isAlreadyImported,
- 'is-invalid': isInvalid && !isAlreadyImported,
+ 'gl-inset-border-1-gray-200!': isAvailableForImport,
+ 'gl-inset-border-1-gray-100!': !isAvailableForImport,
+ 'is-invalid': isInvalid && isAvailableForImport,
}"
- :disabled="isAlreadyImported"
+ :disabled="!isAvailableForImport"
:value="importTarget.new_name"
@input="$emit('update-new-name', $event)"
/>
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 57188441158..c08cf909a00 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
@@ -5,10 +5,13 @@ 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';
@@ -34,6 +37,7 @@ function makeGroup(data) {
};
const NESTED_OBJECT_FIELDS = {
import_target: clientTypenames.BulkImportTarget,
+ last_import_target: clientTypenames.BulkImportTarget,
progress: clientTypenames.BulkImportProgress,
};
@@ -55,6 +59,7 @@ async function checkImportTargetIsValid({ client, newName, targetNamespace, sour
data: { existingGroup, existingProject },
} = await client.query({
query: groupAndProjectQuery,
+ fetchPolicy: 'no-cache',
variables: {
fullPath: `${targetNamespace}/${newName}`,
},
@@ -82,6 +87,7 @@ async function checkImportTargetIsValid({ client, newName, targetNamespace, sour
}
const localProgressId = (id) => `not-started-${id}`;
+const nextName = (name) => `${name}-1`;
export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGroupsManager }) {
const groupsManager = new GroupsManager({
@@ -140,17 +146,28 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
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: cachedImportState?.status ?? STATUSES.NONE,
- },
- import_target: cachedImportState?.importTarget ?? {
- new_name: group.full_path,
- target_namespace: availableNamespaces[0]?.full_path ?? '',
+ status,
},
+ import_target: importTarget,
+ last_import_target: cachedImportState?.importTarget ?? null,
});
}),
pageInfo: {
@@ -161,7 +178,7 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
setTimeout(() => {
response.nodes.forEach((group) => {
- if (group.progress.status === STATUSES.NONE) {
+ if (isAvailableForImport(group)) {
checkImportTargetIsValid({
client,
newName: group.import_target.new_name,
@@ -193,32 +210,18 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
targetNamespace,
newName,
});
+
return makeGroup({
id: sourceGroupId,
import_target: {
target_namespace: targetNamespace,
new_name: newName,
+ id: sourceGroupId,
},
});
},
- 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 }) {
+ async setImportProgress(_, { sourceGroupId, status, jobId, importTarget }) {
if (jobId) {
groupsManager.updateImportProgress(jobId, status);
}
@@ -229,16 +232,46 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
id: jobId ?? localProgressId(sourceGroupId),
status,
},
+ last_import_target: {
+ __typename: clientTypenames.BulkImportTarget,
+ ...importTarget,
+ },
});
},
- async updateImportStatus(_, { id, status }) {
- groupsManager.updateImportProgress(id, status);
+ async updateImportStatus(_, { id, status: newStatus }, { client, getCacheKey }) {
+ groupsManager.updateImportProgress(id, newStatus);
+
+ const progressItem = client.readFragment({
+ fragment: bulkImportSourceGroupProgressFragment,
+ fragmentName: 'BulkImportSourceGroupProgress',
+ id: getCacheKey({
+ __typename: clientTypenames.BulkImportProgress,
+ id,
+ }),
+ });
+
+ const isInProgress = Boolean(progressItem);
+ const { status: currentStatus } = progressItem ?? {};
+ if (newStatus === STATUSES.FINISHED && isInProgress && currentStatus !== newStatus) {
+ const groups = groupsManager.getImportedGroupsByJobId(id);
+
+ groups.forEach(async ({ id: groupId, importTarget }) => {
+ client.mutate({
+ mutation: setImportTargetMutation,
+ variables: {
+ sourceGroupId: groupId,
+ targetNamespace: importTarget.target_namespace,
+ newName: nextName(importTarget.new_name),
+ },
+ });
+ });
+ }
return {
__typename: clientTypenames.BulkImportProgress,
id,
- status,
+ status: newStatus,
};
},
@@ -327,10 +360,10 @@ export function createResolvers({ endpoints, sourceUrl, GroupsManager = SourceGr
return { status: STATUSES.NONE };
})
.then((newStatus) =>
- sourceGroupIds.forEach((sourceGroupId) =>
+ sourceGroupIds.forEach((sourceGroupId, idx) =>
client.mutate({
mutation: setImportProgressMutation,
- variables: { sourceGroupId, ...newStatus },
+ variables: { sourceGroupId, ...newStatus, importTarget: groups[idx].import_target },
}),
),
)
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 47675cd1bd0..089340b3c48 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 2ec1269932a..43301554de3 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
+ }
}
}
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 97dbdbf518a..7caa37d9ad4 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,18 @@ 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: { ...g.import_target },
+ 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 +55,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 +73,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
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 c830aaa75e6..6ef4bbafec0 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!
diff --git a/app/assets/javascripts/import_entities/import_groups/utils.js b/app/assets/javascripts/import_entities/import_groups/utils.js
index b451008b6f9..a1baeaf39dd 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);
+}