Commit 093ba5b2 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '296179-change-empty-state-location' into 'master'

Move empty state into the threat monitoring tabs

See merge request gitlab-org/gitlab!51748
parents 0e570cc8 a6e10ea3
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import { import { GlAlert, GlIcon, GlLink, GlPopover, GlTabs, GlTab } from '@gitlab/ui';
GlAlert,
GlEmptyState,
GlIcon,
GlLink,
GlPopover,
GlSprintf,
GlTabs,
GlTab,
} from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
...@@ -17,22 +8,22 @@ import Alerts from './alerts/alerts.vue'; ...@@ -17,22 +8,22 @@ import Alerts from './alerts/alerts.vue';
import ThreatMonitoringFilters from './threat_monitoring_filters.vue'; import ThreatMonitoringFilters from './threat_monitoring_filters.vue';
import ThreatMonitoringSection from './threat_monitoring_section.vue'; import ThreatMonitoringSection from './threat_monitoring_section.vue';
import NetworkPolicyList from './network_policy_list.vue'; import NetworkPolicyList from './network_policy_list.vue';
import NoEnvironmentEmptyState from './no_environment_empty_state.vue';
export default { export default {
name: 'ThreatMonitoring', name: 'ThreatMonitoring',
components: { components: {
GlAlert, GlAlert,
GlEmptyState,
GlIcon, GlIcon,
GlLink, GlLink,
GlPopover, GlPopover,
GlSprintf,
GlTabs, GlTabs,
GlTab, GlTab,
Alerts, Alerts,
ThreatMonitoringFilters, ThreatMonitoringFilters,
ThreatMonitoringSection, ThreatMonitoringSection,
NetworkPolicyList, NetworkPolicyList,
NoEnvironmentEmptyState,
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
inject: ['documentationPath'], inject: ['documentationPath'],
...@@ -45,10 +36,6 @@ export default { ...@@ -45,10 +36,6 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
emptyStateSvgPath: {
type: String,
required: true,
},
wafNoDataSvgPath: { wafNoDataSvgPath: {
type: String, type: String,
required: true, required: true,
...@@ -122,10 +109,6 @@ export default { ...@@ -122,10 +109,6 @@ export default {
`ThreatMonitoring|Container Network Policies are not installed or have been disabled. To view `ThreatMonitoring|Container Network Policies are not installed or have been disabled. To view
this data, ensure your Network Policies are installed and enabled for your cluster.`, this data, ensure your Network Policies are installed and enabled for your cluster.`,
), ),
emptyStateDescription: s__(
`ThreatMonitoring|To view this data, ensure you have configured an environment
for this project and that at least one threat monitoring feature is enabled. %{linkStart}More information%{linkEnd}`,
),
alertText: s__( alertText: s__(
`ThreatMonitoring|The graph below is an overview of traffic coming to your `ThreatMonitoring|The graph below is an overview of traffic coming to your
application as tracked by the Web Application Firewall (WAF). View the docs application as tracked by the Web Application Firewall (WAF). View the docs
...@@ -138,22 +121,7 @@ export default { ...@@ -138,22 +121,7 @@ export default {
</script> </script>
<template> <template>
<gl-empty-state <section>
v-if="!isSetUpMaybe"
ref="emptyState"
:title="s__('ThreatMonitoring|No environments detected')"
:svg-path="emptyStateSvgPath"
>
<template #description>
<gl-sprintf :message="$options.emptyStateDescription">
<template #link="{ content }">
<gl-link :href="documentationPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</template>
</gl-empty-state>
<section v-else>
<gl-alert <gl-alert
v-if="showAlert" v-if="showAlert"
class="my-3" class="my-3"
...@@ -190,45 +158,55 @@ export default { ...@@ -190,45 +158,55 @@ export default {
<alerts /> <alerts />
</gl-tab> </gl-tab>
<gl-tab ref="networkPolicyTab" :title="s__('ThreatMonitoring|Policies')"> <gl-tab ref="networkPolicyTab" :title="s__('ThreatMonitoring|Policies')">
<no-environment-empty-state v-if="!isSetUpMaybe" />
<network-policy-list <network-policy-list
v-else
:documentation-path="documentationPath" :documentation-path="documentationPath"
:new-policy-path="newPolicyPath" :new-policy-path="newPolicyPath"
/> />
</gl-tab> </gl-tab>
<gl-tab :title="s__('ThreatMonitoring|Statistics')"> <gl-tab
<threat-monitoring-filters /> :title="s__('ThreatMonitoring|Statistics')"
data-testid="threat-monitoring-statistics-tab"
>
<no-environment-empty-state v-if="!isSetUpMaybe" />
<template v-else>
<threat-monitoring-filters />
<threat-monitoring-section <threat-monitoring-section
ref="wafSection" ref="wafSection"
store-namespace="threatMonitoringWaf" store-namespace="threatMonitoringWaf"
:title="s__('ThreatMonitoring|Web Application Firewall')" :title="s__('ThreatMonitoring|Web Application Firewall')"
:subtitle="s__('ThreatMonitoring|Requests')" :subtitle="s__('ThreatMonitoring|Requests')"
:anomalous-title="s__('ThreatMonitoring|Anomalous Requests')" :anomalous-title="s__('ThreatMonitoring|Anomalous Requests')"
:nominal-title="s__('ThreatMonitoring|Total Requests')" :nominal-title="s__('ThreatMonitoring|Total Requests')"
:y-legend="s__('ThreatMonitoring|Requests')" :y-legend="s__('ThreatMonitoring|Requests')"
:chart-empty-state-title="s__('ThreatMonitoring|Application firewall not detected')" :chart-empty-state-title="s__('ThreatMonitoring|Application firewall not detected')"
:chart-empty-state-text="$options.wafChartEmptyStateDescription" :chart-empty-state-text="$options.wafChartEmptyStateDescription"
:chart-empty-state-svg-path="wafNoDataSvgPath" :chart-empty-state-svg-path="wafNoDataSvgPath"
:documentation-path="documentationPath" :documentation-path="documentationPath"
documentation-anchor="web-application-firewall" documentation-anchor="web-application-firewall"
/> />
<hr /> <hr />
<threat-monitoring-section <threat-monitoring-section
ref="networkPolicySection" ref="networkPolicySection"
store-namespace="threatMonitoringNetworkPolicy" store-namespace="threatMonitoringNetworkPolicy"
:title="s__('ThreatMonitoring|Container Network Policy')" :title="s__('ThreatMonitoring|Container Network Policy')"
:subtitle="s__('ThreatMonitoring|Packet Activity')" :subtitle="s__('ThreatMonitoring|Packet Activity')"
:anomalous-title="s__('ThreatMonitoring|Dropped Packets')" :anomalous-title="s__('ThreatMonitoring|Dropped Packets')"
:nominal-title="s__('ThreatMonitoring|Total Packets')" :nominal-title="s__('ThreatMonitoring|Total Packets')"
:y-legend="s__('ThreatMonitoring|Operations Per Second')" :y-legend="s__('ThreatMonitoring|Operations Per Second')"
:chart-empty-state-title="s__('ThreatMonitoring|Container NetworkPolicies not detected')" :chart-empty-state-title="
:chart-empty-state-text="$options.networkPolicyChartEmptyStateDescription" s__('ThreatMonitoring|Container NetworkPolicies not detected')
:chart-empty-state-svg-path="networkPolicyNoDataSvgPath" "
:documentation-path="documentationPath" :chart-empty-state-text="$options.networkPolicyChartEmptyStateDescription"
documentation-anchor="container-network-policy" :chart-empty-state-svg-path="networkPolicyNoDataSvgPath"
/> :documentation-path="documentationPath"
documentation-anchor="container-network-policy"
/>
</template>
</gl-tab> </gl-tab>
</gl-tabs> </gl-tabs>
</section> </section>
......
...@@ -5,6 +5,11 @@ export const TOTAL_REQUESTS = s__('ThreatMonitoring|Total Requests'); ...@@ -5,6 +5,11 @@ export const TOTAL_REQUESTS = s__('ThreatMonitoring|Total Requests');
export const ANOMALOUS_REQUESTS = s__('ThreatMonitoring|Anomalous Requests'); export const ANOMALOUS_REQUESTS = s__('ThreatMonitoring|Anomalous Requests');
export const TIME = s__('ThreatMonitoring|Time'); export const TIME = s__('ThreatMonitoring|Time');
export const REQUESTS = s__('ThreatMonitoring|Requests'); export const REQUESTS = s__('ThreatMonitoring|Requests');
export const NO_ENVIRONMENT_TITLE = s__('ThreatMonitoring|No environments detected');
export const EMPTY_STATE_DESCRIPTION = s__(
`ThreatMonitoring|To view this data, ensure you have configured an environment
for this project and that at least one threat monitoring feature is enabled. %{linkStart}More information%{linkEnd}`,
);
export const COLORS = { export const COLORS = {
nominal: gray700, nominal: gray700,
......
<script>
import { GlEmptyState, GlLink, GlSprintf } from '@gitlab/ui';
import { EMPTY_STATE_DESCRIPTION, NO_ENVIRONMENT_TITLE } from './constants';
export default {
i18n: { EMPTY_STATE_DESCRIPTION, NO_ENVIRONMENT_TITLE },
name: 'NoEnvironmentEmptyState',
components: {
GlEmptyState,
GlLink,
GlSprintf,
},
inject: {
documentationPath: { type: String, default: '' },
emptyStateSvgPath: { type: String, default: '' },
},
};
</script>
<template>
<gl-empty-state :title="$options.i18n.NO_ENVIRONMENT_TITLE" :svg-path="emptyStateSvgPath">
<template #description>
<gl-sprintf :message="$options.i18n.EMPTY_STATE_DESCRIPTION">
<template #link="{ content }">
<gl-link :href="documentationPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</template>
</gl-empty-state>
</template>
...@@ -46,6 +46,7 @@ export default () => { ...@@ -46,6 +46,7 @@ export default () => {
el, el,
provide: { provide: {
documentationPath, documentationPath,
emptyStateSvgPath,
projectPath, projectPath,
}, },
store, store,
...@@ -53,7 +54,6 @@ export default () => { ...@@ -53,7 +54,6 @@ export default () => {
return createElement(ThreatMonitoringApp, { return createElement(ThreatMonitoringApp, {
props: { props: {
chartEmptyStateSvgPath, chartEmptyStateSvgPath,
emptyStateSvgPath,
wafNoDataSvgPath, wafNoDataSvgPath,
networkPolicyNoDataSvgPath, networkPolicyNoDataSvgPath,
defaultEnvironmentId: parseInt(defaultEnvironmentId, 10), defaultEnvironmentId: parseInt(defaultEnvironmentId, 10),
......
---
title: Move empty state into the threat monitoring tabs
merge_request: 51748
author:
type: changed
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NoEnvironmentEmptyState component default state matches the snapshot 1`] = `
<gl-empty-state-stub
svgpath="/svgs"
title="No environments detected"
>
<gl-sprintf-stub
message="To view this data, ensure you have configured an environment for this project and that at least one threat monitoring feature is enabled. %{linkStart}More information%{linkEnd}"
/>
</gl-empty-state-stub>
`;
import { GlAlert, GlSprintf } from '@gitlab/ui'; import { GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import ThreatMonitoringAlerts from 'ee/threat_monitoring/components/alerts/alerts.vue'; import ThreatMonitoringAlerts from 'ee/threat_monitoring/components/alerts/alerts.vue';
import ThreatMonitoringApp from 'ee/threat_monitoring/components/app.vue'; import ThreatMonitoringApp from 'ee/threat_monitoring/components/app.vue';
import ThreatMonitoringFilters from 'ee/threat_monitoring/components/threat_monitoring_filters.vue'; import ThreatMonitoringFilters from 'ee/threat_monitoring/components/threat_monitoring_filters.vue';
import NetworkPolicyList from 'ee/threat_monitoring/components/network_policy_list.vue';
import NoEnvironmentEmptyState from 'ee/threat_monitoring/components/no_environment_empty_state.vue';
import createStore from 'ee/threat_monitoring/store'; import createStore from 'ee/threat_monitoring/store';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
...@@ -25,7 +28,7 @@ describe('ThreatMonitoringApp component', () => { ...@@ -25,7 +28,7 @@ describe('ThreatMonitoringApp component', () => {
let store; let store;
let wrapper; let wrapper;
const factory = ({ propsData, provide = {}, state, options } = {}) => { const factory = ({ propsData, provide = {}, state, stubs = {} } = {}) => {
store = createStore(); store = createStore();
Object.assign(store.state.threatMonitoring, { Object.assign(store.state.threatMonitoring, {
environmentsEndpoint, environmentsEndpoint,
...@@ -36,38 +39,41 @@ describe('ThreatMonitoringApp component', () => { ...@@ -36,38 +39,41 @@ describe('ThreatMonitoringApp component', () => {
jest.spyOn(store, 'dispatch').mockImplementation(); jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = shallowMount(ThreatMonitoringApp, { wrapper = extendedWrapper(
propsData: { shallowMount(ThreatMonitoringApp, {
defaultEnvironmentId, propsData: {
chartEmptyStateSvgPath, defaultEnvironmentId,
emptyStateSvgPath, chartEmptyStateSvgPath,
wafNoDataSvgPath, emptyStateSvgPath,
networkPolicyNoDataSvgPath, wafNoDataSvgPath,
newPolicyPath, networkPolicyNoDataSvgPath,
showUserCallout: true, newPolicyPath,
userCalloutId, showUserCallout: true,
userCalloutsPath, userCalloutId,
...propsData, userCalloutsPath,
}, ...propsData,
provide: { },
documentationPath, provide: {
glFeatures: { threatMonitoringAlerts: false }, documentationPath,
...provide, glFeatures: { threatMonitoringAlerts: false },
}, ...provide,
store, },
...options, store,
}); stubs,
}),
);
}; };
const findAlert = () => wrapper.find(GlAlert); const findAlert = () => wrapper.find(GlAlert);
const findAlertsView = () => wrapper.find(ThreatMonitoringAlerts); const findAlertsView = () => wrapper.find(ThreatMonitoringAlerts);
const findNetworkPolicyList = () => wrapper.find(NetworkPolicyList);
const findFilters = () => wrapper.find(ThreatMonitoringFilters); const findFilters = () => wrapper.find(ThreatMonitoringFilters);
const findWafSection = () => wrapper.find({ ref: 'wafSection' }); const findWafSection = () => wrapper.find({ ref: 'wafSection' });
const findNetworkPolicySection = () => wrapper.find({ ref: 'networkPolicySection' }); const findNetworkPolicySection = () => wrapper.find({ ref: 'networkPolicySection' });
const findEmptyState = () => wrapper.find({ ref: 'emptyState' }); const findNoEnvironmentEmptyStates = () => wrapper.findAll(NoEnvironmentEmptyState);
const findEmptyStateMessage = () => wrapper.find(GlSprintf);
const findNetworkPolicyTab = () => wrapper.find({ ref: 'networkPolicyTab' }); const findNetworkPolicyTab = () => wrapper.find({ ref: 'networkPolicyTab' });
const findAlertTab = () => wrapper.find('[data-testid="threat-monitoring-alerts-tab"]'); const findAlertTab = () => wrapper.findByTestId('threat-monitoring-alerts-tab');
const findStatisticsTab = () => wrapper.findByTestId('threat-monitoring-statistics-tab');
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -82,6 +88,7 @@ describe('ThreatMonitoringApp component', () => { ...@@ -82,6 +88,7 @@ describe('ThreatMonitoringApp component', () => {
propsData: { propsData: {
defaultEnvironmentId: invalidEnvironmentId, defaultEnvironmentId: invalidEnvironmentId,
}, },
stubs: { GlTabs: false },
}); });
}); });
...@@ -89,13 +96,21 @@ describe('ThreatMonitoringApp component', () => { ...@@ -89,13 +96,21 @@ describe('ThreatMonitoringApp component', () => {
expect(store.dispatch).not.toHaveBeenCalled(); expect(store.dispatch).not.toHaveBeenCalled();
}); });
it('shows only the empty state', () => { it('shows the "no environment" empty state', () => {
const emptyState = findEmptyState(); expect(findNoEnvironmentEmptyStates().length).toBe(2);
expect(wrapper.element).toBe(emptyState.element); });
expect(findEmptyStateMessage().exists()).toBe(true);
expect(emptyState.props()).toMatchObject({ it('shows the tabs', () => {
svgPath: emptyStateSvgPath, expect(findNetworkPolicyTab().exists()).toBe(true);
}); expect(findStatisticsTab().exists()).toBe(true);
});
it('does not show the network policy list', () => {
expect(findNetworkPolicyList().exists()).toBe(false);
});
it('does not show the threat monitoring section', () => {
expect(findNetworkPolicySection().exists()).toBe(false);
}); });
}, },
); );
......
import { shallowMount } from '@vue/test-utils';
import { GlEmptyState, GlSprintf } from '@gitlab/ui';
import {
EMPTY_STATE_DESCRIPTION,
NO_ENVIRONMENT_TITLE,
} from 'ee/threat_monitoring/components/constants';
import NoEnvironmentEmptyState from 'ee/threat_monitoring/components/no_environment_empty_state.vue';
const documentationPath = '/docs';
const emptyStateSvgPath = '/svgs';
describe('NoEnvironmentEmptyState component', () => {
let wrapper;
const findGlEmptyState = () => wrapper.find(GlEmptyState);
const findGlSprintf = () => wrapper.find(GlSprintf);
const factory = () => {
wrapper = shallowMount(NoEnvironmentEmptyState, {
provide: {
documentationPath,
emptyStateSvgPath,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('default state', () => {
beforeEach(() => {
factory();
});
it('matches the snapshot', () => {
expect(wrapper.element).toMatchSnapshot();
});
it('shows the GlEmptyState component', () => {
expect(findGlEmptyState().exists()).toBe(true);
expect(findGlEmptyState().attributes()).toMatchObject({
title: NO_ENVIRONMENT_TITLE,
svgpath: emptyStateSvgPath,
});
});
it('shows the message', () => {
expect(findGlSprintf().exists()).toBe(true);
expect(findGlSprintf().attributes('message')).toBe(EMPTY_STATE_DESCRIPTION);
});
});
});
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