Commit 627da134 authored by Zack Cuddy's avatar Zack Cuddy Committed by Kushal Pandya

Geo Node Status 2.0 - Node Header

This change adds the header info
with placeholder for its details
for the Geo nodes.

This header is also collapsable and
will collapse the full node
details in a future MR.
parent 8e7780e2
<script> <script>
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import GeoNodeHeader from './header/geo_node_header.vue';
export default { export default {
name: 'GeoNodes', name: 'GeoNodes',
components: {
GeoNodeHeader,
},
props: { props: {
node: { node: {
type: Object, type: Object,
required: true, required: true,
validator: (value) =>
['id', 'name', 'geoNodeId', 'url', 'healthStatus'].every((prop) => value[prop]),
},
}, },
data() {
return {
collapsed: false,
};
}, },
computed: { computed: {
siteTitle() { siteTitle() {
return this.node.primary ? s__('Geo|Primary site') : s__('Geo|Secondary site'); return this.node.primary ? s__('Geo|Primary site') : s__('Geo|Secondary site');
}, },
}, },
methods: {
toggleCollapse() {
this.collapsed = !this.collapsed;
},
},
}; };
</script> </script>
<template> <template>
<div> <div>
<h4 class="gl-font-lg gl-my-5">{{ siteTitle }}</h4> <h4 class="gl-font-lg gl-my-5">{{ siteTitle }}</h4>
<geo-node-header :node="node" :collapsed="collapsed" @collapse="toggleCollapse" />
<p v-if="!collapsed">{{ s__('Geo|Node Details') }}</p>
</div> </div>
</template> </template>
<script>
import { GlButton, GlBadge } from '@gitlab/ui';
export default {
name: 'GeoNodeHeader',
components: {
GlButton,
GlBadge,
},
props: {
node: {
type: Object,
required: true,
},
collapsed: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
chevronIcon() {
return this.collapsed ? 'chevron-right' : 'chevron-down';
},
},
};
</script>
<template>
<div
class="gl-display-grid geo-node-header-grid-columns gl-bg-gray-10 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100 gl-border-t-1 gl-border-t-solid gl-border-t-gray-100 gl-py-3 gl-px-5"
>
<div class="gl-display-flex gl-align-items-center">
<gl-button
class="gl-mr-3 gl-p-0!"
category="tertiary"
variant="confirm"
:icon="chevronIcon"
@click="$emit('collapse')"
/>
<div
class="gl-display-flex gl-flex-direction-column gl-md-flex-direction-row gl-md-align-items-center gl-flex-fill-1"
>
<div class="gl-display-flex gl-align-items-center gl-flex-fill-1">
<gl-badge v-if="node.current" variant="info" class="gl-mr-2">{{
__('Current')
}}</gl-badge>
<h4 class="gl-font-lg">{{ node.name }}</h4>
</div>
<div class="gl-display-flex gl-align-items-center gl-flex-fill-2">
<span>{{ s__('Geo|Health Status') }}</span>
<span class="gl-ml-2">{{ __('Last Updated') }}</span>
</div>
</div>
</div>
<div class="gl-display-flex gl-align-items-center gl-justify-content-end">
<span>{{ __('Actions') }}</span>
</div>
</div>
</template>
...@@ -28,3 +28,12 @@ ...@@ -28,3 +28,12 @@
} }
} }
} }
.geo-node-header-grid-columns {
grid-template-columns: 1fr auto;
grid-gap: 1rem;
@include media-breakpoint-up(md) {
grid-template-columns: 3fr 1fr;
}
}
import { createLocalVue, shallowMount } from '@vue/test-utils'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import GeoNodes from 'ee/geo_nodes_beta/components/geo_nodes.vue'; import GeoNodes from 'ee/geo_nodes_beta/components/geo_nodes.vue';
import GeoNodeHeader from 'ee/geo_nodes_beta/components/header/geo_node_header.vue';
import { MOCK_PRIMARY_VERSION, MOCK_REPLICABLE_TYPES, MOCK_NODES } from '../mock_data'; import { MOCK_PRIMARY_VERSION, MOCK_REPLICABLE_TYPES, MOCK_NODES } from '../mock_data';
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -40,6 +41,8 @@ describe('GeoNodes', () => { ...@@ -40,6 +41,8 @@ describe('GeoNodes', () => {
const findGeoNodesContainer = () => wrapper.find('div'); const findGeoNodesContainer = () => wrapper.find('div');
const findGeoSiteTitle = () => wrapper.find('h4'); const findGeoSiteTitle = () => wrapper.find('h4');
const findGeoNodeHeader = () => wrapper.find(GeoNodeHeader);
const findGeoNodeDetails = () => wrapper.find('p');
describe('template', () => { describe('template', () => {
beforeEach(() => { beforeEach(() => {
...@@ -49,6 +52,24 @@ describe('GeoNodes', () => { ...@@ -49,6 +52,24 @@ describe('GeoNodes', () => {
it('renders the Geo Nodes Container always', () => { it('renders the Geo Nodes Container always', () => {
expect(findGeoNodesContainer().exists()).toBe(true); expect(findGeoNodesContainer().exists()).toBe(true);
}); });
it('renders the Geo Node Header always', () => {
expect(findGeoNodeHeader().exists()).toBe(true);
});
describe('Node Details', () => {
it('renders by default', () => {
expect(findGeoNodeDetails().exists()).toBe(true);
});
it('is hidden when toggled', () => {
findGeoNodeHeader().vm.$emit('collapse');
return wrapper.vm.$nextTick(() => {
expect(findGeoNodeDetails().exists()).toBe(false);
});
});
});
}); });
describe.each` describe.each`
......
import { GlButton, GlBadge } from '@gitlab/ui';
import { createLocalVue, shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import GeoNodeHeader from 'ee/geo_nodes_beta/components/header/geo_node_header.vue';
import {
MOCK_PRIMARY_VERSION,
MOCK_REPLICABLE_TYPES,
MOCK_NODES,
} from 'ee_jest/geo_nodes_beta/mock_data';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('GeoNodeHeader', () => {
let wrapper;
const defaultProps = {
node: MOCK_NODES[0],
collapsed: false,
};
const createComponent = (initialState, props) => {
const store = new Vuex.Store({
state: {
primaryVersion: MOCK_PRIMARY_VERSION.version,
primaryRevision: MOCK_PRIMARY_VERSION.revision,
replicableTypes: MOCK_REPLICABLE_TYPES,
...initialState,
},
});
wrapper = shallowMount(GeoNodeHeader, {
localVue,
store,
propsData: {
...defaultProps,
...props,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
const findHeaderCollapseButton = () => wrapper.find(GlButton);
const findCurrentNodeBadge = () => wrapper.find(GlBadge);
describe('template', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
});
describe('Header Collapse Icon', () => {
describe('when not collapsed', () => {
beforeEach(() => {
createComponent();
});
it('renders the chevron-down icon', () => {
expect(findHeaderCollapseButton().attributes('icon')).toBe('chevron-down');
});
});
describe('when collapsed', () => {
beforeEach(() => {
createComponent(null, { collapsed: true });
});
it('renders the chevron-right icon', () => {
expect(findHeaderCollapseButton().attributes('icon')).toBe('chevron-right');
});
});
describe('on click', () => {
beforeEach(() => {
createComponent();
findHeaderCollapseButton().vm.$emit('click');
});
it('emits the collapse event', () => {
expect(wrapper.emitted('collapse')).toHaveLength(1);
});
});
});
describe('Current Node Badge', () => {
describe('when current node is true', () => {
beforeEach(() => {
createComponent();
});
it('renders', () => {
expect(findCurrentNodeBadge().exists()).toBe(true);
});
});
describe('when current node is false', () => {
beforeEach(() => {
createComponent(null, { node: MOCK_NODES[1] });
});
it('does not render', () => {
expect(findCurrentNodeBadge().exists()).toBe(false);
});
});
});
});
});
...@@ -13648,6 +13648,9 @@ msgstr "" ...@@ -13648,6 +13648,9 @@ msgstr ""
msgid "Geo|Go to the primary site" msgid "Geo|Go to the primary site"
msgstr "" msgstr ""
msgid "Geo|Health Status"
msgstr ""
msgid "Geo|If you want to make changes, you must visit the primary site." msgid "Geo|If you want to make changes, you must visit the primary site."
msgstr "" msgstr ""
...@@ -13681,6 +13684,9 @@ msgstr "" ...@@ -13681,6 +13684,9 @@ msgstr ""
msgid "Geo|Next sync scheduled at" msgid "Geo|Next sync scheduled at"
msgstr "" msgstr ""
msgid "Geo|Node Details"
msgstr ""
msgid "Geo|Node name can't be blank" msgid "Geo|Node name can't be blank"
msgstr "" msgstr ""
...@@ -17565,6 +17571,9 @@ msgstr "" ...@@ -17565,6 +17571,9 @@ msgstr ""
msgid "Last Seen" msgid "Last Seen"
msgstr "" msgstr ""
msgid "Last Updated"
msgstr ""
msgid "Last Used" msgid "Last Used"
msgstr "" msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment