Commit 5a9b0af6 authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch '336882-geo-sites-filter' into 'master'

Geo Sites - Filter By Status

See merge request gitlab-org/gitlab!79070
parents 631d3e14 bd82e591
<script> <script>
import { GlLink, GlButton, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui'; import { GlLink, GlButton, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui';
import { mapActions, mapState } from 'vuex'; import { mapActions, mapState, mapGetters } from 'vuex';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import { GEO_INFO_URL, REMOVE_NODE_MODAL_ID } from '../constants'; import { GEO_INFO_URL, REMOVE_NODE_MODAL_ID } from '../constants';
import GeoNodesFilters from './geo_nodes_filters.vue';
import GeoNodes from './geo_nodes.vue'; import GeoNodes from './geo_nodes.vue';
import GeoNodesEmptyState from './geo_nodes_empty_state.vue'; import GeoNodesEmptyState from './geo_nodes_empty_state.vue';
...@@ -25,6 +26,7 @@ export default { ...@@ -25,6 +26,7 @@ export default {
GlLink, GlLink,
GlButton, GlButton,
GlLoadingIcon, GlLoadingIcon,
GeoNodesFilters,
GeoNodes, GeoNodes,
GeoNodesEmptyState, GeoNodesEmptyState,
GlModal, GlModal,
...@@ -42,14 +44,15 @@ export default { ...@@ -42,14 +44,15 @@ export default {
}, },
computed: { computed: {
...mapState(['nodes', 'isLoading']), ...mapState(['nodes', 'isLoading']),
...mapGetters(['filteredNodes']),
noNodes() { noNodes() {
return !this.nodes || this.nodes.length === 0; return !this.nodes || this.nodes.length === 0;
}, },
primaryNodes() { primaryNodes() {
return this.nodes.filter((n) => n.primary); return this.filteredNodes.filter((n) => n.primary);
}, },
secondaryNodes() { secondaryNodes() {
return this.nodes.filter((n) => !n.primary); return this.filteredNodes.filter((n) => !n.primary);
}, },
}, },
created() { created() {
...@@ -100,14 +103,19 @@ export default { ...@@ -100,14 +103,19 @@ export default {
<gl-loading-icon v-if="isLoading" size="xl" class="gl-mt-5" /> <gl-loading-icon v-if="isLoading" size="xl" class="gl-mt-5" />
<template v-if="!isLoading"> <template v-if="!isLoading">
<div v-if="!noNodes"> <div v-if="!noNodes">
<h4 class="gl-font-lg gl-my-5">{{ $options.i18n.primarySite }}</h4> <geo-nodes-filters :total-nodes="nodes.length" />
<h4 v-if="primaryNodes.length" class="gl-font-lg gl-my-5">
{{ $options.i18n.primarySite }}
</h4>
<geo-nodes <geo-nodes
v-for="node in primaryNodes" v-for="node in primaryNodes"
:key="node.id" :key="node.id"
:node="node" :node="node"
data-testid="primary-nodes" data-testid="primary-nodes"
/> />
<h4 class="gl-font-lg gl-my-5">{{ $options.i18n.secondarySite }}</h4> <h4 v-if="secondaryNodes.length" class="gl-font-lg gl-my-5">
{{ $options.i18n.secondarySite }}
</h4>
<geo-nodes <geo-nodes
v-for="node in secondaryNodes" v-for="node in secondaryNodes"
:key="node.id" :key="node.id"
......
<script>
import { GlTabs, GlTab, GlBadge } from '@gitlab/ui';
import { mapGetters, mapActions } from 'vuex';
import { s__ } from '~/locale';
import { HEALTH_STATUS_UI, STATUS_FILTER_QUERY_PARAM } from 'ee/geo_nodes/constants';
export default {
name: 'GeoNodesFilters',
i18n: {
allTab: s__('Geo|All'),
},
components: {
GlTabs,
GlTab,
GlBadge,
},
props: {
totalNodes: {
type: Number,
required: false,
default: 0,
},
},
computed: {
...mapGetters(['countNodesForStatus']),
tabs() {
const ALL_TAB = { text: this.$options.i18n.allTab, count: this.totalNodes, status: null };
const tabs = [ALL_TAB];
Object.entries(HEALTH_STATUS_UI).forEach(([status, tab]) => {
const count = this.countNodesForStatus(status);
if (count) {
tabs.push({ ...tab, count, status });
}
});
return tabs;
},
},
methods: {
...mapActions(['setStatusFilter']),
tabChange(tabIndex) {
this.setStatusFilter(this.tabs[tabIndex]?.status);
},
},
STATUS_FILTER_QUERY_PARAM,
};
</script>
<template>
<gl-tabs
sync-active-tab-with-query-params
:query-param-name="$options.STATUS_FILTER_QUERY_PARAM"
data-testid="geo-sites-filter"
@input="tabChange"
>
<gl-tab v-for="tab in tabs" :key="tab.text" :query-param-value="tab.status">
<template #title>
<span>{{ tab.text }}</span>
<gl-badge size="sm" class="gl-tab-counter-badge">{{ tab.count }}</gl-badge>
</template>
</gl-tab>
</gl-tabs>
</template>
...@@ -78,3 +78,5 @@ export const REPOSITORY = 'repository'; ...@@ -78,3 +78,5 @@ export const REPOSITORY = 'repository';
export const BLOB = 'blob'; export const BLOB = 'blob';
export const REMOVE_NODE_MODAL_ID = 'remove-node-modal'; export const REMOVE_NODE_MODAL_ID = 'remove-node-modal';
export const STATUS_FILTER_QUERY_PARAM = 'status';
...@@ -46,3 +46,7 @@ export const removeNode = ({ commit, state }) => { ...@@ -46,3 +46,7 @@ export const removeNode = ({ commit, state }) => {
commit(types.RECEIVE_NODE_REMOVAL_ERROR); commit(types.RECEIVE_NODE_REMOVAL_ERROR);
}); });
}; };
export const setStatusFilter = ({ commit }, status) => {
commit(types.SET_STATUS_FILTER, status);
};
...@@ -59,3 +59,21 @@ export const canRemoveNode = (state) => (id) => { ...@@ -59,3 +59,21 @@ export const canRemoveNode = (state) => (id) => {
return !node.primary || state.nodes.length === 1; return !node.primary || state.nodes.length === 1;
}; };
export const filteredNodes = (state) => {
if (!state.statusFilter) {
return state.nodes;
}
return state.nodes.filter((n) =>
n.healthStatus
? n.healthStatus.toLowerCase() === state.statusFilter
: state.statusFilter === 'unknown',
);
};
export const countNodesForStatus = (state) => (status) => {
return state.nodes.filter((n) =>
n.healthStatus ? n.healthStatus.toLowerCase() === status : status === 'unknown',
).length;
};
...@@ -8,3 +8,5 @@ export const UNSTAGE_NODE_REMOVAL = 'UNSTAGE_NODE_REMOVAL'; ...@@ -8,3 +8,5 @@ export const UNSTAGE_NODE_REMOVAL = 'UNSTAGE_NODE_REMOVAL';
export const REQUEST_NODE_REMOVAL = 'REQUEST_NODE_REMOVAL'; export const REQUEST_NODE_REMOVAL = 'REQUEST_NODE_REMOVAL';
export const RECEIVE_NODE_REMOVAL_SUCCESS = 'RECEIVE_NODE_REMOVAL_SUCCESS'; export const RECEIVE_NODE_REMOVAL_SUCCESS = 'RECEIVE_NODE_REMOVAL_SUCCESS';
export const RECEIVE_NODE_REMOVAL_ERROR = 'RECEIVE_NODE_REMOVAL_ERROR'; export const RECEIVE_NODE_REMOVAL_ERROR = 'RECEIVE_NODE_REMOVAL_ERROR';
export const SET_STATUS_FILTER = 'SET_STATUS_FILTER';
...@@ -33,4 +33,7 @@ export default { ...@@ -33,4 +33,7 @@ export default {
state.isLoading = false; state.isLoading = false;
state.nodeToBeRemoved = null; state.nodeToBeRemoved = null;
}, },
[types.SET_STATUS_FILTER](state, status) {
state.statusFilter = status;
},
}; };
...@@ -5,5 +5,6 @@ const createState = ({ primaryVersion, primaryRevision, replicableTypes }) => ({ ...@@ -5,5 +5,6 @@ const createState = ({ primaryVersion, primaryRevision, replicableTypes }) => ({
nodes: [], nodes: [],
isLoading: false, isLoading: false,
nodeToBeRemoved: null, nodeToBeRemoved: null,
statusFilter: null,
}); });
export default createState; export default createState;
...@@ -58,6 +58,47 @@ RSpec.describe 'GEO Nodes', :geo do ...@@ -58,6 +58,47 @@ RSpec.describe 'GEO Nodes', :geo do
expect(all('.geo-node-details-grid-columns').last).to have_link('Open replications', href: expected_url) expect(all('.geo-node-details-grid-columns').last).to have_link('Open replications', href: expected_url)
end end
context 'Status Filters', :js do
it 'defaults to the All tab when a status query is not already set' do
visit admin_geo_nodes_path
tab_count = find('[data-testid="geo-sites-filter"] .active .badge').text.to_i
results_count = page.all('[data-testid="primary-nodes"]').length + page.all('[data-testid="secondary-nodes"]').length
expect(find('[data-testid="geo-sites-filter"] .active')).to have_content('All')
expect(results_count).to be(tab_count)
end
it 'sets the correct tab when a status query is already set' do
visit admin_geo_nodes_path(status: 'unknown')
tab_count = find('[data-testid="geo-sites-filter"] .active .badge').text.to_i
results_count = page.all('[data-testid="primary-nodes"]').length + page.all('[data-testid="secondary-nodes"]').length
expect(find('[data-testid="geo-sites-filter"] .active')).not_to have_content('All')
expect(find('[data-testid="geo-sites-filter"] .active')).to have_content('Unknown')
expect(results_count).to be(tab_count)
end
it 'properly updates the query and sets the tab when a new one is clicked' do
visit admin_geo_nodes_path
tab_count = find('[data-testid="geo-sites-filter"] .active .badge').text.to_i
results_count = page.all('[data-testid="primary-nodes"]').length + page.all('[data-testid="secondary-nodes"]').length
expect(find('[data-testid="geo-sites-filter"] .active')).to have_content('All')
expect(results_count).to be(tab_count)
click_link 'Unknown'
wait_for_requests
tab_count = find('[data-testid="geo-sites-filter"] .active .badge').text.to_i
results_count = page.all('[data-testid="primary-nodes"]').length + page.all('[data-testid="secondary-nodes"]').length
expect(find('[data-testid="geo-sites-filter"] .active')).not_to have_content('All')
expect(find('[data-testid="geo-sites-filter"] .active')).to have_content('Unknown')
expect(page).to have_current_path(admin_geo_nodes_path(status: 'unknown'))
expect(results_count).to be(tab_count)
end
end
end end
end end
end end
import { GlLink, GlButton, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui'; import { GlLink, GlButton, GlLoadingIcon, GlModal, GlSprintf } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import Vuex from 'vuex'; import Vuex from 'vuex';
import GeoNodesApp from 'ee/geo_nodes/components/app.vue'; import GeoNodesApp from 'ee/geo_nodes/components/app.vue';
import GeoNodes from 'ee/geo_nodes/components/geo_nodes.vue'; import GeoNodes from 'ee/geo_nodes/components/geo_nodes.vue';
import GeoNodesEmptyState from 'ee/geo_nodes/components/geo_nodes_empty_state.vue'; import GeoNodesEmptyState from 'ee/geo_nodes/components/geo_nodes_empty_state.vue';
import { GEO_INFO_URL } from 'ee/geo_nodes/constants'; import { GEO_INFO_URL } from 'ee/geo_nodes/constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { MOCK_NODES, MOCK_NEW_NODE_URL, MOCK_EMPTY_STATE_SVG } from '../mock_data'; import { MOCK_NODES, MOCK_NEW_NODE_URL, MOCK_EMPTY_STATE_SVG } from '../mock_data';
Vue.use(Vuex); Vue.use(Vuex);
...@@ -25,24 +24,26 @@ describe('GeoNodesApp', () => { ...@@ -25,24 +24,26 @@ describe('GeoNodesApp', () => {
geoNodesEmptyStateSvg: MOCK_EMPTY_STATE_SVG, geoNodesEmptyStateSvg: MOCK_EMPTY_STATE_SVG,
}; };
const createComponent = (initialState, props) => { const createComponent = (initialState, props, getters) => {
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
...initialState, ...initialState,
}, },
actions: actionSpies, actions: actionSpies,
getters: {
filteredNodes: () => [],
...getters,
},
}); });
wrapper = extendedWrapper( wrapper = shallowMountExtended(GeoNodesApp, {
shallowMount(GeoNodesApp, { store,
store, propsData: {
propsData: { ...defaultProps,
...defaultProps, ...props,
...props, },
}, stubs: { GlSprintf },
stubs: { GlSprintf }, });
}),
);
}; };
afterEach(() => { afterEach(() => {
...@@ -58,6 +59,8 @@ describe('GeoNodesApp', () => { ...@@ -58,6 +59,8 @@ describe('GeoNodesApp', () => {
const findPrimaryGeoNodes = () => wrapper.findAllByTestId('primary-nodes'); const findPrimaryGeoNodes = () => wrapper.findAllByTestId('primary-nodes');
const findSecondaryGeoNodes = () => wrapper.findAllByTestId('secondary-nodes'); const findSecondaryGeoNodes = () => wrapper.findAllByTestId('secondary-nodes');
const findGlModal = () => wrapper.findComponent(GlModal); const findGlModal = () => wrapper.findComponent(GlModal);
const findPrimarySiteTitle = () => wrapper.findByText('Primary site');
const findSecondarySiteTitle = () => wrapper.findByText('Secondary site');
describe('template', () => { describe('template', () => {
describe('always', () => { describe('always', () => {
...@@ -89,7 +92,7 @@ describe('GeoNodesApp', () => { ...@@ -89,7 +92,7 @@ describe('GeoNodesApp', () => {
`conditionally`, `conditionally`,
({ isLoading, nodes, showLoadingIcon, showNodes, showEmptyState, showAddButton }) => { ({ isLoading, nodes, showLoadingIcon, showNodes, showEmptyState, showAddButton }) => {
beforeEach(() => { beforeEach(() => {
createComponent({ isLoading, nodes }); createComponent({ isLoading, nodes }, null, { filteredNodes: () => nodes });
}); });
describe(`when isLoading is ${isLoading} & nodes length ${nodes.length}`, () => { describe(`when isLoading is ${isLoading} & nodes length ${nodes.length}`, () => {
...@@ -117,7 +120,7 @@ describe('GeoNodesApp', () => { ...@@ -117,7 +120,7 @@ describe('GeoNodesApp', () => {
const secondaryNodes = MOCK_NODES.filter((n) => !n.primary); const secondaryNodes = MOCK_NODES.filter((n) => !n.primary);
beforeEach(() => { beforeEach(() => {
createComponent({ nodes: MOCK_NODES }); createComponent({ nodes: MOCK_NODES }, null, { filteredNodes: () => MOCK_NODES });
}); });
it('renders the correct Geo Node component for each node', () => { it('renders the correct Geo Node component for each node', () => {
...@@ -125,6 +128,28 @@ describe('GeoNodesApp', () => { ...@@ -125,6 +128,28 @@ describe('GeoNodesApp', () => {
expect(findSecondaryGeoNodes()).toHaveLength(secondaryNodes.length); expect(findSecondaryGeoNodes()).toHaveLength(secondaryNodes.length);
}); });
}); });
describe.each`
description | nodes | primaryTitle | secondaryTitle
${'with both primary and secondary nodes'} | ${MOCK_NODES} | ${true} | ${true}
${'with only primary nodes'} | ${MOCK_NODES.filter((n) => n.primary)} | ${true} | ${false}
${'with only secondary nodes'} | ${MOCK_NODES.filter((n) => !n.primary)} | ${false} | ${true}
${'with no nodes'} | ${[]} | ${false} | ${false}
`('Site Titles', ({ description, nodes, primaryTitle, secondaryTitle }) => {
describe(`${description}`, () => {
beforeEach(() => {
createComponent({ nodes }, null, { filteredNodes: () => nodes });
});
it(`should ${primaryTitle ? '' : 'not '}render the Primary Site Title`, () => {
expect(findPrimarySiteTitle().exists()).toBe(primaryTitle);
});
it(`should ${secondaryTitle ? '' : 'not '}render the Secondary Site Title`, () => {
expect(findSecondarySiteTitle().exists()).toBe(secondaryTitle);
});
});
});
}); });
describe('onCreate', () => { describe('onCreate', () => {
......
import { GlTabs, GlTab } from '@gitlab/ui';
import Vue from 'vue';
import Vuex from 'vuex';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import GeoNodesFilters from 'ee/geo_nodes/components/geo_nodes_filters.vue';
import { HEALTH_STATUS_UI, STATUS_FILTER_QUERY_PARAM } from 'ee/geo_nodes/constants';
Vue.use(Vuex);
const MOCK_TAB_COUNT = 5;
describe('GeoNodesFilters', () => {
let wrapper;
const defaultProps = {
totalNodes: MOCK_TAB_COUNT,
};
const actionSpies = {
setStatusFilter: jest.fn(),
};
const createComponent = (initialState, props, getters) => {
const store = new Vuex.Store({
state: {
...initialState,
},
actions: actionSpies,
getters: {
countNodesForStatus: () => () => 0,
...getters,
},
});
wrapper = shallowMountExtended(GeoNodesFilters, {
store,
propsData: {
...defaultProps,
...props,
},
stubs: { GlTab },
});
};
afterEach(() => {
wrapper.destroy();
});
const findGlTabs = () => wrapper.findComponent(GlTabs);
const findAllGlTabs = () => wrapper.findAllComponents(GlTab);
const findAllGlTabTitles = () => wrapper.findAllComponents(GlTab).wrappers.map((w) => w.text());
const findAllTab = () => findAllGlTabs().at(0);
describe('template', () => {
describe('always', () => {
beforeEach(() => {
createComponent();
});
it('renders the GlTabs', () => {
expect(findGlTabs().exists()).toBe(true);
});
it('allows GlTabs to manage the query param', () => {
expect(findGlTabs().attributes('syncactivetabwithqueryparams')).toBe('true');
expect(findGlTabs().attributes('queryparamname')).toBe(STATUS_FILTER_QUERY_PARAM);
});
it('renders the All tab with the totalNodes count', () => {
expect(findAllTab().exists()).toBe(true);
expect(findAllTab().text()).toBe(`All ${MOCK_TAB_COUNT}`);
});
});
describe('conditional tabs', () => {
describe('when every status has counts', () => {
beforeEach(() => {
createComponent(
null,
{ totalNodes: MOCK_TAB_COUNT },
{ countNodesForStatus: () => () => MOCK_TAB_COUNT },
);
});
it('renders every status tab', () => {
const expectedTabTitles = [
`All ${MOCK_TAB_COUNT}`,
...Object.values(HEALTH_STATUS_UI).map((tab) => `${tab.text} ${MOCK_TAB_COUNT}`),
];
expect(findAllGlTabTitles()).toStrictEqual(expectedTabTitles);
});
});
describe('when only certain statuses have counts', () => {
const MOCK_COUNTER_GETTER = () => (status) => {
if (status === 'healthy' || status === 'unhealthy') {
return MOCK_TAB_COUNT;
}
return 0;
};
beforeEach(() => {
createComponent(
null,
{ totalNodes: MOCK_TAB_COUNT },
{ countNodesForStatus: MOCK_COUNTER_GETTER },
);
});
it('renders only those status tabs', () => {
const expectedTabTitles = [
`All ${MOCK_TAB_COUNT}`,
`Healthy ${MOCK_TAB_COUNT}`,
`Unhealthy ${MOCK_TAB_COUNT}`,
];
expect(findAllGlTabTitles()).toStrictEqual(expectedTabTitles);
});
});
});
});
describe('methods', () => {
describe('when clicking each tab', () => {
const expectedTabs = [
{ status: null },
...Object.keys(HEALTH_STATUS_UI).map((status) => {
return { status };
}),
];
beforeEach(() => {
createComponent(
null,
{ totalNodes: MOCK_TAB_COUNT },
{ countNodesForStatus: () => () => MOCK_TAB_COUNT },
);
});
it('calls setStatusFilter with the correct status', () => {
for (let i = 0; i < findAllGlTabs().length; i += 1) {
findGlTabs().vm.$emit('input', i);
expect(actionSpies.setStatusFilter).toHaveBeenCalledWith(
expect.any(Object),
expectedTabs[i].status,
);
}
});
});
});
});
...@@ -241,3 +241,24 @@ export const MOCK_NODE_STATUSES_RES = [ ...@@ -241,3 +241,24 @@ export const MOCK_NODE_STATUSES_RES = [
web_geo_projects_url: 'http://127.0.0.1:3002/replication/projects', web_geo_projects_url: 'http://127.0.0.1:3002/replication/projects',
}, },
]; ];
export const MOCK_HEALTH_STATUS_NODES = [
{
healthStatus: 'Healthy',
},
{
healthStatus: 'Healthy',
},
{
healthStatus: 'Unhealthy',
},
{
healthStatus: 'Disabled',
},
{
healthStatus: 'Offline',
},
{
healthStatus: null,
},
];
...@@ -135,4 +135,15 @@ describe('GeoNodes Store Actions', () => { ...@@ -135,4 +135,15 @@ describe('GeoNodes Store Actions', () => {
}); });
}); });
}); });
describe('setStatusFilter', () => {
it('should dispatch the correct mutations', () => {
return testAction({
action: actions.setStatusFilter,
payload: 'healthy',
state,
expectedMutations: [{ type: types.SET_STATUS_FILTER, payload: 'healthy' }],
});
});
});
}); });
...@@ -7,6 +7,7 @@ import { ...@@ -7,6 +7,7 @@ import {
MOCK_PRIMARY_VERIFICATION_INFO, MOCK_PRIMARY_VERIFICATION_INFO,
MOCK_SECONDARY_VERIFICATION_INFO, MOCK_SECONDARY_VERIFICATION_INFO,
MOCK_SECONDARY_SYNC_INFO, MOCK_SECONDARY_SYNC_INFO,
MOCK_HEALTH_STATUS_NODES,
} from '../mock_data'; } from '../mock_data';
describe('GeoNodes Store Getters', () => { describe('GeoNodes Store Getters', () => {
...@@ -69,4 +70,44 @@ describe('GeoNodes Store Getters', () => { ...@@ -69,4 +70,44 @@ describe('GeoNodes Store Getters', () => {
}); });
}); });
}); });
describe.each`
status | expectedNodes
${null} | ${MOCK_HEALTH_STATUS_NODES}
${'healthy'} | ${[{ healthStatus: 'Healthy' }, { healthStatus: 'Healthy' }]}
${'unhealthy'} | ${[{ healthStatus: 'Unhealthy' }]}
${'offline'} | ${[{ healthStatus: 'Offline' }]}
${'disabled'} | ${[{ healthStatus: 'Disabled' }]}
${'unknown'} | ${[{ healthStatus: null }]}
`('filteredNodes', ({ status, expectedNodes }) => {
describe(`when status is ${status}`, () => {
beforeEach(() => {
state.nodes = MOCK_HEALTH_STATUS_NODES;
state.statusFilter = status;
});
it('should return the correct filtered array', () => {
expect(getters.filteredNodes(state)).toStrictEqual(expectedNodes);
});
});
});
describe.each`
status | expectedCount
${'healthy'} | ${2}
${'unhealthy'} | ${1}
${'offline'} | ${1}
${'disabled'} | ${1}
${'unknown'} | ${1}
`('countNodesForStatus', ({ status, expectedCount }) => {
describe(`when status is ${status}`, () => {
beforeEach(() => {
state.nodes = MOCK_HEALTH_STATUS_NODES;
});
it(`should return ${expectedCount}`, () => {
expect(getters.countNodesForStatus(state)(status)).toBe(expectedCount);
});
});
});
}); });
...@@ -105,4 +105,12 @@ describe('GeoNodes Store Mutations', () => { ...@@ -105,4 +105,12 @@ describe('GeoNodes Store Mutations', () => {
expect(state.nodeToBeRemoved).toEqual(null); expect(state.nodeToBeRemoved).toEqual(null);
}); });
}); });
describe('SET_STATUS_FILTER', () => {
it('sets statusFilter', () => {
mutations[types.SET_STATUS_FILTER](state, 'healthy');
expect(state.statusFilter).toBe('healthy');
});
});
}); });
...@@ -15797,6 +15797,9 @@ msgstr "" ...@@ -15797,6 +15797,9 @@ msgstr ""
msgid "Geo|Adjust your filters/search criteria above. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information." msgid "Geo|Adjust your filters/search criteria above. If you believe this may be an error, please refer to the %{linkStart}Geo Troubleshooting%{linkEnd} documentation for more information."
msgstr "" msgstr ""
msgid "Geo|All"
msgstr ""
msgid "Geo|All %{replicable_name}" msgid "Geo|All %{replicable_name}"
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