security_dashboard_table_row.vue 4.81 KB
Newer Older
1
<script>
2
import { mapActions } from 'vuex';
Clement Ho's avatar
Clement Ho committed
3
import { GlButton, GlSkeletonLoading } from '@gitlab/ui';
4
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
5
import Icon from '~/vue_shared/components/icon.vue';
6
import VulnerabilityActionButtons from './vulnerability_action_buttons.vue';
7
import VulnerabilityIssueLink from './vulnerability_issue_link.vue';
8
9
10
11

export default {
  name: 'SecurityDashboardTableRow',
  components: {
12
    GlButton,
13
    GlSkeletonLoading,
14
15
    Icon,
    SeverityBadge,
16
    VulnerabilityActionButtons,
17
    VulnerabilityIssueLink,
18
19
20
21
  },
  props: {
    vulnerability: {
      type: Object,
22
23
24
25
26
27
28
      required: false,
      default: () => ({}),
    },
    isLoading: {
      type: Boolean,
      required: false,
      default: false,
29
30
31
32
33
34
35
    },
  },
  computed: {
    confidence() {
      return this.vulnerability.confidence || '';
    },
    severity() {
36
      return this.vulnerability.severity || ' ';
37
    },
38
    projectFullName() {
39
      const { project } = this.vulnerability;
40
      return project && project.full_name;
41
42
    },
    isDismissed() {
43
      return Boolean(this.vulnerability.dismissal_feedback);
44
45
    },
    hasIssue() {
46
47
48
      return Boolean(
        this.vulnerability.issue_feedback && this.vulnerability.issue_feedback.issue_iid,
      );
49
50
    },
    canDismissVulnerability() {
51
52
      const path = this.vulnerability.create_vulnerability_feedback_dismissal_path;
      return Boolean(path);
53
54
    },
    canCreateIssue() {
55
56
      const path = this.vulnerability.create_vulnerability_feedback_issue_path;
      return Boolean(path) && !this.hasIssue;
57
58
    },
  },
59
60
61
  methods: {
    ...mapActions('vulnerabilities', ['openModal']),
  },
62
63
64
65
};
</script>

<template>
66
  <div class="gl-responsive-table-row vulnerabilities-row p-2" :class="{ dismissed: isDismissed }">
67
    <div class="table-section section-10">
Mike Greiling's avatar
Mike Greiling committed
68
69
      <div class="table-mobile-header" role="rowheader">{{ s__('Reports|Severity') }}</div>
      <div class="table-mobile-content"><severity-badge :severity="severity" /></div>
70
71
    </div>

72
73
74
75
76
    <div class="table-section section-10 ml-md-2">
      <div class="table-mobile-header" role="rowheader">{{ s__('Reports|Confidence') }}</div>
      <div class="table-mobile-content text-capitalize">{{ confidence }}</div>
    </div>

77
    <div class="table-section flex-grow-1">
Mike Greiling's avatar
Mike Greiling committed
78
      <div class="table-mobile-header" role="rowheader">{{ s__('Reports|Vulnerability') }}</div>
79
      <div class="table-mobile-content vulnerability-info">
Mike Greiling's avatar
Mike Greiling committed
80
        <gl-skeleton-loading v-if="isLoading" class="mt-2 js-skeleton-loader" :lines="2" />
81
        <template v-else>
82
          <gl-button
83
            class="vulnerability-title d-inline"
84
            variant="blank"
85
            @click="openModal({ vulnerability })"
Mike Greiling's avatar
Mike Greiling committed
86
87
            >{{ vulnerability.name }}</gl-button
          >
88
89
90
91
          <template v-if="isDismissed">
            <icon
              v-show="vulnerability.dismissal_feedback.comment_details"
              name="comment"
92
              class="text-warning vertical-align-middle"
93
94
95
96
97
            />
            <span class="vertical-align-middle text-uppercase">{{
              s__('vulnerability|dismissed')
            }}</span>
          </template>
98
99
          <vulnerability-issue-link
            v-if="hasIssue"
100
            class="text-nowrap"
101
102
103
            :issue="vulnerability.issue_feedback"
            :project-name="vulnerability.project.name"
          />
104
          <br />
Mike Greiling's avatar
Mike Greiling committed
105
          <span v-if="projectFullName" class="vulnerability-namespace">
106
            {{ projectFullName }}
107
          </span>
108
        </template>
109
110
111
112
      </div>
    </div>

    <div class="table-section section-20">
Mike Greiling's avatar
Mike Greiling committed
113
      <div class="table-mobile-header" role="rowheader">{{ s__('Reports|Actions') }}</div>
114
      <div class="table-mobile-content action-buttons d-flex justify-content-end">
115
        <vulnerability-action-buttons
116
          v-if="!isLoading"
117
          :vulnerability="vulnerability"
118
119
120
          :can-create-issue="canCreateIssue"
          :can-dismiss-vulnerability="canDismissVulnerability"
          :is-dismissed="isDismissed"
121
122
123
124
125
126
        />
      </div>
    </div>
  </div>
</template>

127
<style scoped>
128
@media (min-width: 768px) {
129
130
131
132
  .vulnerabilities-row:last-child {
    border-bottom: 1px solid transparent;
  }

133
134
135
136
137
138
139
140
  .vulnerabilities-row:hover,
  .vulnerabilities-row:focus {
    background: #f6fafd;
    border-bottom: 1px solid #c1daf4;
    border-top: 1px solid #c1daf4;
    margin-top: -1px;
  }

141
  .vulnerabilities-row .action-buttons {
142
143
144
    opacity: 0;
  }

145
  .vulnerabilities-row:hover .action-buttons,
146
  .vulnerabilities-row:focus-within .action-buttons {
147
148
149
150
    opacity: 1;
  }
}

151
152
153
154
155
156
.vulnerability-info {
  white-space: normal;
}

.vulnerability-title {
  text-align: inherit;
157
  white-space: normal;
158
  line-height: inherit;
159
160
161
162
}

.vulnerability-namespace {
  color: #707070;
163
  font-size: 0.8em;
164
}
165
166
167
168

.dismissed .table-mobile-content:not(.action-buttons) {
  opacity: 0.5;
}
169
</style>