Commit 079d4b89 authored by Zack Cuddy's avatar Zack Cuddy Committed by Phil Hughes
Browse files

Cleanup styles for Geo Node Items

Remove unneeded class

Fix geo node status colors

Node warning styles

Cleanup geo-node-item

Cleanup node section items

Mobile friendly node actions

Tweak margins

Remove unneeded class

Starting to fix tests

Another fix

Lots of tests

Final lint and tests

Fix backend tests
parent c7fc256d
......@@ -79,53 +79,49 @@ export default {
</script>
 
<template>
<div class="geo-node-actions">
<div v-if="isSecondaryNode" class="node-action-container">
<a :href="node.geoProjectsUrl" class="btn btn-sm btn-node-action" target="_blank">
<icon v-if="!node.current" name="external-link" /> {{ __('Open projects') }}
</a>
</div>
<div class="d-flex align-items-center justify-content-end geo-node-actions">
<a v-if="isSecondaryNode" :href="node.geoProjectsUrl" class="btn btn-sm mx-1 " target="_blank">
<icon v-if="!node.current" name="external-link" /> {{ __('Open projects') }}
</a>
<template v-if="nodeActionsAllowed">
<div v-if="nodeMissingOauth" class="node-action-container">
<button type="button" class="btn btn-default btn-sm btn-node-action" @click="onRepairNode">
{{ s__('Repair authentication') }}
</button>
</div>
<div v-if="isToggleAllowed" class="node-action-container">
<button
:class="{
'btn-warning': node.enabled,
'btn-success': !node.enabled,
}"
type="button"
class="btn btn-sm btn-node-action"
@click="onToggleNode"
>
<icon :name="nodeToggleIcon" />
{{ nodeToggleLabel }}
</button>
</div>
<div v-if="nodeEditAllowed" class="node-action-container">
<a :href="node.editPath" class="btn btn-sm btn-node-action"> {{ __('Edit') }} </a>
</div>
<div class="node-action-container">
<button
v-if="isSecondaryNode"
type="button"
class="btn btn-sm btn-node-action btn-danger"
@click="onRemoveSecondaryNode"
>
{{ __('Remove') }}
</button>
<button
v-else
type="button"
class="btn btn-sm btn-node-action btn-danger"
@click="onRemovePrimaryNode"
>
{{ __('Remove') }}
</button>
</div>
<button
v-if="nodeMissingOauth"
type="button"
class="btn btn-sm btn-default mx-1"
@click="onRepairNode"
>
{{ s__('Repair authentication') }}
</button>
<button
v-if="isToggleAllowed"
:class="{
'btn-warning': node.enabled,
'btn-success': !node.enabled,
}"
type="button"
class="btn btn-sm mx-1"
@click="onToggleNode"
>
<icon :name="nodeToggleIcon" />
{{ nodeToggleLabel }}
</button>
<a v-if="nodeEditAllowed" :href="node.editPath" class="btn btn-sm mx-1"> {{ __('Edit') }} </a>
<button
v-if="isSecondaryNode"
type="button"
class="btn btn-sm btn-danger mx-1"
@click="onRemoveSecondaryNode"
>
{{ __('Remove') }}
</button>
<button
v-if="!isSecondaryNode"
type="button"
class="btn btn-sm btn-danger mx-1"
@click="onRemovePrimaryNode"
>
{{ __('Remove') }}
</button>
</template>
</div>
</template>
......@@ -126,19 +126,21 @@ export default {
</script>
 
<template>
<div v-if="!featureDisabled" class="prepend-top-15 prepend-left-10 node-detail-item">
<div class="node-detail-title">
<span>{{ itemTitle }}</span>
<div v-if="!featureDisabled" class="mt-2 ml-2 node-detail-item">
<div class="d-flex align-items-center text-secondary-700">
<span class="node-detail-title">{{ itemTitle }}</span>
<icon
v-if="hasHelpInfo"
v-popover="popoverConfig"
:size="12"
class="node-detail-help-text prepend-left-5"
class="text-primary-600 ml-1 node-detail-help-text"
name="question"
/>
</div>
<div v-if="isValueTypePlain" :class="cssClass" class="node-detail-value">{{ itemValue }}</div>
<div v-if="isValueTypeGraph" :class="{ 'd-flex': itemValueStale }" class="node-detail-value">
<div v-if="isValueTypePlain" :class="cssClass" class="mt-1 node-detail-value">
{{ itemValue }}
</div>
<div v-if="isValueTypeGraph" :class="{ 'd-flex': itemValueStale }" class="mt-1">
<stacked-progress-bar
:css-class="itemValueStale ? 'flex-fill' : ''"
:success-label="successLabel"
......@@ -153,7 +155,7 @@ export default {
v-tooltip
:title="itemValueStaleTooltip"
name="time-out"
class="prepend-left-10 detail-value-stale-icon"
class="ml-2 text-warning-500"
data-container="body"
/>
</div>
......
......@@ -66,7 +66,7 @@ export default {
</script>
 
<template>
<div class="card-body">
<div class="card-body p-0">
<node-details-section-main
:node="node"
:node-details="nodeDetails"
......@@ -85,8 +85,8 @@ export default {
:node-details="nodeDetails"
:node-type-primary="node.primary"
/>
<div v-if="hasError || hasVersionMismatch" class="node-health-message-container">
<p class="node-health-message">
<div v-if="hasError || hasVersionMismatch">
<p class="p-3 mb-0 bg-danger-100 text-danger-500">
{{ errorMessage }}
<gl-link :href="geoTroubleshootingHelpPath">{{
s__('Geo|Please refer to Geo Troubleshooting.')
......
......@@ -39,7 +39,7 @@ export default {
</script>
 
<template>
<div class="node-detail-value">
<div class="mt-1 node-detail-value">
<template v-if="eventTimeStamp">
<strong> {{ eventString }} </strong>
<span
......
......@@ -42,11 +42,10 @@ export default {
return this.isNodeHTTP || this.nodeDetailsFailed;
},
nodeStatusIconClass() {
const iconClasses = 'prepend-left-10 node-status-icon';
if (this.nodeDetailsFailed) {
return `${iconClasses} status-icon-failure`;
}
return `${iconClasses} status-icon-warning`;
return [
'ml-2',
{ 'text-danger-500': this.nodeDetailsFailed, 'text-warning-500': !this.nodeDetailsFailed },
];
},
nodeStatusIconName() {
if (this.nodeDetailsFailed) {
......@@ -70,7 +69,7 @@ export default {
<div class="card-header">
<div class="row">
<div class="col-md-8 clearfix">
<span class="d-flex float-left append-right-10">
<span class="d-flex align-items-center float-left append-right-10">
<strong class="node-url"> {{ node.url }} </strong>
<gl-loading-icon
v-if="nodeDetailsLoading || node.nodeActionActive"
......@@ -87,11 +86,17 @@ export default {
data-placement="bottom"
/>
</span>
<span class="inline node-type-badges">
<span v-if="node.current" class="node-badge current-node">
<span class="inline">
<span
v-if="node.current"
class="rounded-pill gl-font-size-12 p-1 text-white bg-success-400"
>
{{ s__('Current node') }}
</span>
<span v-if="node.primary" class="prepend-left-5 node-badge primary-node">
<span
v-if="node.primary"
class="ml-1 rounded-pill gl-font-size-12 p-1 text-white bg-primary-600"
>
{{ s__('Primary') }}
</span>
</span>
......
<script>
import icon from '~/vue_shared/components/icon.vue';
import { HEALTH_STATUS_ICON } from '../constants';
import { HEALTH_STATUS_ICON, HEALTH_STATUS_CLASS } from '../constants';
 
export default {
components: {
......@@ -14,7 +14,7 @@ export default {
},
computed: {
healthCssClass() {
return `geo-node-${this.status.toLowerCase()}`;
return HEALTH_STATUS_CLASS[this.status.toLowerCase()];
},
statusIconName() {
return HEALTH_STATUS_ICON[this.status.toLowerCase()];
......@@ -24,11 +24,11 @@ export default {
</script>
 
<template>
<div class="prepend-top-15 detail-section-item">
<div class="node-detail-title">{{ s__('GeoNodes|Health status') }}</div>
<div :class="healthCssClass" class="node-detail-value node-health-status">
<div class="mt-2 detail-section-item">
<div class="text-secondary-700 node-detail-title">{{ s__('GeoNodes|Health status') }}</div>
<div :class="healthCssClass" class="mt-1 d-flex align-items-center node-health-status">
<icon :size="16" :name="statusIconName" />
<span class="status-text prepend-left-5"> {{ status }} </span>
<span class="status-text ml-2"> {{ status }} </span>
</div>
</div>
</template>
......@@ -78,7 +78,7 @@ export default {
</script>
 
<template>
<div :class="{ 'node-action-active': node.nodeActionActive }" class="card geo-node-item">
<div :class="{ 'node-action-active': node.nodeActionActive }" class="card">
<geo-node-header
:node="node"
:node-details="nodeDetails"
......@@ -93,8 +93,8 @@ export default {
:node-actions-allowed="nodeActionsAllowed"
:geo-troubleshooting-help-path="geoTroubleshootingHelpPath"
/>
<div v-if="isNodeDetailsFailed" class="node-health-message-container">
<p class="node-health-message">
<div v-if="isNodeDetailsFailed">
<p class="p-3 mb-0 bg-danger-100 text-danger-500">
{{ errorMessage
}}<gl-link :href="geoTroubleshootingHelpPath">{{
s__('Geo|Please refer to Geo Troubleshooting.')
......
......@@ -108,18 +108,18 @@ export default {
</script>
 
<template>
<div class="node-detail-value">
<span v-if="syncStatusUnavailable" class="node-detail-value-bold"> {{ __('Unknown') }} </span>
<div class="mt-1 node-sync-settings">
<strong v-if="syncStatusUnavailable"> {{ __('Unknown') }} </strong>
<span
v-else
v-tooltip
:title="syncStatusTooltip"
class="node-sync-settings"
class="d-flex align-items-center"
data-placement="bottom"
>
<strong>{{ syncType }}</strong>
<icon name="retry" class="sync-status-icon prepend-left-5" />
<span v-if="!eventTimestampEmpty" class="sync-status-event-info prepend-left-5">
<icon name="retry" class="ml-2" />
<span v-if="!eventTimestampEmpty" class="ml-2">
{{ syncStatusEventInfo }}
</span>
</span>
......
......@@ -46,13 +46,13 @@ export default {
</script>
 
<template>
<div class="row-fluid clearfix node-detail-section primary-section">
<div class="col-md-8 section-items-container">
<div class="detail-section-item node-version">
<div class="node-detail-title">{{ s__('GeoNodes|GitLab version') }}</div>
<div class="row-fluid clearfix py-3 primary-section">
<div class="col-md-8">
<div>
<div class="text-secondary-700 node-detail-title">{{ s__('GeoNodes|GitLab version') }}</div>
<div
:class="{ 'node-detail-value-error': versionMismatch }"
class="node-detail-value node-detail-value-bold"
:class="{ 'text-danger-500': versionMismatch }"
class="mt-1 font-weight-bold node-detail-value"
>
{{ nodeVersion }}
</div>
......
......@@ -54,7 +54,7 @@ export default {
itemTitle: s__('GeoNodes|Replication slot WAL'),
itemValue: numberToHumanSize(this.nodeDetails.replicationSlotWAL),
itemValueType: VALUE_TYPE.PLAIN,
cssClass: 'node-detail-value-bold',
cssClass: 'font-weight-bold',
});
}
 
......@@ -63,7 +63,7 @@ export default {
itemTitle: s__('GeoNodes|Internal URL'),
itemValue: this.node.internalUrl,
itemValueType: VALUE_TYPE.PLAIN,
cssClass: 'node-detail-value-bold',
cssClass: 'font-weight-bold',
});
}
 
......@@ -76,7 +76,7 @@ export default {
itemTitle: s__('GeoNodes|Storage config'),
itemValue: this.storageShardsStatus,
itemValueType: VALUE_TYPE.PLAIN,
cssClass: this.storageShardsCssClass,
cssClass: this.storageShardsCssClass.join(' '),
},
];
},
......@@ -89,10 +89,7 @@ export default {
: s__('GeoNodes|Does not match the primary storage configuration');
},
storageShardsCssClass() {
const cssClass = 'node-detail-value-bold';
return !this.nodeDetails.storageShardsMatch
? `${cssClass} node-detail-value-error`
: cssClass;
return ['font-weight-bold', { 'text-danger-500': !this.nodeDetails.storageShardsMatch }];
},
},
methods: {
......@@ -104,17 +101,14 @@ export default {
</script>
 
<template>
<div class="row-fluid clearfix node-detail-section other-section">
<div class="row-fluid clearfix py-3 border-top border-color-default other-section">
<div class="col-md-12">
<section-reveal-button
:button-title="__('Other information')"
@toggleButton="handleSectionToggle"
/>
</div>
<div
v-show="showSectionItems"
class="col-md-6 prepend-left-15 prepend-top-10 section-items-container"
>
<div v-if="showSectionItems" class="col-md-6 ml-2 mt-2 section-items-container">
<geo-node-detail-item
v-for="(nodeDetailItem, index) in nodeDetailItems"
:key="index"
......
......@@ -130,17 +130,14 @@ export default {
</script>
 
<template>
<div class="row-fluid clearfix node-detail-section sync-section">
<div class="row-fluid clearfix py-3 border-top border-color-default sync-section">
<div class="col-md-12">
<section-reveal-button
:button-title="__('Sync information')"
@toggleButton="handleSectionToggle"
/>
</div>
<div
v-show="showSectionItems"
class="col-md-6 prepend-left-15 prepend-top-10 section-items-container"
>
<div v-if="showSectionItems" class="col-md-6 ml-2 mt-2 section-items-container">
<geo-node-detail-item
v-for="(nodeDetailItem, index) in nodeDetailItems"
:key="index"
......
......@@ -113,7 +113,7 @@ export default {
</script>
 
<template>
<div class="row-fluid clearfix node-detail-section verification-section">
<div class="row-fluid clearfix py-3 border-top border-color-default verification-section">
<div class="col-md-12">
<section-reveal-button
:button-title="__('Verification information')"
......@@ -121,7 +121,7 @@ export default {
/>
</div>
<template v-if="showSectionItems">
<div class="col-md-6 prepend-left-15 prepend-top-10 section-items-container">
<div class="col-md-6 ml-2 mt-2 section-items-container">
<geo-node-detail-item
v-for="(nodeDetailItem, index) in nodeDetailItems"
:key="index"
......
......@@ -31,7 +31,7 @@ export default {
</script>
 
<template>
<button class="btn-link btn-show-section" type="button" @click="onClickButton">
<button class="btn-link d-flex align-items-center" type="button" @click="onClickButton">
<icon :size="16" :name="toggleButtonIcon" />
<span class="prepend-left-8">{{ buttonTitle }}</span>
</button>
......
......@@ -23,6 +23,14 @@ export const HEALTH_STATUS_ICON = {
offline: 'status_canceled',
};
 
export const HEALTH_STATUS_CLASS = {
healthy: 'text-success-500',
unhealthy: 'text-danger-500',
disabled: 'text-secondary-950',
unknown: 'cdark',
offline: 'cdark',
};
export const TIME_DIFF = {
FIVE_MINS: 300,
HOUR: 3600,
......
.node-badge {
color: $white-light;
padding: 1px $gl-padding-8;
font-size: $label-font-size;
border-radius: $label-border-radius;
@media (max-width: map-get($grid-breakpoints, sm)) {
.geo-node-actions {
flex-direction: column;
margin: 0 1rem;
 
&.primary-node {
background-color: $blue-600;
}
&.current-node {
background-color: $green-400;
}
}
.geo-node-healthy {
color: $green-500;
}
.geo-node-unhealthy {
color: $red-500;
}
.geo-node-offline {
color: $gray-950;
}
.geo-node-disabled {
color: $gray-darkest;
}
.geo-node-unknown {
color: $gray-darkest;
}
.geo-node-item {
.node-status-icon {
height: 35px;
}
.status-icon-warning {
fill: $orange-500;
}
.status-icon-failure {
fill: $red-500;
}
.card-body {
padding: 0;
.node-detail-section {
padding: $gl-padding 0;
&.sync-section,
&.verification-section,
&.other-section {
border-top: 1px solid $border-color;
}
.btn-show-section {
padding: 0;
}
}
}
.node-health-message-container {
max-height: $dropdown-max-height;
overflow-y: auto;
.node-health-message {
margin-bottom: 0;
padding: $gl-padding;
background-color: $red-100;
color: $red-500;
}
}
}
.node-detail-section {
.detail-section-item,
.section-items-container {
.node-detail-title {
color: $gray-700;
.node-detail-help-text {
color: $blue-600;
}
.tooltip .tooltip-inner {
text-align: left;
}
}
.node-detail-value {
margin-top: 4px;
}
.detail-value-stale-icon {
color: $orange-500;
}
.node-detail-value-bold {
font-weight: $gl-font-weight-bold;
}
.node-detail-value-error {
color: $red-500;
}
}
.section-items-container {
display: inline-block;
.node-detail-item {
&:first-child {
margin-top: 0;
}
}
@include media-breakpoint-down(sm) {
width: 95%;
}
}
}
.node-detail-title,
.node-health-status,
.node-sync-settings,
.node-detail-section .btn-show-section {
display: flex;
align-items: center;
}
.geo-node-actions {
display: inline-flex;
justify-content: center;
float: right;
.node-action-container {
margin: 0 5px;
&:last-child {
margin-right: $gl-padding;
}
}
@include media-breakpoint-down(sm) {
display: block;
width: 100%;
.node-action-container {
width: 100%;
margin: 0;
margin-top: 10px;
padding: 0 10px;
}
.btn-node-action {