summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/import_entities
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/import_entities')
-rw-r--r--app/assets/javascripts/import_entities/components/import_status.vue33
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_actions_cell.vue35
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table.vue60
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js1
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql1
-rw-r--r--app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue4
-rw-r--r--app/assets/javascripts/import_entities/import_projects/index.js8
7 files changed, 117 insertions, 25 deletions
diff --git a/app/assets/javascripts/import_entities/components/import_status.vue b/app/assets/javascripts/import_entities/components/import_status.vue
index bd69165f0ca..db677c574d1 100644
--- a/app/assets/javascripts/import_entities/components/import_status.vue
+++ b/app/assets/javascripts/import_entities/components/import_status.vue
@@ -7,13 +7,21 @@ import { STATUSES } from '../constants';
const STATISTIC_ITEMS = {
diff_note: __('Diff notes'),
issue: __('Issues'),
+ issue_attachment: s__('GithubImporter|Issue attachments'),
+ issue_event: __('Issue events'),
label: __('Labels'),
+ lfs_object: __('LFS objects'),
+ merge_request_attachment: s__('GithubImporter|Merge request attachments'),
milestone: __('Milestones'),
note: __('Notes'),
+ note_attachment: s__('GithubImporter|Note attachments'),
+ protected_branch: __('Protected branches'),
pull_request: s__('GithubImporter|Pull requests'),
pull_request_merged_by: s__('GithubImporter|PR mergers'),
pull_request_review: s__('GithubImporter|PR reviews'),
+ pull_request_review_request: s__('GithubImporter|PR reviews'),
release: __('Releases'),
+ release_attachment: s__('GithubImporter|Release attachments'),
};
// support both camel case and snake case versions
@@ -93,18 +101,17 @@ export default {
mappedStatus() {
if (this.status === STATUSES.FINISHED) {
const isIncomplete = this.stats && isIncompleteImport(this.stats);
- return {
- icon: 'status-success',
- ...(isIncomplete
- ? {
- text: __('Partial import'),
- variant: 'warning',
- }
- : {
- text: __('Complete'),
- variant: 'success',
- }),
- };
+ return isIncomplete
+ ? {
+ icon: 'status-alert',
+ text: __('Partial import'),
+ variant: 'warning',
+ }
+ : {
+ icon: 'status-success',
+ text: __('Complete'),
+ variant: 'success',
+ };
}
return STATUS_MAP[this.status];
@@ -120,6 +127,8 @@ export default {
return { name: 'status-success', class: 'gl-text-green-400' };
} else if (imported === 0) {
return { name: 'status-scheduled', class: 'gl-text-gray-400' };
+ } else if (this.status === STATUSES.FINISHED) {
+ return { name: 'status-alert', class: 'gl-text-orange-400' };
}
return { name: 'status-running', class: 'gl-text-blue-400' };
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
index deaf2654424..8d72942447c 100644
--- 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
@@ -1,15 +1,27 @@
<script>
-import { GlButton, GlIcon, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
+import {
+ GlButton,
+ GlDropdown,
+ GlDropdownItem,
+ GlIcon,
+ GlTooltipDirective as GlTooltip,
+} from '@gitlab/ui';
export default {
components: {
GlIcon,
GlButton,
+ GlDropdown,
+ GlDropdownItem,
},
directives: {
GlTooltip,
},
props: {
+ isProjectsImportEnabled: {
+ type: Boolean,
+ required: true,
+ },
isFinished: {
type: Boolean,
required: true,
@@ -23,13 +35,32 @@ export default {
required: true,
},
},
+ methods: {
+ importGroup(extraArgs = {}) {
+ this.$emit('import-group', extraArgs);
+ },
+ },
};
</script>
<template>
<span class="gl-white-space-nowrap gl-inline-flex gl-align-items-center">
+ <gl-dropdown
+ v-if="isProjectsImportEnabled && isAvailableForImport"
+ :text="isFinished ? __('Re-import with projects') : __('Import with projects')"
+ :disabled="isInvalid"
+ variant="confirm"
+ category="secondary"
+ data-qa-selector="import_group_button"
+ split
+ @click="importGroup({ migrateProjects: true })"
+ >
+ <gl-dropdown-item @click="importGroup({ migrateProjects: false })">{{
+ isFinished ? __('Re-import without projects') : __('Import without projects')
+ }}</gl-dropdown-item>
+ </gl-dropdown>
<gl-button
- v-if="isAvailableForImport"
+ v-else-if="isAvailableForImport"
:disabled="isInvalid"
variant="confirm"
category="secondary"
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 6412f26fde7..c590d832568 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
@@ -2,6 +2,8 @@
import {
GlAlert,
GlButton,
+ GlDropdown,
+ GlDropdownItem,
GlEmptyState,
GlIcon,
GlLink,
@@ -15,6 +17,7 @@ import {
import { debounce } from 'lodash';
import { createAlert } from '~/flash';
import { s__, __, n__, sprintf } from '~/locale';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import PaginationBar from '~/vue_shared/components/pagination_bar/pagination_bar.vue';
import HelpPopover from '~/vue_shared/components/help_popover.vue';
import { getGroupPathAvailability } from '~/rest_api';
@@ -47,6 +50,8 @@ export default {
components: {
GlAlert,
GlButton,
+ GlDropdown,
+ GlDropdownItem,
GlEmptyState,
GlIcon,
GlLink,
@@ -65,6 +70,7 @@ export default {
directives: {
GlTooltip: GlTooltipDirective,
},
+ mixins: [glFeatureFlagsMixin()],
props: {
sourceUrl: {
type: String,
@@ -128,32 +134,36 @@ export default {
{
key: 'webUrl',
label: s__('BulkImport|Source group'),
- thClass: `${DEFAULT_TH_CLASSES} gl-pl-0! import-jobs-from-col`,
+ thClass: `${DEFAULT_TH_CLASSES} gl-pl-0! gl-w-half`,
// eslint-disable-next-line @gitlab/require-i18n-strings
tdClass: `${DEFAULT_TD_CLASSES} gl-pl-0!`,
},
{
key: 'importTarget',
label: s__('BulkImport|New group'),
- thClass: `${DEFAULT_TH_CLASSES} import-jobs-to-col`,
+ thClass: `${DEFAULT_TH_CLASSES} gl-w-half`,
tdClass: DEFAULT_TD_CLASSES,
},
{
key: 'progress',
label: __('Status'),
- thClass: `${DEFAULT_TH_CLASSES} import-jobs-status-col`,
+ thClass: `${DEFAULT_TH_CLASSES}`,
tdClass: DEFAULT_TD_CLASSES,
tdAttr: { 'data-qa-selector': 'import_status_indicator' },
},
{
key: 'actions',
label: '',
- thClass: `${DEFAULT_TH_CLASSES} import-jobs-cta-col`,
+ thClass: `${DEFAULT_TH_CLASSES}`,
tdClass: DEFAULT_TD_CLASSES,
},
],
computed: {
+ isProjectsImportEnabled() {
+ return Boolean(this.glFeatures.bulkImportProjects);
+ },
+
groups() {
return this.bulkImportSourceGroups?.nodes ?? [];
},
@@ -260,7 +270,7 @@ export default {
const table = this.getTableRef();
const matches = new Set();
this.groups.forEach((g, idx) => {
- if (!this.importGroups[g.id]) {
+ if (!this.importTargets[g.id]) {
this.setDefaultImportTarget(g);
}
@@ -375,13 +385,14 @@ export default {
}
},
- importSelectedGroups() {
+ importSelectedGroups(extraArgs = {}) {
const importRequests = this.groupsTableData
.filter((group) => this.selectedGroupsIds.includes(group.id))
.map((group) => ({
sourceGroupId: group.id,
targetNamespace: group.importTarget.targetNamespace.fullPath,
newName: group.importTarget.newName,
+ ...extraArgs,
}));
this.importGroups(importRequests);
@@ -521,6 +532,7 @@ export default {
gitlabLogo: window.gon.gitlab_logo,
PAGE_SIZES,
permissionsHelpPath: helpPagePath('user/permissions', { anchor: 'group-members-permissions' }),
+ betaFeatureHelpPath: helpPagePath('policy/alpha-beta-support', { anchor: 'beta-features' }),
popoverOptions: { title: __('What is listed here?') },
i18n,
LOCAL_STORAGE_KEY: 'gl-bulk-imports-status-page-size-v1',
@@ -637,7 +649,7 @@ export default {
</gl-empty-state>
<template v-else>
<div
- class="gl-bg-gray-10 gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1 gl-px-4 gl-display-flex gl-align-items-center import-table-bar"
+ class="gl-bg-gray-10 gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1 gl-px-4 gl-display-flex gl-align-items-center gl-sticky gl-z-index-3 import-table-bar"
>
<span data-test-id="selection-count">
<gl-sprintf :message="__('%{count} selected')">
@@ -646,7 +658,22 @@ export default {
</template>
</gl-sprintf>
</span>
+ <gl-dropdown
+ v-if="isProjectsImportEnabled"
+ :text="s__('BulkImport|Import with projects')"
+ :disabled="!hasSelectedGroups"
+ variant="confirm"
+ category="primary"
+ class="gl-ml-4"
+ split
+ @click="importSelectedGroups({ migrateProjects: true })"
+ >
+ <gl-dropdown-item @click="importSelectedGroups({ migrateProjects: false })">
+ {{ s__('BulkImport|Import without projects') }}
+ </gl-dropdown-item>
+ </gl-dropdown>
<gl-button
+ v-else
category="primary"
variant="confirm"
class="gl-ml-4"
@@ -654,6 +681,22 @@ export default {
@click="importSelectedGroups"
>{{ s__('BulkImport|Import selected') }}</gl-button
>
+ <span class="gl-ml-3">
+ <gl-icon name="information-o" :size="12" class="gl-text-blue-600" />
+ <gl-sprintf
+ :message="
+ s__(
+ 'BulkImport|Importing projects is a %{docsLinkStart}Beta%{docsLinkEnd} feature.',
+ )
+ "
+ >
+ <template #docsLink="{ content }"
+ ><gl-link :href="$options.betaFeatureHelpPath" target="_blank">{{
+ content
+ }}</gl-link></template
+ >
+ </gl-sprintf>
+ </span>
</div>
<gl-table
ref="table"
@@ -661,6 +704,7 @@ export default {
data-qa-selector="import_table"
:tbody-tr-class="rowClasses"
:tbody-tr-attr="qaRowAttributes"
+ thead-class="gl-sticky gl-z-index-2 gl-bg-gray-10"
:items="groupsTableData"
:fields="$options.fields"
selectable
@@ -711,6 +755,7 @@ export default {
</template>
<template #cell(actions)="{ item: group }">
<import-actions-cell
+ :is-projects-import-enabled="isProjectsImportEnabled"
:is-finished="group.flags.isFinished"
:is-available-for-import="group.flags.isAvailableForImport"
:is-invalid="group.flags.isInvalid"
@@ -720,6 +765,7 @@ export default {
sourceGroupId: group.id,
targetNamespace: group.importTarget.targetNamespace.fullPath,
newName: group.importTarget.newName,
+ ...$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 913a5a659b3..de0595360bf 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
@@ -153,6 +153,7 @@ export function createResolvers({ endpoints }) {
source_full_path: op.group.fullPath,
destination_namespace: op.targetNamespace,
destination_name: op.newName,
+ migrate_projects: op.migrateProjects,
})),
});
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 c48e22a7717..83d17a5baa7 100644
--- a/app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql
+++ b/app/assets/javascripts/import_entities/import_groups/graphql/typedefs.graphql
@@ -74,6 +74,7 @@ input ImportRequestInput {
sourceGroupId: ID!
targetNamespace: String!
newName: String!
+ migrateProjects: Boolean!
}
extend type Mutation {
diff --git a/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue b/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue
index b8faf349375..da5dcfa71e3 100644
--- a/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue
+++ b/app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue
@@ -140,7 +140,7 @@ export default {
>
<template v-if="repo.importSource.target">{{ repo.importSource.target }}</template>
<template v-else-if="isImportNotStarted">
- <div class="import-entities-target-select gl-display-flex gl-align-items-stretch gl-w-full">
+ <div class="gl-display-flex gl-align-items-stretch gl-w-full">
<import-group-dropdown #default="{ namespaces }" :text="importTarget.targetNamespace">
<template v-if="namespaces.length">
<gl-dropdown-section-header>{{ __('Groups') }}</gl-dropdown-section-header>
@@ -161,7 +161,7 @@ export default {
}}</gl-dropdown-item>
</import-group-dropdown>
<div
- class="import-entities-target-select-separator gl-px-3 gl-display-flex gl-align-items-center gl-border-solid gl-border-0 gl-border-t-1 gl-border-b-1"
+ class="gl-px-3 gl-display-flex gl-align-items-center gl-border-solid gl-border-0 gl-border-t-1 gl-border-b-1"
>
/
</div>
diff --git a/app/assets/javascripts/import_entities/import_projects/index.js b/app/assets/javascripts/import_entities/import_projects/index.js
index 197fb03af2c..485511510f7 100644
--- a/app/assets/javascripts/import_entities/import_projects/index.js
+++ b/app/assets/javascripts/import_entities/import_projects/index.js
@@ -57,7 +57,11 @@ const apolloProvider = new VueApollo({
defaultClient,
});
-export default function mountImportProjectsTable(mountElement) {
+export default function mountImportProjectsTable({
+ mountElement,
+ Component = ImportProjectsTable,
+ extraProps = () => ({}),
+}) {
if (!mountElement) return undefined;
const store = initStoreFromElement(mountElement);
@@ -68,7 +72,7 @@ export default function mountImportProjectsTable(mountElement) {
store,
apolloProvider,
render(createElement) {
- return createElement(ImportProjectsTable, { props });
+ return createElement(Component, { props: { ...props, ...extraProps(mountElement.dataset) } });
},
});
}