gitlab-org--gitlab-foss/app/assets/javascripts/import_entities/components/import_status.vue

161 lines
4.1 KiB
Vue

<script>
import { GlAccordion, GlAccordionItem, GlBadge, GlIcon } from '@gitlab/ui';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { __, s__ } from '~/locale';
import { STATUSES } from '../constants';
const STATISTIC_ITEMS = {
diff_note: __('Diff notes'),
issue: __('Issues'),
label: __('Labels'),
milestone: __('Milestones'),
note: __('Notes'),
pull_request: s__('GithubImporter|Pull requests'),
pull_request_merged_by: s__('GithubImporter|PR mergers'),
pull_request_review: s__('GithubImporter|PR reviews'),
release: __('Releases'),
};
// support both camel case and snake case versions
Object.assign(STATISTIC_ITEMS, convertObjectPropsToCamelCase(STATISTIC_ITEMS));
const SCHEDULED_STATUS = {
icon: 'status-scheduled',
text: __('Pending'),
variant: 'muted',
};
const STATUS_MAP = {
[STATUSES.NONE]: {
icon: 'status-waiting',
text: __('Not started'),
variant: 'muted',
},
[STATUSES.SCHEDULING]: SCHEDULED_STATUS,
[STATUSES.SCHEDULED]: SCHEDULED_STATUS,
[STATUSES.CREATED]: SCHEDULED_STATUS,
[STATUSES.STARTED]: {
icon: 'status-running',
text: __('Importing...'),
variant: 'info',
},
[STATUSES.FAILED]: {
icon: 'status-failed',
text: __('Failed'),
variant: 'danger',
},
[STATUSES.TIMEOUT]: {
icon: 'status-failed',
text: __('Timeout'),
variant: 'danger',
},
[STATUSES.CANCELLED]: {
icon: 'status-stopped',
text: __('Cancelled'),
variant: 'neutral',
},
};
function isIncompleteImport(stats) {
return Object.keys(stats.fetched).some((key) => stats.fetched[key] !== stats.imported[key]);
}
export default {
name: 'ImportStatus',
components: {
GlAccordion,
GlAccordionItem,
GlBadge,
GlIcon,
},
props: {
status: {
type: String,
required: true,
},
stats: {
type: Object,
required: false,
default: () => ({ fetched: {}, imported: {} }),
},
},
computed: {
knownStats() {
const knownStatisticKeys = Object.keys(STATISTIC_ITEMS);
return Object.keys(this.stats.fetched).filter((key) => knownStatisticKeys.includes(key));
},
hasStats() {
return this.stats && this.knownStats.length > 0;
},
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 STATUS_MAP[this.status];
},
},
methods: {
getStatisticIconProps(key) {
const fetched = this.stats.fetched[key];
const imported = this.stats.imported[key];
if (fetched === imported) {
return { name: 'status-success', class: 'gl-text-green-400' };
} else if (imported === 0) {
return { name: 'status-scheduled', class: 'gl-text-gray-400' };
}
return { name: 'status-running', class: 'gl-text-blue-400' };
},
},
STATISTIC_ITEMS,
};
</script>
<template>
<div>
<div class="gl-display-inline-block gl-w-13">
<gl-badge :icon="mappedStatus.icon" :variant="mappedStatus.variant" size="md" class="gl-mr-2">
{{ mappedStatus.text }}
</gl-badge>
</div>
<gl-accordion v-if="hasStats" :header-level="3">
<gl-accordion-item :title="__('Details')">
<ul class="gl-p-0 gl-list-style-none gl-font-sm">
<li v-for="key in knownStats" :key="key">
<div class="gl-display-flex gl-w-20 gl-align-items-center">
<gl-icon
:size="12"
class="gl-mr-3 gl-flex-shrink-0"
v-bind="getStatisticIconProps(key)"
/>
<span class="">{{ $options.STATISTIC_ITEMS[key] }}</span>
<span class="gl-ml-auto">
{{ stats.imported[key] || 0 }}/{{ stats.fetched[key] }}
</span>
</div>
</li>
</ul>
</gl-accordion-item>
</gl-accordion>
</div>
</template>