1<script> 2import { GlButton, GlEmptyState, GlLink, GlLoadingIcon, GlTable } from '@gitlab/ui'; 3 4import { s__, __ } from '~/locale'; 5import createFlash from '~/flash'; 6import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils'; 7import { joinPaths } from '~/lib/utils/url_utility'; 8import { getBulkImportsHistory } from '~/rest_api'; 9import ImportStatus from '~/import_entities/components/import_status.vue'; 10import PaginationBar from '~/vue_shared/components/pagination_bar/pagination_bar.vue'; 11import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; 12 13import { DEFAULT_ERROR } from '../utils/error_messages'; 14 15const DEFAULT_PER_PAGE = 20; 16const DEFAULT_TH_CLASSES = 17 'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-200! gl-border-b-1! gl-p-5!'; 18 19const tableCell = (config) => ({ 20 thClass: `${DEFAULT_TH_CLASSES}`, 21 tdClass: (value, key, item) => { 22 return { 23 // eslint-disable-next-line no-underscore-dangle 24 'gl-border-b-0!': item._showDetails, 25 }; 26 }, 27 ...config, 28}); 29 30export default { 31 components: { 32 GlButton, 33 GlEmptyState, 34 GlLink, 35 GlLoadingIcon, 36 GlTable, 37 PaginationBar, 38 ImportStatus, 39 TimeAgo, 40 }, 41 42 data() { 43 return { 44 loading: true, 45 historyItems: [], 46 paginationConfig: { 47 page: 1, 48 perPage: DEFAULT_PER_PAGE, 49 }, 50 pageInfo: {}, 51 }; 52 }, 53 54 fields: [ 55 tableCell({ 56 key: 'source_full_path', 57 label: s__('BulkImport|Source group'), 58 thClass: `${DEFAULT_TH_CLASSES} gl-w-30p`, 59 }), 60 tableCell({ 61 key: 'destination_name', 62 label: s__('BulkImport|New group'), 63 thClass: `${DEFAULT_TH_CLASSES} gl-w-40p`, 64 }), 65 tableCell({ 66 key: 'created_at', 67 label: __('Date'), 68 }), 69 tableCell({ 70 key: 'status', 71 label: __('Status'), 72 tdAttr: { 'data-qa-selector': 'import_status_indicator' }, 73 }), 74 ], 75 76 computed: { 77 hasHistoryItems() { 78 return this.historyItems.length > 0; 79 }, 80 }, 81 82 watch: { 83 paginationConfig: { 84 handler() { 85 this.loadHistoryItems(); 86 }, 87 deep: true, 88 immediate: true, 89 }, 90 }, 91 92 methods: { 93 async loadHistoryItems() { 94 try { 95 this.loading = true; 96 const { data: historyItems, headers } = await getBulkImportsHistory({ 97 page: this.paginationConfig.page, 98 per_page: this.paginationConfig.perPage, 99 }); 100 this.pageInfo = parseIntPagination(normalizeHeaders(headers)); 101 this.historyItems = historyItems; 102 } catch (e) { 103 createFlash({ message: DEFAULT_ERROR, captureError: true, error: e }); 104 } finally { 105 this.loading = false; 106 } 107 }, 108 109 getDestinationUrl({ destination_name: name, destination_namespace: namespace }) { 110 return [namespace, name].filter(Boolean).join('/'); 111 }, 112 113 getFullDestinationUrl(params) { 114 return joinPaths(gon.relative_url_root || '', this.getDestinationUrl(params)); 115 }, 116 }, 117 118 gitlabLogo: window.gon.gitlab_logo, 119}; 120</script> 121 122<template> 123 <div> 124 <div 125 class="gl-border-solid gl-border-gray-200 gl-border-0 gl-border-b-1 gl-display-flex gl-align-items-center" 126 > 127 <h1 class="gl-my-0 gl-py-4 gl-font-size-h1"> 128 <img :src="$options.gitlabLogo" class="gl-w-6 gl-h-6 gl-mb-2 gl-display-inline gl-mr-2" /> 129 {{ s__('BulkImport|Group import history') }} 130 </h1> 131 </div> 132 <gl-loading-icon v-if="loading" size="md" class="gl-mt-5" /> 133 <gl-empty-state 134 v-else-if="!hasHistoryItems" 135 :title="s__('BulkImport|No history is available')" 136 :description="s__('BulkImport|Your imported groups will appear here.')" 137 /> 138 <template v-else> 139 <gl-table 140 :fields="$options.fields" 141 :items="historyItems" 142 data-qa-selector="import_history_table" 143 class="gl-w-full" 144 > 145 <template #cell(destination_name)="{ item }"> 146 <gl-link :href="getFullDestinationUrl(item)" target="_blank"> 147 {{ getDestinationUrl(item) }} 148 </gl-link> 149 </template> 150 <template #cell(created_at)="{ value }"> 151 <time-ago :time="value" /> 152 </template> 153 <template #cell(status)="{ value, item, toggleDetails, detailsShowing }"> 154 <import-status :status="value" class="gl-display-inline-block gl-w-13" /> 155 <gl-button 156 v-if="item.failures.length" 157 class="gl-ml-3" 158 :selected="detailsShowing" 159 @click="toggleDetails" 160 >{{ __('Details') }}</gl-button 161 > 162 </template> 163 <template #row-details="{ item }"> 164 <pre>{{ item.failures }}</pre> 165 </template> 166 </gl-table> 167 <pagination-bar 168 :page-info="pageInfo" 169 class="gl-m-0 gl-mt-3" 170 @set-page="paginationConfig.page = $event" 171 @set-page-size="paginationConfig.perPage = $event" 172 /> 173 </template> 174 </div> 175</template> 176