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-02-18 13:34:06 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 13:34:06 +0300
commit859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch)
treed7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /app/assets/javascripts/import_entities
parent446d496a6d000c73a304be52587cd9bbc7493136 (diff)
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'app/assets/javascripts/import_entities')
-rw-r--r--app/assets/javascripts/import_entities/import_groups/components/import_table.vue212
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/client_factory.js61
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql14
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/services/source_groups_manager.js10
-rw-r--r--app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js85
-rw-r--r--app/assets/javascripts/import_entities/import_groups/index.js17
-rw-r--r--app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue36
-rw-r--r--app/assets/javascripts/import_entities/import_projects/components/provider_repo_table_row.vue61
-rw-r--r--app/assets/javascripts/import_entities/import_projects/index.js2
-rw-r--r--app/assets/javascripts/import_entities/import_projects/store/actions.js12
-rw-r--r--app/assets/javascripts/import_entities/import_projects/store/index.js2
-rw-r--r--app/assets/javascripts/import_entities/import_projects/store/mutations.js2
12 files changed, 333 insertions, 181 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 80e2e73f420..7c5f48dcafc 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
@@ -1,78 +1,184 @@
<script>
-import { GlLoadingIcon } from '@gitlab/ui';
-import bulkImportSourceGroupsQuery from '../graphql/queries/bulk_import_source_groups.query.graphql';
-import availableNamespacesQuery from '../graphql/queries/available_namespaces.query.graphql';
-import setTargetNamespaceMutation from '../graphql/mutations/set_target_namespace.mutation.graphql';
-import setNewNameMutation from '../graphql/mutations/set_new_name.mutation.graphql';
+import {
+ GlEmptyState,
+ GlIcon,
+ GlLink,
+ GlLoadingIcon,
+ GlSearchBoxByClick,
+ GlSprintf,
+} from '@gitlab/ui';
+import { s__ } from '~/locale';
+import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
import importGroupMutation from '../graphql/mutations/import_group.mutation.graphql';
+import setNewNameMutation from '../graphql/mutations/set_new_name.mutation.graphql';
+import setTargetNamespaceMutation from '../graphql/mutations/set_target_namespace.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';
-const mapApolloMutations = (mutations) =>
- Object.fromEntries(
- Object.entries(mutations).map(([key, mutation]) => [
- key,
- function mutate(config) {
- return this.$apollo.mutate({
- mutation,
- ...config,
- });
- },
- ]),
- );
-
export default {
components: {
+ GlEmptyState,
+ GlIcon,
+ GlLink,
GlLoadingIcon,
+ GlSearchBoxByClick,
+ GlSprintf,
ImportTableRow,
+ PaginationLinks,
+ },
+
+ props: {
+ sourceUrl: {
+ type: String,
+ required: true,
+ },
+ },
+
+ data() {
+ return {
+ filter: '',
+ page: 1,
+ };
},
apollo: {
- bulkImportSourceGroups: bulkImportSourceGroupsQuery,
+ bulkImportSourceGroups: {
+ query: bulkImportSourceGroupsQuery,
+ variables() {
+ return { page: this.page, filter: this.filter };
+ },
+ },
availableNamespaces: availableNamespacesQuery,
},
+ computed: {
+ hasGroups() {
+ return this.bulkImportSourceGroups?.nodes?.length > 0;
+ },
+
+ hasEmptyFilter() {
+ return this.filter.length > 0 && !this.hasGroups;
+ },
+
+ statusMessage() {
+ return this.filter.length === 0
+ ? s__('BulkImport|Showing %{start}-%{end} of %{total} from %{link}')
+ : s__(
+ 'BulkImport|Showing %{start}-%{end} of %{total} matching filter "%{filter}" from %{link}',
+ );
+ },
+
+ paginationInfo() {
+ const { page, perPage, total } = this.bulkImportSourceGroups?.pageInfo ?? {
+ page: 1,
+ perPage: 0,
+ total: 0,
+ };
+ const start = (page - 1) * perPage + 1;
+ const end = start + (this.bulkImportSourceGroups.nodes?.length ?? 0) - 1;
+
+ return { start, end, total };
+ },
+ },
+
+ watch: {
+ filter() {
+ this.page = 1;
+ },
+ },
+
methods: {
- ...mapApolloMutations({
- setTargetNamespace: setTargetNamespaceMutation,
- setNewName: setNewNameMutation,
- importGroup: importGroupMutation,
- }),
+ setPage(page) {
+ this.page = page;
+ },
+
+ updateTargetNamespace(sourceGroupId, targetNamespace) {
+ this.$apollo.mutate({
+ mutation: setTargetNamespaceMutation,
+ variables: { sourceGroupId, targetNamespace },
+ });
+ },
+
+ updateNewName(sourceGroupId, newName) {
+ this.$apollo.mutate({
+ mutation: setNewNameMutation,
+ variables: { sourceGroupId, newName },
+ });
+ },
+
+ importGroup(sourceGroupId) {
+ this.$apollo.mutate({
+ mutation: importGroupMutation,
+ variables: { sourceGroupId },
+ });
+ },
},
};
</script>
<template>
<div>
- <gl-loading-icon v-if="$apollo.loading" size="md" class="gl-mt-5" />
- <div v-else-if="bulkImportSourceGroups.length">
- <table class="gl-w-full">
- <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>
- <template v-for="group in bulkImportSourceGroups">
- <import-table-row
- :key="group.id"
- :group="group"
- :available-namespaces="availableNamespaces"
- @update-target-namespace="
- setTargetNamespace({
- variables: { sourceGroupId: group.id, targetNamespace: $event },
- })
- "
- @update-new-name="
- setNewName({
- variables: { sourceGroupId: group.id, newName: $event },
- })
- "
- @import-group="importGroup({ variables: { sourceGroupId: group.id } })"
- />
+ <div
+ class="gl-py-5 gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1 gl-display-flex gl-align-items-center"
+ >
+ <span>
+ <gl-sprintf v-if="!$apollo.loading && hasGroups" :message="statusMessage">
+ <template #start>
+ <strong>{{ paginationInfo.start }}</strong>
+ </template>
+ <template #end>
+ <strong>{{ paginationInfo.end }}</strong>
</template>
- </tbody>
- </table>
+ <template #total>
+ <strong>{{ n__('%d group', '%d groups', paginationInfo.total) }}</strong>
+ </template>
+ <template #filter>
+ <strong>{{ filter }}</strong>
+ </template>
+ <template #link>
+ <gl-link class="gl-display-inline-block" :href="sourceUrl" target="_blank">
+ {{ sourceUrl }} <gl-icon name="external-link" class="vertical-align-middle" />
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </span>
+ <gl-search-box-by-click class="gl-ml-auto" @submit="filter = $event" @clear="filter = ''" />
</div>
+ <gl-loading-icon v-if="$apollo.loading" size="md" class="gl-mt-5" />
+ <template v-else>
+ <gl-empty-state v-if="hasEmptyFilter" :title="__('Sorry, your filter produced no results')" />
+ <gl-empty-state
+ v-else-if="!hasGroups"
+ :title="s__('BulkImport|No groups available for import')"
+ />
+ <div v-else class="gl-display-flex gl-flex-direction-column gl-align-items-center">
+ <table class="gl-w-full">
+ <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>
+ <template v-for="group in bulkImportSourceGroups.nodes">
+ <import-table-row
+ :key="group.id"
+ :group="group"
+ :available-namespaces="availableNamespaces"
+ @update-target-namespace="updateTargetNamespace(group.id, $event)"
+ @update-new-name="updateNewName(group.id, $event)"
+ @import-group="importGroup(group.id)"
+ />
+ </template>
+ </tbody>
+ </table>
+ <pagination-links
+ :change="setPage"
+ :page-info="bulkImportSourceGroups.pageInfo"
+ class="gl-mt-3"
+ />
+ </div>
+ </template>
</div>
</template>
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 8f2d488d661..8110934efc4 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,15 +1,18 @@
-import axios from '~/lib/utils/axios_utils';
+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 createFlash from '~/flash';
import { STATUSES } from '../../constants';
import availableNamespacesQuery from './queries/available_namespaces.query.graphql';
import { SourceGroupsManager } from './services/source_groups_manager';
import { StatusPoller } from './services/status_poller';
export const clientTypenames = {
+ BulkImportSourceGroupConnection: 'ClientBulkImportSourceGroupConnection',
BulkImportSourceGroup: 'ClientBulkImportSourceGroup',
AvailableNamespace: 'ClientAvailableNamespace',
+ BulkImportPageInfo: 'ClientBulkImportPageInfo',
};
export function createResolvers({ endpoints }) {
@@ -17,22 +20,47 @@ export function createResolvers({ endpoints }) {
return {
Query: {
- async bulkImportSourceGroups(_, __, { client }) {
+ async bulkImportSourceGroups(_, vars, { client }) {
const {
data: { availableNamespaces },
} = await client.query({ query: availableNamespacesQuery });
- return axios.get(endpoints.status).then(({ data }) => {
- return data.importable_data.map((group) => ({
- __typename: clientTypenames.BulkImportSourceGroup,
- ...group,
- status: STATUSES.NONE,
- import_target: {
- new_name: group.full_path,
- target_namespace: availableNamespaces[0].full_path,
+ if (!statusPoller) {
+ statusPoller = new StatusPoller({
+ client,
+ pollPath: endpoints.jobs,
+ });
+ statusPoller.startPolling();
+ }
+
+ return axios
+ .get(endpoints.status, {
+ params: {
+ page: vars.page,
+ per_page: vars.perPage,
+ filter: vars.filter,
},
- }));
- });
+ })
+ .then(({ headers, data }) => {
+ const pagination = parseIntPagination(normalizeHeaders(headers));
+
+ return {
+ __typename: clientTypenames.BulkImportSourceGroupConnection,
+ nodes: data.importable_data.map((group) => ({
+ __typename: clientTypenames.BulkImportSourceGroup,
+ ...group,
+ status: STATUSES.NONE,
+ import_target: {
+ new_name: group.full_path,
+ target_namespace: availableNamespaces[0].full_path,
+ },
+ })),
+ pageInfo: {
+ __typename: clientTypenames.BulkImportPageInfo,
+ ...pagination,
+ },
+ };
+ });
},
availableNamespaces: () =>
@@ -63,7 +91,7 @@ export function createResolvers({ endpoints }) {
const group = groupManager.findById(sourceGroupId);
groupManager.setImportStatus(group, STATUSES.SCHEDULING);
try {
- await axios.post(endpoints.createBulkImport, {
+ const response = await axios.post(endpoints.createBulkImport, {
bulk_import: [
{
source_type: 'group_entity',
@@ -74,10 +102,7 @@ export function createResolvers({ endpoints }) {
],
});
groupManager.setImportStatus(group, STATUSES.STARTED);
- if (!statusPoller) {
- statusPoller = new StatusPoller({ client, interval: 3000 });
- statusPoller.startPolling();
- }
+ SourceGroupsManager.attachImportId(group, response.data.id);
} catch (e) {
createFlash({
message: s__('BulkImport|Importing the group failed'),
diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql b/app/assets/javascripts/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql
index 8d52d94925c..28dfefdf8a7 100644
--- a/app/assets/javascripts/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql
+++ b/app/assets/javascripts/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql
@@ -1,7 +1,15 @@
#import "../fragments/bulk_import_source_group_item.fragment.graphql"
-query bulkImportSourceGroups {
- bulkImportSourceGroups @client {
- ...BulkImportSourceGroupItem
+query bulkImportSourceGroups($page: Int = 1, $perPage: Int = 20, $filter: String = "") {
+ bulkImportSourceGroups(page: $page, filter: $filter, perPage: $perPage) @client {
+ nodes {
+ ...BulkImportSourceGroupItem
+ }
+ pageInfo {
+ page
+ perPage
+ total
+ totalPages
+ }
}
}
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 047b04fe7d6..261e30edbbb 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
@@ -14,6 +14,12 @@ function generateGroupId(id) {
}
export class SourceGroupsManager {
+ static importMap = new Map();
+
+ static attachImportId(group, importId) {
+ SourceGroupsManager.importMap.set(importId, group.id);
+ }
+
constructor({ client }) {
this.client = client;
}
@@ -36,6 +42,10 @@ export class SourceGroupsManager {
this.update(group, fn);
}
+ findByImportId(importId) {
+ return this.findById(SourceGroupsManager.importMap.get(importId));
+ }
+
setImportStatus(group, status) {
this.update(group, (sourceGroup) => {
// eslint-disable-next-line no-param-reassign
diff --git a/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js b/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js
index 41dd25b9150..63cd6b48fc4 100644
--- a/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js
+++ b/app/assets/javascripts/import_entities/import_groups/graphql/services/status_poller.js
@@ -1,68 +1,47 @@
-import gql from 'graphql-tag';
+import Visibility from 'visibilityjs';
import createFlash from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+import Poll from '~/lib/utils/poll';
import { s__ } from '~/locale';
-import bulkImportSourceGroupsQuery from '../queries/bulk_import_source_groups.query.graphql';
-import { STATUSES } from '../../../constants';
import { SourceGroupsManager } from './source_groups_manager';
-const groupId = (i) => `group${i}`;
-
-function generateGroupsQuery(groups) {
- return gql`{
- ${groups
- .map(
- (g, idx) =>
- `${groupId(idx)}: group(fullPath: "${g.import_target.target_namespace}/${
- g.import_target.new_name
- }") { id }`,
- )
- .join('\n')}
- }`;
-}
-
export class StatusPoller {
- constructor({ client, interval }) {
+ constructor({ client, pollPath }) {
this.client = client;
- this.interval = interval;
- this.timeoutId = null;
- this.groupManager = new SourceGroupsManager({ client });
- }
- startPolling() {
- if (this.timeoutId) {
- return;
- }
+ this.eTagPoll = new Poll({
+ resource: {
+ fetchJobs: () => axios.get(pollPath),
+ },
+ method: 'fetchJobs',
+ successCallback: ({ data }) => this.updateImportsStatuses(data),
+ errorCallback: () =>
+ createFlash({
+ message: s__('BulkImport|Update of import statuses with realtime changes failed'),
+ }),
+ });
+
+ Visibility.change(() => {
+ if (!Visibility.hidden()) {
+ this.eTagPoll.restart();
+ } else {
+ this.eTagPoll.stop();
+ }
+ });
- this.checkPendingImports();
+ this.groupManager = new SourceGroupsManager({ client });
}
- stopPolling() {
- clearTimeout(this.timeoutId);
- this.timeoutId = null;
+ startPolling() {
+ this.eTagPoll.makeRequest();
}
- async checkPendingImports() {
- try {
- const { bulkImportSourceGroups } = this.client.readQuery({
- query: bulkImportSourceGroupsQuery,
- });
- const groupsInProgress = bulkImportSourceGroups.filter((g) => g.status === STATUSES.STARTED);
- if (groupsInProgress.length) {
- const { data: results } = await this.client.query({
- query: generateGroupsQuery(groupsInProgress),
- fetchPolicy: 'no-cache',
- });
- const completedGroups = groupsInProgress.filter((_, idx) => Boolean(results[groupId(idx)]));
- completedGroups.forEach((group) => {
- this.groupManager.setImportStatus(group, STATUSES.FINISHED);
- });
+ async updateImportsStatuses(importStatuses) {
+ importStatuses.forEach(({ id, status_name: statusName }) => {
+ const group = this.groupManager.findByImportId(id);
+ if (group.id) {
+ this.groupManager.setImportStatus(group, statusName);
}
- } catch (e) {
- createFlash({
- message: s__('BulkImport|Update of import statuses with realtime changes failed'),
- });
- } finally {
- this.timeoutId = setTimeout(() => this.checkPendingImports(), this.interval);
- }
+ });
}
}
diff --git a/app/assets/javascripts/import_entities/import_groups/index.js b/app/assets/javascripts/import_entities/import_groups/index.js
index bf427075564..cd837a840e4 100644
--- a/app/assets/javascripts/import_entities/import_groups/index.js
+++ b/app/assets/javascripts/import_entities/import_groups/index.js
@@ -1,8 +1,8 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import Translate from '~/vue_shared/translate';
-import { createApolloClient } from './graphql/client_factory';
import ImportTable from './components/import_table.vue';
+import { createApolloClient } from './graphql/client_factory';
Vue.use(Translate);
Vue.use(VueApollo);
@@ -10,13 +10,20 @@ Vue.use(VueApollo);
export function mountImportGroupsApp(mountElement) {
if (!mountElement) return undefined;
- const { statusPath, availableNamespacesPath, createBulkImportPath } = mountElement.dataset;
+ const {
+ statusPath,
+ availableNamespacesPath,
+ createBulkImportPath,
+ jobsPath,
+ sourceUrl,
+ } = mountElement.dataset;
const apolloProvider = new VueApollo({
defaultClient: createApolloClient({
endpoints: {
status: statusPath,
availableNamespaces: availableNamespacesPath,
createBulkImport: createBulkImportPath,
+ jobs: jobsPath,
},
}),
});
@@ -25,7 +32,11 @@ export function mountImportGroupsApp(mountElement) {
el: mountElement,
apolloProvider,
render(createElement) {
- return createElement(ImportTable);
+ return createElement(ImportTable, {
+ props: {
+ sourceUrl,
+ },
+ });
},
});
}
diff --git a/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue b/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
index 192d6e056cd..be09052fb7e 100644
--- a/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
+++ b/app/assets/javascripts/import_entities/import_projects/components/import_projects_table.vue
@@ -1,6 +1,6 @@
<script>
+import { GlButton, GlLoadingIcon, GlIntersectionObserver, GlModal, GlFormInput } from '@gitlab/ui';
import { mapActions, mapState, mapGetters } from 'vuex';
-import { GlButton, GlLoadingIcon, GlIntersectionObserver, GlModal } from '@gitlab/ui';
import { n__, __, sprintf } from '~/locale';
import ProviderRepoTableRow from './provider_repo_table_row.vue';
@@ -12,6 +12,7 @@ export default {
GlButton,
GlModal,
GlIntersectionObserver,
+ GlFormInput,
},
props: {
providerTitle: {
@@ -115,13 +116,13 @@ export default {
<template>
<div>
- <p class="light text-nowrap mt-2">
+ <p class="gl-text-gray-900 gl-white-space-nowrap gl-mt-3">
{{ s__('ImportProjects|Select the repositories you want to import') }}
</p>
<template v-if="hasIncompatibleRepos">
<slot name="incompatible-repos-warning"></slot>
</template>
- <div class="d-flex justify-content-between align-items-end flex-wrap mb-3">
+ <div class="gl-display-flex gl-justify-content-space-between gl-flex-wrap gl-mb-5">
<gl-button
variant="success"
:loading="isImportingAnyRepo"
@@ -148,24 +149,29 @@ export default {
<slot name="actions"></slot>
<form v-if="filterable" class="gl-ml-auto" novalidate @submit.prevent>
- <input
+ <gl-form-input
data-qa-selector="githubish_import_filter_field"
- class="form-control"
name="filter"
:placeholder="__('Filter your repositories by name')"
autofocus
- size="40"
+ size="lg"
@keyup.enter="setFilter($event.target.value)"
/>
</form>
</div>
- <div v-if="repositories.length" class="table-responsive">
- <table class="table import-table">
- <thead>
- <th class="import-jobs-from-col">{{ fromHeaderText }}</th>
- <th class="import-jobs-to-col">{{ __('To GitLab') }}</th>
- <th class="import-jobs-status-col">{{ __('Status') }}</th>
- <th class="import-jobs-cta-col"></th>
+ <div v-if="repositories.length" class="gl-w-full">
+ <table>
+ <thead class="gl-border-0 gl-border-solid gl-border-t-1 gl-border-gray-100">
+ <th class="import-jobs-from-col gl-p-4 gl-vertical-align-top gl-border-b-1">
+ {{ fromHeaderText }}
+ </th>
+ <th class="import-jobs-to-col gl-p-4 gl-vertical-align-top gl-border-b-1">
+ {{ __('To GitLab') }}
+ </th>
+ <th class="import-jobs-status-col gl-p-4 gl-vertical-align-top gl-border-b-1">
+ {{ __('Status') }}
+ </th>
+ <th class="import-jobs-cta-col gl-p-4 gl-vertical-align-top gl-border-b-1"></th>
</thead>
<tbody>
<template v-for="repo in repositories">
@@ -183,9 +189,9 @@ export default {
:key="pagePaginationStateKey"
@appear="fetchRepos"
/>
- <gl-loading-icon v-if="isLoading" class="import-projects-loading-icon" size="md" />
+ <gl-loading-icon v-if="isLoading" class="gl-mt-7" size="md" />
- <div v-if="!isLoading && repositories.length === 0" class="text-center">
+ <div v-if="!isLoading && repositories.length === 0" class="gl-text-center">
<strong>{{ emptyStateText }}</strong>
</div>
</div>
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 983abda57f7..289c83979bb 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
@@ -1,8 +1,8 @@
<script>
+import { GlIcon, GlBadge, GlFormInput, GlButton, GlLink } from '@gitlab/ui';
import { mapState, mapGetters, mapActions } from 'vuex';
-import { GlIcon, GlBadge } from '@gitlab/ui';
-import Select2Select from '~/vue_shared/components/select2_select.vue';
import { __ } from '~/locale';
+import Select2Select from '~/vue_shared/components/select2_select.vue';
import ImportStatus from '../../components/import_status.vue';
import { STATUSES } from '../../constants';
import { isProjectImportable, isIncompatible, getImportStatus } from '../utils';
@@ -12,8 +12,11 @@ export default {
components: {
Select2Select,
ImportStatus,
+ GlFormInput,
+ GlButton,
GlIcon,
GlBadge,
+ GlLink,
},
props: {
repo: {
@@ -61,7 +64,7 @@ export default {
select2Options() {
return {
data: this.availableNamespaces,
- containerCssClass: 'import-namespace-select qa-project-namespace-select w-auto',
+ containerCssClass: 'import-namespace-select qa-project-namespace-select gl-w-auto',
};
},
@@ -97,52 +100,56 @@ export default {
</script>
<template>
- <tr class="qa-project-import-row import-row">
- <td>
- <a
- :href="repo.importSource.providerLink"
- rel="noreferrer noopener"
- target="_blank"
- data-testid="providerLink"
+ <tr
+ class="qa-project-import-row gl-h-11 gl-border-0 gl-border-solid gl-border-t-1 gl-border-gray-100 gl-h-11"
+ >
+ <td class="gl-p-4">
+ <gl-link :href="repo.importSource.providerLink" target="_blank" data-testid="providerLink"
>{{ repo.importSource.fullName }}
<gl-icon v-if="repo.importSource.providerLink" name="external-link" />
- </a>
+ </gl-link>
</td>
- <td class="d-flex flex-wrap flex-lg-nowrap" data-testid="fullPath">
+ <td
+ class="gl-display-flex gl-flex-sm-wrap gl-p-4 gl-pt-5 gl-vertical-align-top"
+ data-testid="fullPath"
+ >
<template v-if="repo.importSource.target">{{ repo.importSource.target }}</template>
<template v-else-if="isImportNotStarted">
- <select2-select v-model="targetNamespaceSelect" :options="select2Options" />
- <span class="px-2 import-slash-divider d-flex justify-content-center align-items-center"
- >/</span
- >
- <input
- v-model="newNameInput"
- type="text"
- class="form-control import-project-name-input qa-project-path-field"
- />
+ <div class="import-entities-target-select gl-display-flex gl-align-items-stretch gl-w-full">
+ <select2-select v-model="targetNamespaceSelect" :options="select2Options" />
+ <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"
+ >
+ /
+ </div>
+ <gl-form-input
+ v-model="newNameInput"
+ class="gl-rounded-top-left-none gl-rounded-bottom-left-none qa-project-path-field"
+ />
+ </div>
</template>
<template v-else-if="repo.importedProject">{{ displayFullPath }}</template>
</td>
- <td>
+ <td class="gl-p-4">
<import-status :status="importStatus" />
</td>
<td data-testid="actions">
- <a
+ <gl-button
v-if="isFinished"
class="btn btn-default"
:href="repo.importedProject.fullPath"
rel="noreferrer noopener"
target="_blank"
>{{ __('Go to project') }}
- </a>
- <button
+ </gl-button>
+ <gl-button
v-if="isImportNotStarted"
type="button"
- class="qa-import-button btn btn-default"
+ class="qa-import-button"
@click="fetchImport(repo.importSource.id)"
>
{{ importButtonText }}
- </button>
+ </gl-button>
<gl-badge v-else-if="isIncompatible" variant="danger">{{
__('Incompatible project')
}}</gl-badge>
diff --git a/app/assets/javascripts/import_entities/import_projects/index.js b/app/assets/javascripts/import_entities/import_projects/index.js
index 7373b628f2b..6b7fe23ed60 100644
--- a/app/assets/javascripts/import_entities/import_projects/index.js
+++ b/app/assets/javascripts/import_entities/import_projects/index.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
-import Translate from '~/vue_shared/translate';
import { parseBoolean } from '~/lib/utils/common_utils';
+import Translate from '~/vue_shared/translate';
import ImportProjectsTable from './components/import_projects_table.vue';
import createStore from './store';
diff --git a/app/assets/javascripts/import_entities/import_projects/store/actions.js b/app/assets/javascripts/import_entities/import_projects/store/actions.js
index a8217ff1033..33f8dbb8737 100644
--- a/app/assets/javascripts/import_entities/import_projects/store/actions.js
+++ b/app/assets/javascripts/import_entities/import_projects/store/actions.js
@@ -1,14 +1,14 @@
import Visibility from 'visibilityjs';
-import * as types from './mutation_types';
-import { isProjectImportable } from '../utils';
-import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
-import Poll from '~/lib/utils/poll';
-import { visitUrl, objectToQuery } from '~/lib/utils/url_utility';
import { deprecatedCreateFlash as createFlash } from '~/flash';
-import { s__, sprintf } from '~/locale';
import axios from '~/lib/utils/axios_utils';
+import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import httpStatusCodes from '~/lib/utils/http_status';
+import Poll from '~/lib/utils/poll';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import { visitUrl, objectToQuery } from '~/lib/utils/url_utility';
+import { s__, sprintf } from '~/locale';
+import { isProjectImportable } from '../utils';
+import * as types from './mutation_types';
let eTagPoll;
diff --git a/app/assets/javascripts/import_entities/import_projects/store/index.js b/app/assets/javascripts/import_entities/import_projects/store/index.js
index 7ba12f81eb9..a2880e7d031 100644
--- a/app/assets/javascripts/import_entities/import_projects/store/index.js
+++ b/app/assets/javascripts/import_entities/import_projects/store/index.js
@@ -1,9 +1,9 @@
import Vue from 'vue';
import Vuex from 'vuex';
-import state from './state';
import actionsFactory from './actions';
import * as getters from './getters';
import mutations from './mutations';
+import state from './state';
Vue.use(Vuex);
diff --git a/app/assets/javascripts/import_entities/import_projects/store/mutations.js b/app/assets/javascripts/import_entities/import_projects/store/mutations.js
index 1a96508bd48..c5e1922597a 100644
--- a/app/assets/javascripts/import_entities/import_projects/store/mutations.js
+++ b/app/assets/javascripts/import_entities/import_projects/store/mutations.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
-import * as types from './mutation_types';
import { STATUSES } from '../../constants';
+import * as types from './mutation_types';
const makeNewImportedProject = (importedProject) => ({
importSource: {