summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/packages/details/components/package_title.vue
blob: 6b7eeacb964f5ab252162c3d8d1d05c410e1fd4e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<script>
/* eslint-disable vue/v-slot-style */
import { mapState, mapGetters } from 'vuex';
import { GlIcon, GlSprintf, GlTooltipDirective, GlBadge } from '@gitlab/ui';
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
import PackageTags from '../../shared/components/package_tags.vue';
import { numberToHumanSize } from '~/lib/utils/number_utils';
import timeagoMixin from '~/vue_shared/mixins/timeago';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import { __ } from '~/locale';

export default {
  name: 'PackageTitle',
  components: {
    TitleArea,
    GlIcon,
    GlSprintf,
    PackageTags,
    MetadataItem,
    GlBadge,
  },
  directives: {
    GlTooltip: GlTooltipDirective,
  },
  mixins: [timeagoMixin],
  i18n: {
    packageInfo: __('v%{version} published %{timeAgo}'),
  },
  data() {
    return {
      isDesktop: true,
    };
  },
  computed: {
    ...mapState(['packageEntity', 'packageFiles']),
    ...mapGetters(['packageTypeDisplay', 'packagePipeline', 'packageIcon']),
    hasTagsToDisplay() {
      return Boolean(this.packageEntity.tags && this.packageEntity.tags.length);
    },
    totalSize() {
      return numberToHumanSize(this.packageFiles.reduce((acc, p) => acc + p.size, 0));
    },
  },
  mounted() {
    this.isDesktop = GlBreakpointInstance.isDesktop();
  },
  methods: {
    dynamicSlotName(index) {
      return `metadata-tag${index}`;
    },
  },
};
</script>

<template>
  <title-area :title="packageEntity.name" :avatar="packageIcon" data-qa-selector="package_title">
    <template #sub-header>
      <gl-icon name="eye" class="gl-mr-3" />
      <gl-sprintf :message="$options.i18n.packageInfo">
        <template #version>
          {{ packageEntity.version }}
        </template>

        <template #timeAgo>
          <span v-gl-tooltip :title="tooltipTitle(packageEntity.created_at)">
            &nbsp;{{ timeFormatted(packageEntity.created_at) }}
          </span>
        </template>
      </gl-sprintf>
    </template>

    <template v-if="packageTypeDisplay" #metadata-type>
      <metadata-item data-testid="package-type" icon="package" :text="packageTypeDisplay" />
    </template>

    <template #metadata-size>
      <metadata-item data-testid="package-size" icon="disk" :text="totalSize" />
    </template>

    <template v-if="packagePipeline" #metadata-pipeline>
      <metadata-item
        data-testid="pipeline-project"
        icon="review-list"
        :text="packagePipeline.project.name"
        :link="packagePipeline.project.web_url"
      />
    </template>

    <template v-if="packagePipeline" #metadata-ref>
      <metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" />
    </template>

    <template v-if="isDesktop && hasTagsToDisplay" #metadata-tags>
      <package-tags :tag-display-limit="2" :tags="packageEntity.tags" hide-label />
    </template>

    <!-- we need to duplicate the package tags on mobile to ensure proper styling inside the flex wrap -->
    <template
      v-for="(tag, index) in packageEntity.tags"
      v-else-if="hasTagsToDisplay"
      v-slot:[dynamicSlotName(index)]
    >
      <gl-badge :key="index" class="gl-my-1" data-testid="tag-badge" variant="info" size="sm">
        {{ tag.name }}
      </gl-badge>
    </template>

    <template #right-actions>
      <slot name="delete-button"></slot>
    </template>
  </title-area>
</template>