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