Skip to content

Commit

Permalink
Enh/readniness chips (gardener#1190)
Browse files Browse the repository at this point in the history
* Moved shoot condition metadata logic from StatusTags to StatusTag (patent) component
Sort readiness chips by name

* Left align readiness tags ( makes not much difference for regular projects but improves overview if additional chips are present for only some of the clusters)
Fill chips that have an error state
Icons for readiness chips

* Do not show icon for healthy readiness chips

* Fixed tests (logic moved to parent component)

* Added additional tests to meet coverage

* Fixed lint errors

* Fixed: Show showAdminOnly only for operators

* fixed icon margin
  • Loading branch information
grolu authored May 6, 2022
1 parent 04de14e commit fa4269a
Show file tree
Hide file tree
Showing 6 changed files with 312 additions and 173 deletions.
2 changes: 1 addition & 1 deletion frontend/src/components/ShootListRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ SPDX-License-Identifier: Apache-2.0
</div>
</template>
<template v-if="cell.header.value === 'readiness'">
<div class="d-flex justify-center pr-4">
<div class="d-flex pr-4">
<status-tags :shoot-item="shootItem"></status-tags>
</div>
</template>
Expand Down
127 changes: 51 additions & 76 deletions frontend/src/components/StatusTag.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,24 @@ SPDX-License-Identifier: Apache-2.0
<div v-if="visible">
<g-popper
@input="onPopperInput"
:title="tag.name"
:title="condition.name"
:toolbar-color="color"
:popper-key="popperKeyWithType"
:placement="popperPlacement"
:disabled="!tag.message">
:disabled="!condition.message">
<template v-slot:popperRef>
<div>
<v-tooltip top max-width="400px" :disabled="tooltipDisabled">
<template v-slot:activator="{ on }">
<v-chip
v-on="on"
class="status-tag"
:class="{ 'cursor-pointer': tag.message }"
outlined
:text-color="color"
:class="{ 'cursor-pointer': condition.message }"
:outlined="!isError"
:text-color="textColor"
small
:color="color">
<v-icon v-if="isUserError" small left>mdi-account-alert</v-icon>
<v-icon v-if="chipIcon" x-small left class="chip-icon">{{chipIcon}}</v-icon>
{{chipText}}
</v-chip>
</template>
Expand All @@ -48,7 +48,7 @@ SPDX-License-Identifier: Apache-2.0
:status-title="chipStatus"
:last-message="nonErrorMessage"
:error-descriptions="errorDescriptions"
:last-transition-time="tag.lastTransitionTime"
:last-transition-time="condition.lastTransitionTime"
:secret-binding-name="secretBindingName"
:namespace="namespace"
/>
Expand All @@ -57,17 +57,8 @@ SPDX-License-Identifier: Apache-2.0
</template>

<script>
import { mapGetters, mapState, mapMutations } from 'vuex'
import { mapGetters } from 'vuex'
import get from 'lodash/get'
import join from 'lodash/join'
import map from 'lodash/map'
import split from 'lodash/split'
import dropRight from 'lodash/dropRight'
import last from 'lodash/last'
import first from 'lodash/first'
import snakeCase from 'lodash/snakeCase'
import includes from 'lodash/includes'
import upperFirst from 'lodash/upperFirst'
import isEmpty from 'lodash/isEmpty'
import filter from 'lodash/filter'

Expand Down Expand Up @@ -106,15 +97,11 @@ export default {
}
},
computed: {
...mapState([
'cfg',
'conditionCache'
]),
...mapGetters([
'isAdmin'
]),
chipText () {
return this.tag.shortName || ''
return this.condition.shortName || ''
},
chipStatus () {
if (this.isError) {
Expand All @@ -131,60 +118,69 @@ export default {
},
chipTooltip () {
return {
title: this.tag.name,
title: this.condition.name,
status: this.chipStatus,
description: this.tag.description,
userErrorCodeObjects: filter(objectsFromErrorCodes(this.tag.codes), { userError: true })
description: this.condition.description,
userErrorCodeObjects: filter(objectsFromErrorCodes(this.condition.codes), { userError: true })
}
},
chipIcon () {
if (this.isUserError) {
return 'mdi-account-alert-outline'
}
if (this.isError) {
return 'mdi-alert-circle-outline'
}
if (this.isUnknown) {
return 'mdi-help-circle-outline'
}
if (this.isProgressing && this.isAdmin) {
return 'mdi-progress-alert'
}

return ''
},
isError () {
if (this.tag.status === 'False' || !isEmpty(this.tag.codes)) {
if (this.condition.status === 'False' || !isEmpty(this.condition.codes)) {
return true
}
return false
},
isUnknown () {
if (this.tag.status === 'Unknown') {
if (this.condition.status === 'Unknown') {
return true
}
return false
},
isProgressing () {
if (this.tag.status === 'Progressing') {
if (this.condition.status === 'Progressing') {
return true
}
return false
},
isUserError () {
return isUserError(this.tag.codes)
return isUserError(this.condition.codes)
},
errorDescriptions () {
if (this.isError) {
return [
{
description: this.tag.message,
errorCodeObjects: objectsFromErrorCodes(this.tag.codes)
description: this.condition.message,
errorCodeObjects: objectsFromErrorCodes(this.condition.codes)
}
]
}
return undefined
},
nonErrorMessage () {
if (!this.isError) {
return this.tag.message
return this.condition.message
}
return undefined
},
popperKeyWithType () {
return `statusTag_${this.popperKey}`
},
tag () {
const { lastTransitionTime, message, status, type, codes } = this.condition
const id = type
const { displayName: name, shortName, description } = this.conditionMetadataFromType(type)

return { id, name, shortName, description, message, lastTransitionTime, status, codes }
},
color () {
if (this.isError) {
return 'error'
Expand All @@ -197,12 +193,15 @@ export default {
}
return 'primary'
},
textColor () {
if (this.isError) {
return 'white'
}
return this.color
},
visible () {
if (!this.isAdmin) {
const { type } = this.condition

const conditionMetadata = this.conditionMetadataFromType(type)
return !get(conditionMetadata, 'showAdminOnly', false)
return !get(this.condition, 'showAdminOnly', false)
}
return true
},
Expand All @@ -211,35 +210,6 @@ export default {
}
},
methods: {
...mapMutations([
'setCondition'
]),
conditionMetadataFromType (type) {
const condition = this.conditionCache[type]
if (condition) {
return condition
}

const dropSuffixes = [
'Available',
'Healthy',
'Ready',
'Availability'
]
let conditionComponents = snakeCase(type)
conditionComponents = split(conditionComponents, '_')
conditionComponents = map(conditionComponents, upperFirst)
if (includes(dropSuffixes, last(conditionComponents))) {
conditionComponents = dropRight(conditionComponents)
}

const displayName = join(conditionComponents, ' ')
const shortName = join(map(conditionComponents, first), '')
const conditionMetaData = { displayName, shortName }
this.setCondition({ conditionKey: type, conditionValue: conditionMetaData })

return conditionMetaData
},
onPopperInput (value) {
this.popperVisible = value
}
Expand All @@ -259,12 +229,17 @@ export default {

.status-tag ::v-deep .v-chip__content {
margin: -4px;

.chip-icon {
margin-left: -4px;
margin-right: 1px;
}
}

::v-deep .v-card {
.v-card__text {
padding: 0px;
text-align: left;
.v-card__text {
padding: 0px;
text-align: left;
}
}
}
</style>
65 changes: 60 additions & 5 deletions frontend/src/components/StatusTags.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ SPDX-License-Identifier: Apache-2.0
<template>
<div class="d-flex flex-nowrap justify-center">
<status-tag
v-for="condition in filteredConditions"
v-for="condition in conditions"
:condition="condition"
:popper-key="condition.type"
:key="condition.type"
:popper-key="condition.id"
:key="condition.id"
:popper-placement="popperPlacement"
:secret-binding-name="shootSecretBindingName"
:namespace="shootNamespace">
Expand All @@ -19,9 +19,20 @@ SPDX-License-Identifier: Apache-2.0
</template>

<script>
import { mapState, mapMutations } from 'vuex'
import join from 'lodash/join'
import map from 'lodash/map'
import split from 'lodash/split'
import dropRight from 'lodash/dropRight'
import last from 'lodash/last'
import first from 'lodash/first'
import snakeCase from 'lodash/snakeCase'
import includes from 'lodash/includes'
import upperFirst from 'lodash/upperFirst'
import StatusTag from '@/components/StatusTag'
import isEmpty from 'lodash/isEmpty'
import filter from 'lodash/filter'
import sortBy from 'lodash/sortBy'
import { shootItem } from '@/mixins/shootItem'

export default {
Expand All @@ -35,11 +46,55 @@ export default {
},
mixins: [shootItem],
computed: {
filteredConditions () {
...mapState([
'conditionCache'
]),
conditions () {
if (isEmpty(this.shootConditions)) {
return []
}
return filter(this.shootConditions, condition => !!condition.lastTransitionTime)

const shootConditions = filter(this.shootConditions, condition => !!condition.lastTransitionTime)
const conditions = map(shootConditions, condition => {
const { lastTransitionTime, message, status, type, codes } = condition
const id = type
const { displayName: name, shortName, description, showAdminOnly } = this.getCondition(condition.type)

return { id, name, shortName, description, message, lastTransitionTime, status, codes, showAdminOnly }
})

return sortBy(conditions, 'shortName')
}
},
methods: {
...mapMutations([
'setCondition'
]),
getCondition (type) {
const condition = this.conditionCache[type]
if (condition) {
return condition
}

const dropSuffixes = [
'Available',
'Healthy',
'Ready',
'Availability'
]
let conditionComponents = snakeCase(type)
conditionComponents = split(conditionComponents, '_')
conditionComponents = map(conditionComponents, upperFirst)
if (includes(dropSuffixes, last(conditionComponents))) {
conditionComponents = dropRight(conditionComponents)
}

const displayName = join(conditionComponents, ' ')
const shortName = join(map(conditionComponents, first), '')
const conditionMetaData = { displayName, shortName }
this.setCondition({ conditionKey: type, conditionValue: conditionMetaData })

return conditionMetaData
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/views/ShootList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ export default {
text: 'READINESS',
value: 'readiness',
sortable: true,
align: 'center',
align: 'start',
defaultSelected: true,
hidden: false
},
Expand Down
Loading

0 comments on commit fa4269a

Please sign in to comment.