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:
Diffstat (limited to 'app/assets/javascripts/import_entities/import_groups/components')
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table.vue269
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table_row.vue227
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue162
3 files changed, 364 insertions, 294 deletions
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 cb7e3ef9632..db44be2bcd7 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
@@ -10,20 +10,25 @@ import {
GlSearchBoxByClick,
GlSprintf,
GlSafeHtmlDirective as SafeHtml,
- GlTooltip,
+ 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 importGroupsMutation from '../graphql/mutations/import_groups.mutation.graphql';
-import setNewNameMutation from '../graphql/mutations/set_new_name.mutation.graphql';
-import setTargetNamespaceMutation from '../graphql/mutations/set_target_namespace.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 ImportTableRow from './import_table_row.vue';
+import { isInvalid } from '../utils';
+import ImportTargetCell from './import_target_cell.vue';
const PAGE_SIZES = [20, 50, 100];
const DEFAULT_PAGE_SIZE = PAGE_SIZES[0];
+const DEFAULT_TH_CLASSES =
+ 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-200! gl-border-b-1! gl-p-5!';
+const DEFAULT_TD_CLASSES = 'gl-vertical-align-top!';
export default {
components: {
@@ -35,9 +40,11 @@ export default {
GlLink,
GlLoadingIcon,
GlSearchBoxByClick,
+ GlFormCheckbox,
GlSprintf,
- GlTooltip,
- ImportTableRow,
+ GlTable,
+ ImportStatus,
+ ImportTargetCell,
PaginationLinks,
},
directives: {
@@ -53,6 +60,10 @@ export default {
type: RegExp,
required: true,
},
+ groupUrlErrorMessage: {
+ type: String,
+ required: true,
+ },
},
data() {
@@ -60,6 +71,7 @@ export default {
filter: '',
page: 1,
perPage: DEFAULT_PAGE_SIZE,
+ selectedGroups: [],
};
},
@@ -73,21 +85,58 @@ export default {
availableNamespaces: availableNamespacesQuery,
},
+ fields: [
+ {
+ key: 'selected',
+ label: '',
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ thClass: `${DEFAULT_TH_CLASSES} gl-w-3 gl-pr-3!`,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ tdClass: `${DEFAULT_TD_CLASSES} gl-pr-3!`,
+ },
+ {
+ key: 'web_url',
+ label: s__('BulkImport|From source group'),
+ thClass: `${DEFAULT_TH_CLASSES} gl-pl-0! import-jobs-from-col`,
+ // eslint-disable-next-line @gitlab/require-i18n-strings
+ tdClass: `${DEFAULT_TD_CLASSES} gl-pl-0!`,
+ },
+ {
+ key: 'import_target',
+ label: s__('BulkImport|To new group'),
+ thClass: `${DEFAULT_TH_CLASSES} import-jobs-to-col`,
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ {
+ key: 'progress',
+ label: __('Status'),
+ thClass: `${DEFAULT_TH_CLASSES} import-jobs-status-col`,
+ tdClass: DEFAULT_TD_CLASSES,
+ tdAttr: { 'data-qa-selector': 'import_status_indicator' },
+ },
+ {
+ key: 'actions',
+ label: '',
+ thClass: `${DEFAULT_TH_CLASSES} import-jobs-cta-col`,
+ tdClass: DEFAULT_TD_CLASSES,
+ },
+ ],
+
computed: {
groups() {
return this.bulkImportSourceGroups?.nodes ?? [];
},
- hasGroupsWithValidationError() {
- return this.groups.some((g) => g.validation_errors.length);
+ hasSelectedGroups() {
+ return this.selectedGroups.length > 0;
},
- availableGroupsForImport() {
- return this.groups.filter((g) => g.progress.status === STATUSES.NONE);
+ hasAllAvailableGroupsSelected() {
+ return this.selectedGroups.length === this.availableGroupsForImport.length;
},
- isImportAllButtonDisabled() {
- return this.hasGroupsWithValidationError || this.availableGroupsForImport.length === 0;
+ availableGroupsForImport() {
+ return this.groups.filter((g) => g.progress.status === STATUSES.NONE && !this.isInvalid(g));
},
humanizedTotal() {
@@ -117,7 +166,7 @@ export default {
total: 0,
};
const start = (page - 1) * perPage + 1;
- const end = start + (this.bulkImportSourceGroups.nodes?.length ?? 0) - 1;
+ const end = start + this.groups.length - 1;
return { start, end, total };
},
@@ -127,9 +176,39 @@ export default {
filter() {
this.page = 1;
},
+ groups() {
+ const table = this.getTableRef();
+ this.groups.forEach((g, idx) => {
+ if (this.selectedGroups.includes(g)) {
+ this.$nextTick(() => {
+ table.selectRow(idx);
+ });
+ }
+ });
+ this.selectedGroups = [];
+ },
},
methods: {
+ qaRowAttributes(group, type) {
+ if (type === 'row') {
+ return {
+ 'data-qa-selector': 'import_item',
+ 'data-qa-source-group': group.full_path,
+ };
+ }
+
+ return {};
+ },
+
+ isAlreadyImported(group) {
+ return group.progress.status !== STATUSES.NONE;
+ },
+
+ isInvalid(group) {
+ return isInvalid(group, this.groupPathRegex);
+ },
+
groupsCount(count) {
return n__('%d group', '%d groups', count);
},
@@ -138,17 +217,10 @@ export default {
this.page = page;
},
- updateTargetNamespace(sourceGroupId, targetNamespace) {
+ updateImportTarget(sourceGroupId, targetNamespace, newName) {
this.$apollo.mutate({
- mutation: setTargetNamespaceMutation,
- variables: { sourceGroupId, targetNamespace },
- });
- },
-
- updateNewName(sourceGroupId, newName) {
- this.$apollo.mutate({
- mutation: setNewNameMutation,
- variables: { sourceGroupId, newName },
+ mutation: setImportTargetMutation,
+ variables: { sourceGroupId, targetNamespace, newName },
});
},
@@ -159,13 +231,33 @@ export default {
});
},
- importAllGroups() {
- this.importGroups(this.availableGroupsForImport.map((g) => g.id));
+ importSelectedGroups() {
+ this.importGroups(this.selectedGroups.map((g) => g.id));
},
setPageSize(size) {
this.perPage = size;
},
+
+ getTableRef() {
+ // Acquire reference to BTable to manipulate selection
+ // issue: https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1531
+ // refs are not reactive, so do not use computed here
+ return this.$refs.table?.$children[0];
+ },
+
+ preventSelectingAlreadyImportedGroups(updatedSelection) {
+ if (updatedSelection) {
+ this.selectedGroups = updatedSelection;
+ }
+
+ const table = this.getTableRef();
+ this.groups.forEach((group, idx) => {
+ if (table.isRowSelected(idx) && (this.isAlreadyImported(group) || this.isInvalid(group))) {
+ table.unselectRow(idx);
+ }
+ });
+ },
},
gitlabLogo: window.gon.gitlab_logo,
@@ -180,28 +272,6 @@ export default {
>
<img :src="$options.gitlabLogo" class="gl-w-6 gl-h-6 gl-mb-2 gl-display-inline gl-mr-2" />
{{ s__('BulkImport|Import groups from GitLab') }}
- <div ref="importAllButtonWrapper" class="gl-ml-auto">
- <gl-button
- v-if="!$apollo.loading && hasGroups"
- :disabled="isImportAllButtonDisabled"
- variant="confirm"
- @click="importAllGroups"
- >
- <gl-sprintf :message="s__('BulkImport|Import %{groups}')">
- <template #groups>
- {{ groupsCount(availableGroupsForImport.length) }}
- </template>
- </gl-sprintf>
- </gl-button>
- </div>
- <gl-tooltip v-if="isImportAllButtonDisabled" :target="() => $refs.importAllButtonWrapper">
- <template v-if="hasGroupsWithValidationError">
- {{ s__('BulkImport|One or more groups has validation errors') }}
- </template>
- <template v-else>
- {{ s__('BulkImport|No groups on this page are available for import') }}
- </template>
- </gl-tooltip>
</h1>
<div
class="gl-py-5 gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1 gl-display-flex"
@@ -247,27 +317,92 @@ export default {
:description="s__('Check your source instance permissions.')"
/>
<template v-else>
- <table class="gl-w-full" data-qa-selector="import_table">
- <thead class="gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1">
- <th class="gl-py-4 import-jobs-from-col">{{ s__('BulkImport|From source group') }}</th>
- <th class="gl-py-4 import-jobs-to-col">{{ s__('BulkImport|To new group') }}</th>
- <th class="gl-py-4 import-jobs-status-col">{{ __('Status') }}</th>
- <th class="gl-py-4 import-jobs-cta-col"></th>
- </thead>
- <tbody class="gl-vertical-align-top">
- <template v-for="group in bulkImportSourceGroups.nodes">
- <import-table-row
- :key="group.id"
- :group="group"
- :available-namespaces="availableNamespaces"
- :group-path-regex="groupPathRegex"
- @update-target-namespace="updateTargetNamespace(group.id, $event)"
- @update-new-name="updateNewName(group.id, $event)"
- @import-group="importGroups([group.id])"
- />
+ <div
+ class="gl-bg-gray-10 gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1 gl-p-4 gl-display-flex gl-align-items-center"
+ >
+ <gl-sprintf :message="__('%{count} selected')">
+ <template #count>
+ {{ selectedGroups.length }}
</template>
- </tbody>
- </table>
+ </gl-sprintf>
+ <gl-button
+ category="primary"
+ variant="confirm"
+ class="gl-ml-4"
+ :disabled="!hasSelectedGroups"
+ @click="importSelectedGroups"
+ >{{ s__('BulkImport|Import selected') }}</gl-button
+ >
+ </div>
+ <gl-table
+ 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-attr="qaRowAttributes"
+ :items="groups"
+ :fields="$options.fields"
+ selectable
+ select-mode="multi"
+ selected-variant="primary"
+ @row-selected="preventSelectingAlreadyImportedGroups"
+ >
+ <template #head(selected)="{ selectAllRows, clearSelected }">
+ <gl-form-checkbox
+ :key="`checkbox-${selectedGroups.length}`"
+ class="gl-h-7 gl-pt-3"
+ :checked="hasSelectedGroups"
+ :indeterminate="hasSelectedGroups && !hasAllAvailableGroupsSelected"
+ @change="hasAllAvailableGroupsSelected ? clearSelected() : selectAllRows()"
+ />
+ </template>
+ <template #cell(selected)="{ rowSelected, selectRow, unselectRow, item: group }">
+ <gl-form-checkbox
+ class="gl-h-7 gl-pt-3"
+ :checked="rowSelected"
+ :disabled="isAlreadyImported(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>
+ <template #cell(import_target)="{ item: group }">
+ <import-target-cell
+ :group="group"
+ :available-namespaces="availableNamespaces"
+ :group-path-regex="groupPathRegex"
+ :group-url-error-message="groupUrlErrorMessage"
+ @update-target-namespace="
+ updateImportTarget(group.id, $event, group.import_target.new_name)
+ "
+ @update-new-name="
+ updateImportTarget(group.id, group.import_target.target_namespace, $event)
+ "
+ />
+ </template>
+ <template #cell(progress)="{ value: { status } }">
+ <import-status :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>
+ </template>
+ </gl-table>
<div v-if="hasGroups" class="gl-display-flex gl-mt-3 gl-align-items-center">
<pagination-links
:change="setPage"
diff --git a/app/assets/javascripts/import_entities/import_groups/components/import_table_row.vue b/app/assets/javascripts/import_entities/import_groups/components/import_table_row.vue
deleted file mode 100644
index 1c3ede769e0..00000000000
--- a/app/assets/javascripts/import_entities/import_groups/components/import_table_row.vue
+++ /dev/null
@@ -1,227 +0,0 @@
-<script>
-import {
- GlButton,
- GlDropdownDivider,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlIcon,
- GlLink,
- GlFormInput,
-} from '@gitlab/ui';
-import { joinPaths } from '~/lib/utils/url_utility';
-import { s__ } from '~/locale';
-import ImportGroupDropdown from '../../components/group_dropdown.vue';
-import ImportStatus from '../../components/import_status.vue';
-import { STATUSES } from '../../constants';
-import addValidationErrorMutation from '../graphql/mutations/add_validation_error.mutation.graphql';
-import removeValidationErrorMutation from '../graphql/mutations/remove_validation_error.mutation.graphql';
-import groupAndProjectQuery from '../graphql/queries/groupAndProject.query.graphql';
-
-const DEBOUNCE_INTERVAL = 300;
-
-export default {
- components: {
- ImportStatus,
- ImportGroupDropdown,
- GlButton,
- GlDropdownDivider,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlLink,
- GlIcon,
- GlFormInput,
- },
- props: {
- group: {
- type: Object,
- required: true,
- },
- availableNamespaces: {
- type: Array,
- required: true,
- },
- groupPathRegex: {
- type: RegExp,
- required: true,
- },
- },
-
- apollo: {
- existingGroupAndProject: {
- query: groupAndProjectQuery,
- debounce: DEBOUNCE_INTERVAL,
- variables() {
- return {
- fullPath: this.fullPath,
- };
- },
- update({ existingGroup, existingProject }) {
- const variables = {
- field: 'new_name',
- sourceGroupId: this.group.id,
- };
-
- if (!existingGroup && !existingProject) {
- this.$apollo.mutate({
- mutation: removeValidationErrorMutation,
- variables,
- });
- } else {
- this.$apollo.mutate({
- mutation: addValidationErrorMutation,
- variables: {
- ...variables,
- message: this.$options.i18n.NAME_ALREADY_EXISTS,
- },
- });
- }
- },
- skip() {
- return !this.isNameValid || this.isAlreadyImported;
- },
- },
- },
-
- computed: {
- availableNamespaceNames() {
- return this.availableNamespaces.map((ns) => ns.full_path);
- },
-
- importTarget() {
- return this.group.import_target;
- },
-
- invalidNameValidationMessage() {
- return this.group.validation_errors.find(({ field }) => field === 'new_name')?.message;
- },
-
- isInvalid() {
- return Boolean(!this.isNameValid || this.invalidNameValidationMessage);
- },
-
- isNameValid() {
- return this.groupPathRegex.test(this.importTarget.new_name);
- },
-
- 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);
- },
- },
-
- i18n: {
- NAME_ALREADY_EXISTS: s__('BulkImport|Name already exists.'),
- },
-};
-</script>
-
-<template>
- <tr
- class="gl-border-gray-200 gl-border-0 gl-border-b-1 gl-border-solid"
- data-qa-selector="import_item"
- :data-qa-source-group="group.full_path"
- >
- <td class="gl-p-4">
- <gl-link
- :href="group.web_url"
- target="_blank"
- class="gl-display-flex gl-align-items-center gl-h-7"
- >
- {{ group.full_path }} <gl-icon name="external-link" />
- </gl-link>
- </td>
- <td class="gl-p-4">
- <gl-link
- v-if="isFinished"
- class="gl-display-flex gl-align-items-center gl-h-7"
- :href="absolutePath"
- >
- {{ fullPath }}
- </gl-link>
-
- <div
- v-else
- class="import-entities-target-select gl-display-flex gl-align-items-stretch"
- :class="{
- disabled: isAlreadyImported,
- }"
- >
- <import-group-dropdown
- #default="{ namespaces }"
- :text="importTarget.target_namespace"
- :disabled="isAlreadyImported"
- :namespaces="availableNamespaceNames"
- toggle-class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
- class="import-entities-namespace-dropdown gl-h-7 gl-flex-grow-1"
- data-qa-selector="target_namespace_selector_dropdown"
- >
- <gl-dropdown-item @click="$emit('update-target-namespace', '')">{{
- s__('BulkImport|No parent')
- }}</gl-dropdown-item>
- <template v-if="namespaces.length">
- <gl-dropdown-divider />
- <gl-dropdown-section-header>
- {{ s__('BulkImport|Existing groups') }}
- </gl-dropdown-section-header>
- <gl-dropdown-item
- v-for="ns in namespaces"
- :key="ns"
- data-qa-selector="target_group_dropdown_item"
- :data-qa-group-name="ns"
- @click="$emit('update-target-namespace', ns)"
- >
- {{ ns }}
- </gl-dropdown-item>
- </template>
- </import-group-dropdown>
- <div
- class="import-entities-target-select-separator 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"
- >
- /
- </div>
- <div class="gl-flex-grow-1">
- <gl-form-input
- class="gl-rounded-top-left-none gl-rounded-bottom-left-none"
- :class="{ 'is-invalid': isInvalid && !isAlreadyImported }"
- :disabled="isAlreadyImported"
- :value="importTarget.new_name"
- @input="$emit('update-new-name', $event)"
- />
- <p v-if="isInvalid" class="gl-text-red-500 gl-m-0 gl-mt-2">
- <template v-if="!isNameValid">
- {{ __('Please choose a group URL with no special characters.') }}
- </template>
- <template v-else-if="invalidNameValidationMessage">
- {{ invalidNameValidationMessage }}
- </template>
- </p>
- </div>
- </div>
- </td>
- <td class="gl-p-4 gl-white-space-nowrap" data-qa-selector="import_status_indicator">
- <import-status :status="group.progress.status" class="gl-mt-2" />
- </td>
- <td class="gl-p-4">
- <gl-button
- v-if="!isAlreadyImported"
- :disabled="isInvalid"
- variant="confirm"
- category="secondary"
- data-qa-selector="import_group_button"
- @click="$emit('import-group')"
- >{{ __('Import') }}</gl-button
- >
- </td>
- </tr>
-</template>
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
new file mode 100644
index 00000000000..7359d4f239e
--- /dev/null
+++ b/app/assets/javascripts/import_entities/import_groups/components/import_target_cell.vue
@@ -0,0 +1,162 @@
+<script>
+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';
+
+export default {
+ components: {
+ ImportGroupDropdown,
+ GlDropdownDivider,
+ GlDropdownItem,
+ GlDropdownSectionHeader,
+ GlLink,
+ GlFormInput,
+ },
+ props: {
+ group: {
+ type: Object,
+ required: true,
+ },
+ availableNamespaces: {
+ type: Array,
+ required: true,
+ },
+ groupPathRegex: {
+ type: RegExp,
+ required: true,
+ },
+ groupUrlErrorMessage: {
+ type: String,
+ required: true,
+ },
+ },
+
+ computed: {
+ availableNamespaceNames() {
+ return this.availableNamespaces.map((ns) => ns.full_path);
+ },
+
+ importTarget() {
+ return this.group.import_target;
+ },
+
+ invalidNameValidationMessage() {
+ return getInvalidNameValidationMessage(this.group);
+ },
+
+ isInvalid() {
+ return isInvalid(this.group, this.groupPathRegex);
+ },
+
+ isNameValid() {
+ 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);
+ },
+ },
+
+ i18n: {
+ NAME_ALREADY_EXISTS: s__('BulkImport|Name already exists.'),
+ },
+};
+</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,
+ }"
+ >
+ <import-group-dropdown
+ #default="{ namespaces }"
+ :text="importTarget.target_namespace"
+ :disabled="isAlreadyImported"
+ :namespaces="availableNamespaceNames"
+ toggle-class="gl-rounded-top-right-none! gl-rounded-bottom-right-none!"
+ class="gl-h-7 gl-flex-grow-1"
+ data-qa-selector="target_namespace_selector_dropdown"
+ >
+ <gl-dropdown-item @click="$emit('update-target-namespace', '')">{{
+ s__('BulkImport|No parent')
+ }}</gl-dropdown-item>
+ <template v-if="namespaces.length">
+ <gl-dropdown-divider />
+ <gl-dropdown-section-header>
+ {{ s__('BulkImport|Existing groups') }}
+ </gl-dropdown-section-header>
+ <gl-dropdown-item
+ v-for="ns in namespaces"
+ :key="ns"
+ data-qa-selector="target_group_dropdown_item"
+ :data-qa-group-name="ns"
+ @click="$emit('update-target-namespace', ns)"
+ >
+ {{ ns }}
+ </gl-dropdown-item>
+ </template>
+ </import-group-dropdown>
+ <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,
+ }"
+ >
+ /
+ </div>
+ <div class="gl-flex-grow-1">
+ <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,
+ }"
+ :disabled="isAlreadyImported"
+ :value="importTarget.new_name"
+ @input="$emit('update-new-name', $event)"
+ />
+ <p v-if="isInvalid" class="gl-text-red-500 gl-m-0 gl-mt-2">
+ <template v-if="!isNameValid">
+ {{ groupUrlErrorMessage }}
+ </template>
+ <template v-else-if="invalidNameValidationMessage">
+ {{ invalidNameValidationMessage }}
+ </template>
+ </p>
+ </div>
+ </div>
+</template>