diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 13:00:54 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-04-20 13:00:54 +0300 |
commit | 3cccd102ba543e02725d247893729e5c73b38295 (patch) | |
tree | f36a04ec38517f5deaaacb5acc7d949688d1e187 /app/assets/javascripts/import_entities/components/import_status.vue | |
parent | 205943281328046ef7b4528031b90fbda70c75ac (diff) |
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'app/assets/javascripts/import_entities/components/import_status.vue')
-rw-r--r-- | app/assets/javascripts/import_entities/components/import_status.vue | 133 |
1 files changed, 129 insertions, 4 deletions
diff --git a/app/assets/javascripts/import_entities/components/import_status.vue b/app/assets/javascripts/import_entities/components/import_status.vue index cc6a057f587..9262a4e1e95 100644 --- a/app/assets/javascripts/import_entities/components/import_status.vue +++ b/app/assets/javascripts/import_entities/components/import_status.vue @@ -1,10 +1,66 @@ <script> -import { GlIcon } from '@gitlab/ui'; -import STATUS_MAP from '../constants'; +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.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: { @@ -12,19 +68,88 @@ export default { 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> - <gl-icon :name="mappedStatus.icon" :class="mappedStatus.iconClass" :size="12" class="gl-mr-2" /> - <span>{{ mappedStatus.text }}</span> + <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> |