Commit 5de26dfc authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '340339-infinite-scroll-envs' into 'master'

Add "Load more" button to environment dropdown

See merge request gitlab-org/gitlab!72731
parents d88007b9 3a3c7df1
...@@ -17,18 +17,11 @@ import getAlertsQuery from '~/graphql_shared/queries/get_alerts.query.graphql'; ...@@ -17,18 +17,11 @@ import getAlertsQuery from '~/graphql_shared/queries/get_alerts.query.graphql';
import { convertToSnakeCase } from '~/lib/utils/text_utility'; import { convertToSnakeCase } from '~/lib/utils/text_utility';
import { joinPaths } from '~/lib/utils/url_utility'; import { joinPaths } from '~/lib/utils/url_utility';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { PAGE_SIZE } from 'ee/threat_monitoring/constants';
import AlertDrawer from './alert_drawer.vue'; import AlertDrawer from './alert_drawer.vue';
import AlertFilters from './alert_filters.vue'; import AlertFilters from './alert_filters.vue';
import AlertStatus from './alert_status.vue'; import AlertStatus from './alert_status.vue';
import { import { DEFAULT_FILTERS, FIELDS, MESSAGES, STATUSES, DOMAIN, CLOSED } from './constants';
DEFAULT_FILTERS,
FIELDS,
MESSAGES,
PAGE_SIZE,
STATUSES,
DOMAIN,
CLOSED,
} from './constants';
export default { export default {
PAGE_SIZE, PAGE_SIZE,
......
...@@ -62,8 +62,6 @@ export const FIELDS = [ ...@@ -62,8 +62,6 @@ export const FIELDS = [
}, },
]; ];
export const PAGE_SIZE = 20;
export const DEFAULT_FILTERS = { statuses: ['TRIGGERED', 'ACKNOWLEDGED'] }; export const DEFAULT_FILTERS = { statuses: ['TRIGGERED', 'ACKNOWLEDGED'] };
export const DOMAIN = 'threat_monitoring'; export const DOMAIN = 'threat_monitoring';
......
<script> <script>
import { GlIcon, GlLink, GlPopover, GlTabs, GlTab } from '@gitlab/ui'; import { GlIcon, GlLink, GlPopover, GlTabs, GlTab } from '@gitlab/ui';
import { mapActions } from 'vuex'; import { mapState } from 'vuex';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import Alerts from './alerts/alerts.vue'; import Alerts from './alerts/alerts.vue';
import NoEnvironmentEmptyState from './no_environment_empty_state.vue'; import NoEnvironmentEmptyState from './no_environment_empty_state.vue';
...@@ -22,10 +22,6 @@ export default { ...@@ -22,10 +22,6 @@ export default {
}, },
inject: ['documentationPath'], inject: ['documentationPath'],
props: { props: {
defaultEnvironmentId: {
type: Number,
required: true,
},
networkPolicyNoDataSvgPath: { networkPolicyNoDataSvgPath: {
type: String, type: String,
required: true, required: true,
...@@ -35,26 +31,8 @@ export default { ...@@ -35,26 +31,8 @@ export default {
required: true, required: true,
}, },
}, },
data() { computed: {
return { ...mapState('threatMonitoring', ['hasEnvironment']),
// We require the project to have at least one available environment.
// An invalid default environment id means there there are no available
// environments, therefore infrastructure cannot be set up. A valid default
// environment id only means that infrastructure *might* be set up.
isSetUpMaybe: this.isValidEnvironmentId(this.defaultEnvironmentId),
};
},
created() {
if (this.isSetUpMaybe) {
this.setCurrentEnvironmentId(this.defaultEnvironmentId);
this.fetchEnvironments();
}
},
methods: {
...mapActions('threatMonitoring', ['fetchEnvironments', 'setCurrentEnvironmentId']),
isValidEnvironmentId(id) {
return Number.isInteger(id) && id >= 0;
},
}, },
networkPolicyChartEmptyStateDescription: s__( networkPolicyChartEmptyStateDescription: s__(
`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
...@@ -96,7 +74,7 @@ export default { ...@@ -96,7 +74,7 @@ export default {
:title="s__('ThreatMonitoring|Statistics')" :title="s__('ThreatMonitoring|Statistics')"
data-testid="threat-monitoring-statistics-tab" data-testid="threat-monitoring-statistics-tab"
> >
<no-environment-empty-state v-if="!isSetUpMaybe" /> <no-environment-empty-state v-if="!hasEnvironment" />
<template v-else> <template v-else>
<threat-monitoring-filters /> <threat-monitoring-filters />
......
<script> <script>
import { GlFormGroup, GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlButton, GlFormGroup, GlDropdown, GlDropdownItem, GlDropdownDivider } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { __ } from '~/locale';
import { ALL_ENVIRONMENT_NAME, LOADING_TEXT } from '../constants'; import { ALL_ENVIRONMENT_NAME, LOADING_TEXT } from '../constants';
export default { export default {
components: { components: {
GlButton,
GlFormGroup, GlFormGroup,
GlDropdown, GlDropdown,
GlDropdownDivider,
GlDropdownItem, GlDropdownItem,
}, },
props: { props: {
...@@ -16,25 +19,45 @@ export default { ...@@ -16,25 +19,45 @@ export default {
default: false, default: false,
}, },
}, },
i18n: {
loadMore: __('Load more'),
},
computed: { computed: {
...mapState('threatMonitoring', [ ...mapState('threatMonitoring', [
'environments',
'currentEnvironmentId',
'allEnvironments', 'allEnvironments',
'currentEnvironmentId',
'environments',
'isLoadingEnvironments', 'isLoadingEnvironments',
'hasEnvironment',
'nextPage',
]), ]),
...mapGetters('threatMonitoring', ['currentEnvironmentName', 'canChangeEnvironment']), ...mapGetters('threatMonitoring', ['currentEnvironmentName', 'canChangeEnvironment']),
environmentName() { environmentName() {
if (this.isLoadingEnvironments) { if (this.isDropdownInitiallyLoading) {
return LOADING_TEXT; return LOADING_TEXT;
} else if (this.allEnvironments && this.includeAll) { } else if (this.allEnvironments && this.includeAll) {
return ALL_ENVIRONMENT_NAME; return ALL_ENVIRONMENT_NAME;
} }
return this.currentEnvironmentName; return this.currentEnvironmentName;
}, },
isDropdownInitiallyLoading() {
return this.isLoadingEnvironments && !this.environments.length;
},
},
created() {
if (this.hasEnvironment) {
this.fetchEnvironments();
}
}, },
methods: { methods: {
...mapActions('threatMonitoring', ['setCurrentEnvironmentId', 'setAllEnvironments']), ...mapActions('threatMonitoring', [
'fetchEnvironments',
'setCurrentEnvironmentId',
'setAllEnvironments',
]),
isEnvironmentChecked(currentEnvironmentName) {
return currentEnvironmentName === this.environmentName;
},
}, },
environmentFilterId: 'threat-monitoring-environment-filter', environmentFilterId: 'threat-monitoring-environment-filter',
ALL_ENVIRONMENT_NAME, ALL_ENVIRONMENT_NAME,
...@@ -44,7 +67,6 @@ export default { ...@@ -44,7 +67,6 @@ export default {
<template> <template>
<gl-form-group <gl-form-group
:label="s__('ThreatMonitoring|Environment')" :label="s__('ThreatMonitoring|Environment')"
label-size="sm"
:label-for="$options.environmentFilterId" :label-for="$options.environmentFilterId"
> >
<gl-dropdown <gl-dropdown
...@@ -53,18 +75,35 @@ export default { ...@@ -53,18 +75,35 @@ export default {
toggle-class="gl-truncate" toggle-class="gl-truncate"
:text="environmentName" :text="environmentName"
:disabled="!canChangeEnvironment" :disabled="!canChangeEnvironment"
:loading="isLoadingEnvironments" :loading="isDropdownInitiallyLoading"
> >
<gl-dropdown-item
v-if="includeAll"
:is-check-item="true"
:is-checked="allEnvironments"
@click="setAllEnvironments"
>
{{ $options.ALL_ENVIRONMENT_NAME }}
</gl-dropdown-item>
<gl-dropdown-divider v-if="includeAll" />
<gl-dropdown-item <gl-dropdown-item
v-for="environment in environments" v-for="environment in environments"
:key="environment.id" :key="environment.id"
:is-check-item="true"
:is-checked="isEnvironmentChecked(environment.name)"
@click="setCurrentEnvironmentId(environment.id)" @click="setCurrentEnvironmentId(environment.id)"
> >
{{ environment.name }} {{ environment.name }}
</gl-dropdown-item> </gl-dropdown-item>
<gl-dropdown-item v-if="includeAll" @click="setAllEnvironments"> <gl-button
{{ $options.ALL_ENVIRONMENT_NAME }} v-if="Boolean(nextPage)"
</gl-dropdown-item> variant="link"
class="gl-w-full"
:loading="isLoadingEnvironments"
@click="fetchEnvironments"
>
{{ this.$options.i18n.loadMore }}
</gl-button>
</gl-dropdown> </gl-dropdown>
</gl-form-group> </gl-form-group>
</template> </template>
...@@ -2,12 +2,12 @@ ...@@ -2,12 +2,12 @@
import produce from 'immer'; import produce from 'immer';
import getUsersProjects from '~/graphql_shared/queries/get_users_projects.query.graphql'; import getUsersProjects from '~/graphql_shared/queries/get_users_projects.query.graphql';
import ProjectSelector from '~/vue_shared/components/project_selector/project_selector.vue'; import ProjectSelector from '~/vue_shared/components/project_selector/project_selector.vue';
import { PAGE_SIZE } from 'ee/threat_monitoring/constants';
const defaultPageInfo = { endCursor: '', hasNextPage: false }; const defaultPageInfo = { endCursor: '', hasNextPage: false };
export default { export default {
MINIMUM_QUERY_LENGTH: 3, MINIMUM_QUERY_LENGTH: 3,
PROJECTS_PER_PAGE: 20,
SEARCH_ERROR: 'SEARCH_ERROR', SEARCH_ERROR: 'SEARCH_ERROR',
QUERY_TOO_SHORT_ERROR: 'QUERY_TOO_SHORT_ERROR', QUERY_TOO_SHORT_ERROR: 'QUERY_TOO_SHORT_ERROR',
NO_RESULTS_ERROR: 'NO_RESULTS_ERROR', NO_RESULTS_ERROR: 'NO_RESULTS_ERROR',
...@@ -17,7 +17,7 @@ export default { ...@@ -17,7 +17,7 @@ export default {
variables() { variables() {
return { return {
search: this.searchQuery, search: this.searchQuery,
first: this.$options.PROJECTS_PER_PAGE, first: PAGE_SIZE,
searchNamespaces: true, searchNamespaces: true,
sort: 'similarity', sort: 'similarity',
}; };
......
<script> <script>
import { mapActions } from 'vuex';
import { isValidEnvironmentId } from '../../utils';
import PoliciesHeader from './policies_header.vue'; import PoliciesHeader from './policies_header.vue';
import PoliciesList from './policies_list.vue'; import PoliciesList from './policies_list.vue';
...@@ -9,25 +7,12 @@ export default { ...@@ -9,25 +7,12 @@ export default {
PoliciesHeader, PoliciesHeader,
PoliciesList, PoliciesList,
}, },
inject: ['defaultEnvironmentId'],
data() { data() {
return { return {
// We require the project to have at least one available environment.
// An invalid default environment id means there there are no available
// environments, therefore infrastructure cannot be set up. A valid default
// environment id only means that infrastructure *might* be set up.
shouldFetchEnvironment: isValidEnvironmentId(this.defaultEnvironmentId),
shouldUpdatePolicyList: false, shouldUpdatePolicyList: false,
}; };
}, },
created() {
if (this.shouldFetchEnvironment) {
this.setCurrentEnvironmentId(this.defaultEnvironmentId);
this.fetchEnvironments();
}
},
methods: { methods: {
...mapActions('threatMonitoring', ['fetchEnvironments', 'setCurrentEnvironmentId']),
handleUpdatePolicyList(val) { handleUpdatePolicyList(val) {
this.shouldUpdatePolicyList = val; this.shouldUpdatePolicyList = val;
}, },
...@@ -38,7 +23,6 @@ export default { ...@@ -38,7 +23,6 @@ export default {
<div> <div>
<policies-header @update-policy-list="handleUpdatePolicyList" /> <policies-header @update-policy-list="handleUpdatePolicyList" />
<policies-list <policies-list
:has-environment="shouldFetchEnvironment"
:should-update-policy-list="shouldUpdatePolicyList" :should-update-policy-list="shouldUpdatePolicyList"
@update-policy-list="handleUpdatePolicyList" @update-policy-list="handleUpdatePolicyList"
/> />
......
...@@ -59,11 +59,6 @@ export default { ...@@ -59,11 +59,6 @@ export default {
}, },
inject: ['documentationPath', 'projectPath', 'newPolicyPath'], inject: ['documentationPath', 'projectPath', 'newPolicyPath'],
props: { props: {
hasEnvironment: {
type: Boolean,
required: false,
default: false,
},
shouldUpdatePolicyList: { shouldUpdatePolicyList: {
type: Boolean, type: Boolean,
required: false, required: false,
...@@ -115,7 +110,7 @@ export default { ...@@ -115,7 +110,7 @@ export default {
}; };
}, },
computed: { computed: {
...mapState('threatMonitoring', ['currentEnvironmentId', 'allEnvironments']), ...mapState('threatMonitoring', ['allEnvironments', 'currentEnvironmentId', 'hasEnvironment']),
...mapGetters('threatMonitoring', ['currentEnvironmentGid']), ...mapGetters('threatMonitoring', ['currentEnvironmentGid']),
allPolicyTypes() { allPolicyTypes() {
return { return {
......
...@@ -66,13 +66,7 @@ export default { ...@@ -66,13 +66,7 @@ export default {
PolicyEditorLayout, PolicyEditorLayout,
DimDisableContainer, DimDisableContainer,
}, },
inject: [ inject: ['networkDocumentationPath', 'noEnvironmentSvgPath', 'projectId', 'policiesPath'],
'hasEnvironment',
'networkDocumentationPath',
'noEnvironmentSvgPath',
'projectId',
'policiesPath',
],
props: { props: {
existingPolicy: { existingPolicy: {
type: Object, type: Object,
...@@ -124,6 +118,7 @@ export default { ...@@ -124,6 +118,7 @@ export default {
'currentEnvironmentId', 'currentEnvironmentId',
'environments', 'environments',
'isLoadingEnvironments', 'isLoadingEnvironments',
'hasEnvironment',
]), ]),
...mapState('networkPolicies', [ ...mapState('networkPolicies', [
'isUpdatingPolicy', 'isUpdatingPolicy',
......
<script> <script>
import { GlAlert, GlFormGroup, GlFormSelect } from '@gitlab/ui'; import { GlAlert, GlFormGroup, GlFormSelect } from '@gitlab/ui';
import { mapActions } from 'vuex';
import { POLICY_TYPE_COMPONENT_OPTIONS } from '../constants'; import { POLICY_TYPE_COMPONENT_OPTIONS } from '../constants';
import EnvironmentPicker from '../environment_picker.vue'; import EnvironmentPicker from '../environment_picker.vue';
import NetworkPolicyEditor from './network_policy/network_policy_editor.vue'; import NetworkPolicyEditor from './network_policy/network_policy_editor.vue';
...@@ -59,11 +58,7 @@ export default { ...@@ -59,11 +58,7 @@ export default {
return !this.existingPolicy; return !this.existingPolicy;
}, },
}, },
created() {
this.fetchEnvironments();
},
methods: { methods: {
...mapActions('threatMonitoring', ['fetchEnvironments']),
setError(error) { setError(error) {
this.error = error; this.error = error;
}, },
......
...@@ -43,3 +43,5 @@ spec: ...@@ -43,3 +43,5 @@ spec:
]; ];
export const ALL_ENVIRONMENT_NAME = s__('ThreatMonitoring|All Environments'); export const ALL_ENVIRONMENT_NAME = s__('ThreatMonitoring|All Environments');
export const PAGE_SIZE = 20;
...@@ -3,6 +3,7 @@ import Vue from 'vue'; ...@@ -3,6 +3,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import ThreatMonitoringApp from './components/app.vue'; import ThreatMonitoringApp from './components/app.vue';
import { isValidEnvironmentId } from './utils';
import createStore from './store'; import createStore from './store';
Vue.use(VueApollo); Vue.use(VueApollo);
...@@ -38,9 +39,20 @@ export default () => { ...@@ -38,9 +39,20 @@ export default () => {
projectPath, projectPath,
} = el.dataset; } = el.dataset;
const environmentId = parseInt(defaultEnvironmentId, 10);
// We require the project to have at least one available environment.
// An invalid default environment id means there there are no available
// environments, therefore infrastructure cannot be set up. A valid default
// environment id only means that infrastructure *might* be set up.
const hasEnvironment = isValidEnvironmentId(environmentId);
const store = createStore(); const store = createStore();
store.dispatch('threatMonitoring/setStatisticsEndpoint', networkPolicyStatisticsEndpoint); store.dispatch('threatMonitoring/setStatisticsEndpoint', networkPolicyStatisticsEndpoint);
store.dispatch('threatMonitoring/setEnvironmentEndpoint', environmentsEndpoint); store.dispatch('threatMonitoring/setEnvironmentEndpoint', environmentsEndpoint);
store.dispatch('threatMonitoring/setHasEnvironment', hasEnvironment);
if (hasEnvironment) {
store.dispatch('threatMonitoring/setCurrentEnvironmentId', environmentId);
}
return new Vue({ return new Vue({
apolloProvider, apolloProvider,
...@@ -55,7 +67,6 @@ export default () => { ...@@ -55,7 +67,6 @@ export default () => {
return createElement(ThreatMonitoringApp, { return createElement(ThreatMonitoringApp, {
props: { props: {
networkPolicyNoDataSvgPath, networkPolicyNoDataSvgPath,
defaultEnvironmentId: parseInt(defaultEnvironmentId, 10),
newPolicyPath, newPolicyPath,
}, },
}); });
......
...@@ -32,13 +32,19 @@ export default () => { ...@@ -32,13 +32,19 @@ export default () => {
environmentId, environmentId,
} = el.dataset; } = el.dataset;
// We require the project to have at least one available environment.
// An invalid default environment id means there there are no available
// environments, therefore infrastructure cannot be set up. A valid default
// environment id only means that infrastructure *might* be set up.
const hasEnvironment = isValidEnvironmentId(parseInt(defaultEnvironmentId, 10));
const store = createStore(); const store = createStore();
store.dispatch('threatMonitoring/setEnvironmentEndpoint', environmentsEndpoint); store.dispatch('threatMonitoring/setEnvironmentEndpoint', environmentsEndpoint);
store.dispatch('networkPolicies/setEndpoints', { store.dispatch('networkPolicies/setEndpoints', {
networkPoliciesEndpoint, networkPoliciesEndpoint,
}); });
store.dispatch('threatMonitoring/setHasEnvironment', hasEnvironment);
if (environmentId !== undefined) { if (hasEnvironment && environmentId !== undefined) {
store.dispatch('threatMonitoring/setCurrentEnvironmentId', parseInt(environmentId, 10)); store.dispatch('threatMonitoring/setCurrentEnvironmentId', parseInt(environmentId, 10));
} }
...@@ -65,7 +71,6 @@ export default () => { ...@@ -65,7 +71,6 @@ export default () => {
noEnvironmentSvgPath, noEnvironmentSvgPath,
projectId, projectId,
projectPath, projectPath,
hasEnvironment: isValidEnvironmentId(parseInt(defaultEnvironmentId, 10)),
policiesPath, policiesPath,
}, },
store, store,
......
...@@ -2,6 +2,7 @@ import Vue from 'vue'; ...@@ -2,6 +2,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils'; import { parseBoolean } from '~/lib/utils/common_utils';
import { isValidEnvironmentId } from './utils';
import SecurityPoliciesApp from './components/policies/policies_app.vue'; import SecurityPoliciesApp from './components/policies/policies_app.vue';
import createStore from './store'; import createStore from './store';
...@@ -25,8 +26,19 @@ export default () => { ...@@ -25,8 +26,19 @@ export default () => {
projectPath, projectPath,
} = el.dataset; } = el.dataset;
const environmentId = parseInt(defaultEnvironmentId, 10);
// We require the project to have at least one available environment.
// An invalid default environment id means there there are no available
// environments, therefore infrastructure cannot be set up. A valid default
// environment id only means that infrastructure *might* be set up.
const hasEnvironment = isValidEnvironmentId(environmentId);
const store = createStore(); const store = createStore();
store.dispatch('threatMonitoring/setEnvironmentEndpoint', environmentsEndpoint); store.dispatch('threatMonitoring/setEnvironmentEndpoint', environmentsEndpoint);
store.dispatch('threatMonitoring/setHasEnvironment', hasEnvironment);
if (hasEnvironment) {
store.dispatch('threatMonitoring/setCurrentEnvironmentId', environmentId);
}
return new Vue({ return new Vue({
apolloProvider, apolloProvider,
...@@ -40,7 +52,6 @@ export default () => { ...@@ -40,7 +52,6 @@ export default () => {
projectPath, projectPath,
emptyFilterSvgPath, emptyFilterSvgPath,
emptyListSvgPath, emptyListSvgPath,
defaultEnvironmentId: parseInt(defaultEnvironmentId, 10),
}, },
render(createElement) { render(createElement) {
return createElement(SecurityPoliciesApp); return createElement(SecurityPoliciesApp);
......
import createFlash from '~/flash'; import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { parseIntPagination, normalizeHeaders } from '~/lib/utils/common_utils';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { PAGE_SIZE } from 'ee/threat_monitoring/constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
export const setEnvironmentEndpoint = ({ commit }, endpoint) => { export const setEnvironmentEndpoint = ({ commit }, endpoint) => {
commit(types.SET_ENDPOINT, endpoint); commit(types.SET_ENDPOINT, endpoint);
}; };
export const setHasEnvironment = ({ commit }, data) => {
commit(types.SET_HAS_ENVIRONMENT, data);
};
export const setStatisticsEndpoint = ({ commit }, endpoint) => { export const setStatisticsEndpoint = ({ commit }, endpoint) => {
commit(`threatMonitoringNetworkPolicy/${types.SET_ENDPOINT}`, endpoint, { root: true }); commit(`threatMonitoringNetworkPolicy/${types.SET_ENDPOINT}`, endpoint, { root: true });
}; };
export const requestEnvironments = ({ commit }) => commit(types.REQUEST_ENVIRONMENTS); export const requestEnvironments = ({ commit }) => commit(types.REQUEST_ENVIRONMENTS);
export const receiveEnvironmentsSuccess = ({ commit }, environments) => export const receiveEnvironmentsSuccess = ({ commit }, data) =>
commit(types.RECEIVE_ENVIRONMENTS_SUCCESS, environments); commit(types.RECEIVE_ENVIRONMENTS_SUCCESS, data);
export const receiveEnvironmentsError = ({ commit }) => { export const receiveEnvironmentsError = ({ commit }) => {
commit(types.RECEIVE_ENVIRONMENTS_ERROR); commit(types.RECEIVE_ENVIRONMENTS_ERROR);
createFlash({ createFlash({
...@@ -21,35 +27,39 @@ export const receiveEnvironmentsError = ({ commit }) => { ...@@ -21,35 +27,39 @@ export const receiveEnvironmentsError = ({ commit }) => {
}); });
}; };
const getAllEnvironments = (url, page = 1) => const getEnvironments = async (url, page = 1) => {
axios try {
.get(url, { const { data, headers } = await axios.get(url, {
params: { params: {
per_page: 100, per_page: PAGE_SIZE,
page, page,
}, },
})
.then(({ headers, data }) => {
const nextPage = headers && headers['x-next-page'];
return nextPage
? // eslint-disable-next-line promise/no-nesting
getAllEnvironments(url, nextPage).then((environments) => [
...data.environments,
...environments,
])
: data.environments;
}); });
export const fetchEnvironments = ({ state, dispatch }) => { const { nextPage } = parseIntPagination(normalizeHeaders(headers));
return { environments: data.environments, nextPage };
} catch {
throw new Error();
}
};
export const fetchEnvironments = async ({ state, dispatch }) => {
if (!state.environmentsEndpoint) { if (!state.environmentsEndpoint) {
return dispatch('receiveEnvironmentsError'); return dispatch('receiveEnvironmentsError');
} }
dispatch('requestEnvironments'); dispatch('requestEnvironments');
return getAllEnvironments(state.environmentsEndpoint) try {
.then((environments) => dispatch('receiveEnvironmentsSuccess', environments)) const data = await getEnvironments(state.environmentsEndpoint, state.nextPage);
.catch(() => dispatch('receiveEnvironmentsError'));
return dispatch('receiveEnvironmentsSuccess', {
environments: [...state.environments, ...data.environments],
nextPage: data.nextPage,
});
} catch {
return dispatch('receiveEnvironmentsError');
}
}; };
export const setCurrentEnvironmentId = ({ commit }, environmentId) => { export const setCurrentEnvironmentId = ({ commit }, environmentId) => {
......
...@@ -8,8 +8,4 @@ export const currentEnvironmentName = (state, getters) => ...@@ -8,8 +8,4 @@ export const currentEnvironmentName = (state, getters) =>
export const currentEnvironmentGid = (state, getters) => getters.currentEnvironment?.global_id; export const currentEnvironmentGid = (state, getters) => getters.currentEnvironment?.global_id;
export const canChangeEnvironment = ({ export const canChangeEnvironment = ({ environments }) => Boolean(environments.length);
isLoadingEnvironments,
isLoadingNetworkPolicyStatistics,
environments,
}) => !isLoadingEnvironments && !isLoadingNetworkPolicyStatistics && environments.length > 0;
export const SET_ENDPOINT = 'SET_ENDPOINT'; export const SET_ENDPOINT = 'SET_ENDPOINT';
export const REQUEST_ENVIRONMENTS = 'REQUEST_ENVIRONMENTS'; export const REQUEST_ENVIRONMENTS = 'REQUEST_ENVIRONMENTS';
export const RECEIVE_ENVIRONMENTS_SUCCESS = 'RECEIVE_ENVIRONMENTS_SUCCESS'; export const RECEIVE_ENVIRONMENTS_SUCCESS = 'RECEIVE_ENVIRONMENTS_SUCCESS';
export const RECEIVE_ENVIRONMENTS_ERROR = 'RECEIVE_ENVIRONMENTS_ERROR'; export const RECEIVE_ENVIRONMENTS_ERROR = 'RECEIVE_ENVIRONMENTS_ERROR';
export const SET_CURRENT_ENVIRONMENT_ID = 'SET_CURRENT_ENVIRONMENT_ID'; export const SET_CURRENT_ENVIRONMENT_ID = 'SET_CURRENT_ENVIRONMENT_ID';
export const SET_ALL_ENVIRONMENTS = 'SET_ALL_ENVIRONMENTS'; export const SET_ALL_ENVIRONMENTS = 'SET_ALL_ENVIRONMENTS';
export const SET_CURRENT_TIME_WINDOW = 'SET_CURRENT_TIME_WINDOW'; export const SET_CURRENT_TIME_WINDOW = 'SET_CURRENT_TIME_WINDOW';
export const SET_HAS_ENVIRONMENT = 'SET_HAS_ENVIRONMENT';
...@@ -8,12 +8,13 @@ export default { ...@@ -8,12 +8,13 @@ export default {
state.isLoadingEnvironments = true; state.isLoadingEnvironments = true;
state.errorLoadingEnvironments = false; state.errorLoadingEnvironments = false;
}, },
[types.RECEIVE_ENVIRONMENTS_SUCCESS](state, payload) { [types.RECEIVE_ENVIRONMENTS_SUCCESS](state, { environments, nextPage }) {
state.environments = payload; state.environments = environments;
state.nextPage = nextPage;
state.isLoadingEnvironments = false; state.isLoadingEnvironments = false;
state.errorLoadingEnvironments = false; state.errorLoadingEnvironments = false;
if (payload.length > 0 && state.currentEnvironmentId === -1) if (environments.length > 0 && state.currentEnvironmentId === -1)
state.currentEnvironmentId = payload[0].id; state.currentEnvironmentId = environments[0].id;
}, },
[types.RECEIVE_ENVIRONMENTS_ERROR](state) { [types.RECEIVE_ENVIRONMENTS_ERROR](state) {
state.isLoadingEnvironments = false; state.isLoadingEnvironments = false;
...@@ -23,10 +24,13 @@ export default { ...@@ -23,10 +24,13 @@ export default {
state.currentEnvironmentId = payload; state.currentEnvironmentId = payload;
state.allEnvironments = false; state.allEnvironments = false;
}, },
[types.SET_ALL_ENVIRONMENTS](state) {
state.allEnvironments = true;
},
[types.SET_CURRENT_TIME_WINDOW](state, payload) { [types.SET_CURRENT_TIME_WINDOW](state, payload) {
state.currentTimeWindow = payload; state.currentTimeWindow = payload;
}, },
[types.SET_ALL_ENVIRONMENTS](state) { [types.SET_HAS_ENVIRONMENT](state, payload) {
state.allEnvironments = true; state.hasEnvironment = payload;
}, },
}; };
...@@ -4,8 +4,10 @@ export default () => ({ ...@@ -4,8 +4,10 @@ export default () => ({
environmentsEndpoint: '', environmentsEndpoint: '',
environments: [], environments: [],
isLoadingEnvironments: false, isLoadingEnvironments: false,
hasEnvironment: false,
errorLoadingEnvironments: false, errorLoadingEnvironments: false,
currentEnvironmentId: -1, currentEnvironmentId: -1,
currentTimeWindow: defaultTimeRange.name, currentTimeWindow: defaultTimeRange.name,
allEnvironments: false, allEnvironments: false,
nextPage: false,
}); });
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`ThreatMonitoringApp component given there is a default environment with data renders the statistics section 1`] = ` exports[`ThreatMonitoringApp component given there are environments present passes the statistics section the correct information 1`] = `
<threat-monitoring-section-stub <threat-monitoring-section-stub
anomaloustitle="Dropped Packets" anomaloustitle="Dropped Packets"
chartemptystatesvgpath="/network-policy-no-data-svg" chartemptystatesvgpath="/network-policy-no-data-svg"
......
...@@ -7,22 +7,22 @@ import createStore from 'ee/threat_monitoring/store'; ...@@ -7,22 +7,22 @@ import createStore from 'ee/threat_monitoring/store';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { extendedWrapper } from 'helpers/vue_test_utils_helper';
const defaultEnvironmentId = 3;
const documentationPath = '/docs'; const documentationPath = '/docs';
const newPolicyPath = '/policy/new'; const newPolicyPath = '/policy/new';
const emptyStateSvgPath = '/svgs';
const networkPolicyNoDataSvgPath = '/network-policy-no-data-svg'; const networkPolicyNoDataSvgPath = '/network-policy-no-data-svg';
const environmentsEndpoint = `${TEST_HOST}/environments`; const environmentsEndpoint = `${TEST_HOST}/environments`;
const hasEnvironment = true;
const networkPolicyStatisticsEndpoint = `${TEST_HOST}/network_policy`; const networkPolicyStatisticsEndpoint = `${TEST_HOST}/network_policy`;
describe('ThreatMonitoringApp component', () => { describe('ThreatMonitoringApp component', () => {
let store; let store;
let wrapper; let wrapper;
const factory = ({ propsData, provide = {}, state, stubs = {} } = {}) => { const factory = ({ propsData, state, stubs = {} } = {}) => {
store = createStore(); store = createStore();
Object.assign(store.state.threatMonitoring, { Object.assign(store.state.threatMonitoring, {
environmentsEndpoint, environmentsEndpoint,
hasEnvironment,
networkPolicyStatisticsEndpoint, networkPolicyStatisticsEndpoint,
...state, ...state,
}); });
...@@ -32,15 +32,12 @@ describe('ThreatMonitoringApp component', () => { ...@@ -32,15 +32,12 @@ describe('ThreatMonitoringApp component', () => {
wrapper = extendedWrapper( wrapper = extendedWrapper(
shallowMount(ThreatMonitoringApp, { shallowMount(ThreatMonitoringApp, {
propsData: { propsData: {
defaultEnvironmentId,
emptyStateSvgPath,
networkPolicyNoDataSvgPath, networkPolicyNoDataSvgPath,
newPolicyPath, newPolicyPath,
...propsData, ...propsData,
}, },
provide: { provide: {
documentationPath, documentationPath,
...provide,
}, },
store, store,
stubs, stubs,
...@@ -60,55 +57,39 @@ describe('ThreatMonitoringApp component', () => { ...@@ -60,55 +57,39 @@ describe('ThreatMonitoringApp component', () => {
wrapper = null; wrapper = null;
}); });
describe.each([-1, NaN, Math.PI])( describe('given there are environments present', () => {
'given an invalid default environment id of %p',
(invalidEnvironmentId) => {
beforeEach(() => {
factory({
propsData: {
defaultEnvironmentId: invalidEnvironmentId,
},
stubs: { GlTabs: false },
});
});
it('dispatches no actions', () => {
expect(store.dispatch).not.toHaveBeenCalled();
});
it('shows the "no environment" empty state', () => {
expect(findNoEnvironmentEmptyState().exists()).toBe(true);
});
it('shows the tabs', () => {
expect(findAlertTab().exists()).toBe(true);
expect(findStatisticsTab().exists()).toBe(true);
});
it('does not show the threat monitoring section', () => {
expect(findStatisticsSection().exists()).toBe(false);
});
},
);
describe('given there is a default environment with data', () => {
beforeEach(() => { beforeEach(() => {
factory(); factory();
}); });
it('dispatches the setCurrentEnvironmentId and fetchEnvironments actions', () => { it.each`
expect(store.dispatch.mock.calls).toEqual([ component | status | findComponent | state
['threatMonitoring/setCurrentEnvironmentId', defaultEnvironmentId], ${'"no environment" empty state'} | ${'does not display'} | ${findNoEnvironmentEmptyState} | ${false}
['threatMonitoring/fetchEnvironments', undefined], ${'alert tab'} | ${'does display'} | ${findAlertTab} | ${true}
]); ${'statistics tab'} | ${'does display'} | ${findStatisticsTab} | ${true}
${'statistics filter section'} | ${'does display'} | ${findFilters} | ${true}
${'statistics section'} | ${'does display'} | ${findStatisticsSection} | ${true}
`('$status the $component', async ({ findComponent, state }) => {
expect(findComponent().exists()).toBe(state);
}); });
it('shows the filter bar', () => { it('passes the statistics section the correct information', () => {
expect(findFilters().exists()).toBe(true); expect(findStatisticsSection().element).toMatchSnapshot();
}); });
});
it('renders the statistics section', () => { describe('given there are no environments present', () => {
expect(findStatisticsSection().element).toMatchSnapshot(); beforeEach(() => {
factory({ state: { hasEnvironment: false }, stubs: { GlTabs: false } });
});
it.each`
component | status | findComponent | state
${'"no environment" empty state'} | ${'does display'} | ${findNoEnvironmentEmptyState} | ${true}
${'statistics filter section'} | ${'does not display'} | ${findFilters} | ${false}
${'statistics section'} | ${'does not display'} | ${findStatisticsSection} | ${false}
`('$status the $component', async ({ findComponent, state }) => {
expect(findComponent().exists()).toBe(state);
}); });
}); });
......
import { GlDropdown, GlDropdownItem } from '@gitlab/ui'; import { GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import EnvironmentPicker from 'ee/threat_monitoring/components/environment_picker.vue'; import EnvironmentPicker from 'ee/threat_monitoring/components/environment_picker.vue';
import { import {
...@@ -15,115 +15,129 @@ const currentEnvironment = mockEnvironments[1]; ...@@ -15,115 +15,129 @@ const currentEnvironment = mockEnvironments[1];
describe('EnvironmentPicker component', () => { describe('EnvironmentPicker component', () => {
let store; let store;
let wrapper; let wrapper;
let fetchEnvironmentsSpy;
const factory = (state) => { const factory = (state = {}, propsData = {}) => {
store = createStore(); store = createStore();
Object.assign(store.state.threatMonitoring, state); store.replaceState({
...store.state,
threatMonitoring: {
...store.state.threatMonitoring,
currentEnvironmentId: currentEnvironment.id,
environments: mockEnvironments,
hasEnvironment: true,
nextPage: 'someHash',
...state,
},
});
fetchEnvironmentsSpy = jest
.spyOn(EnvironmentPicker.methods, 'fetchEnvironments')
.mockImplementation(() => {});
jest.spyOn(store, 'dispatch').mockImplementation(); jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = shallowMount(EnvironmentPicker, { wrapper = shallowMount(EnvironmentPicker, {
propsData,
store, store,
}); });
}; };
const findEnvironmentsDropdown = () => wrapper.findComponent(GlDropdown); const findDropdown = () => wrapper.findComponent(GlDropdown);
const findEnvironmentsDropdownItems = () => wrapper.findAllComponents(GlDropdownItem); const findDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
const findLoadMoreButton = () => wrapper.findComponent(GlButton);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null; wrapper = null;
}); });
describe('the environments dropdown', () => { describe('when there are environments', () => {
describe('given there are no environments', () => { beforeEach(() => {
beforeEach(() => { factory();
factory(); });
});
it('has no dropdown items', () => { it('fetches the environments when created', async () => {
expect(findEnvironmentsDropdownItems()).toHaveLength(0); expect(fetchEnvironmentsSpy).toHaveBeenCalled();
});
}); });
describe('given there are environments', () => {
beforeEach(() => {
factory({
environments: mockEnvironments,
currentEnvironmentId: currentEnvironment.id,
});
});
it('is not disabled', () => { it('is not disabled', () => {
expect(findEnvironmentsDropdown().attributes().disabled).toBe(undefined); expect(findDropdown().attributes().disabled).toBe(undefined);
}); });
it('has text set to the current environment', () => { it('has text set to the current environment', () => {
expect(findEnvironmentsDropdown().attributes().text).toBe(currentEnvironment.name); expect(findDropdown().attributes().text).toBe(currentEnvironment.name);
}); });
it('has dropdown items for each environment', () => { it('has dropdown items for each environment', () => {
const dropdownItems = findEnvironmentsDropdownItems(); const dropdownItems = findDropdownItems();
mockEnvironments.forEach((environment, i) => { mockEnvironments.forEach((environment, i) => {
const dropdownItem = dropdownItems.at(i); const dropdownItem = dropdownItems.at(i);
expect(dropdownItem.text()).toBe(environment.name); expect(dropdownItem.text()).toBe(environment.name);
dropdownItem.vm.$emit('click'); dropdownItem.vm.$emit('click');
expect(store.dispatch).toHaveBeenCalledWith( expect(store.dispatch).toHaveBeenCalledWith(
'threatMonitoring/setCurrentEnvironmentId', 'threatMonitoring/setCurrentEnvironmentId',
environment.id, environment.id,
); );
});
}); });
}); });
describe('with includeAll enabled', () => {
beforeEach(() => { it('shows the "Load more" button when there are more environments to fetch', () => {
factory({ expect(findLoadMoreButton().exists()).toBe(true);
environments: mockEnvironments, });
currentEnvironmentId: currentEnvironment.id, });
allEnvironments: true,
}); describe('when there are no environments', () => {
wrapper = shallowMount(EnvironmentPicker, { beforeEach(() => {
propsData: { factory({
includeAll: true, environments: [],
}, hasEnvironment: false,
store, isLoadingEnvironments: false,
}); nextPage: '',
}); });
});
it('has text set to the all environment option', () => { it('disables the environments dropdown', () => {
expect(findEnvironmentsDropdown().attributes().text).toBe(ALL_ENVIRONMENT_NAME); expect(findDropdown().attributes()).toMatchObject({
disabled: 'true',
text: INVALID_CURRENT_ENVIRONMENT_NAME,
}); });
}); });
it('has no dropdown items', () => {
expect(findDropdownItems()).toHaveLength(0);
});
it('does not fetch the environments when created', () => {
expect(fetchEnvironmentsSpy).not.toHaveBeenCalled();
});
it('does not show the "Load more" button', () => {
expect(findLoadMoreButton().exists()).toBe(false);
});
}); });
describe.each` describe('when includeAll is enabled', () => {
context | isLoadingEnvironments | isLoadingNetworkPolicyStatistics | environments | text | loadingState beforeEach(() => {
${'environments are loading'} | ${true} | ${false} | ${mockEnvironments} | ${LOADING_TEXT} | ${'true'} factory({ allEnvironments: true }, { includeAll: true });
${'NetPol statistics are loading'} | ${false} | ${true} | ${mockEnvironments} | ${INVALID_CURRENT_ENVIRONMENT_NAME} | ${undefined} });
${'there are no environments'} | ${false} | ${false} | ${[]} | ${INVALID_CURRENT_ENVIRONMENT_NAME} | ${undefined}
`(
'given $context',
({
isLoadingEnvironments,
isLoadingNetworkPolicyStatistics,
environments,
text,
loadingState,
}) => {
beforeEach(() => {
factory({
environments,
isLoadingEnvironments,
isLoadingNetworkPolicyStatistics,
});
return wrapper.vm.$nextTick();
});
it('disables the environments dropdown', () => { it('has text set to the all environment option', () => {
expect(findEnvironmentsDropdown().attributes('disabled')).toBe('true'); expect(findDropdown().attributes().text).toBe(ALL_ENVIRONMENT_NAME);
expect(findEnvironmentsDropdown().attributes('text')).toBe(text); });
expect(findEnvironmentsDropdown().attributes('loading')).toBe(loadingState); });
describe('when environments are loading', () => {
beforeEach(() => {
factory({ environments: [], isLoadingEnvironments: true });
});
it('disables the environments dropdown', () => {
expect(findDropdown().attributes()).toMatchObject({
disabled: 'true',
text: LOADING_TEXT,
loading: 'true',
}); });
}, });
); });
}); });
import PoliciesApp from 'ee/threat_monitoring/components/policies/policies_app.vue'; import PoliciesApp from 'ee/threat_monitoring/components/policies/policies_app.vue';
import PoliciesHeader from 'ee/threat_monitoring/components/policies/policies_header.vue'; import PoliciesHeader from 'ee/threat_monitoring/components/policies/policies_header.vue';
import PoliciesList from 'ee/threat_monitoring/components/policies/policies_list.vue'; import PoliciesList from 'ee/threat_monitoring/components/policies/policies_list.vue';
import createStore from 'ee/threat_monitoring/store';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
describe('Policies App', () => { describe('Policies App', () => {
let wrapper; let wrapper;
let store;
let setCurrentEnvironmentIdSpy;
let fetchEnvironmentsSpy;
const findPoliciesHeader = () => wrapper.findComponent(PoliciesHeader); const findPoliciesHeader = () => wrapper.findComponent(PoliciesHeader);
const findPoliciesList = () => wrapper.findComponent(PoliciesList); const findPoliciesList = () => wrapper.findComponent(PoliciesList);
const createWrapper = ({ provide } = {}) => { const createWrapper = () => {
store = createStore(); wrapper = shallowMountExtended(PoliciesApp, {});
setCurrentEnvironmentIdSpy = jest
.spyOn(PoliciesApp.methods, 'setCurrentEnvironmentId')
.mockImplementation(() => {});
fetchEnvironmentsSpy = jest
.spyOn(PoliciesApp.methods, 'fetchEnvironments')
.mockImplementation(() => {});
wrapper = shallowMountExtended(PoliciesApp, {
store,
provide: {
defaultEnvironmentId: -1,
...provide,
},
});
}; };
afterEach(() => { afterEach(() => {
...@@ -39,23 +19,13 @@ describe('Policies App', () => { ...@@ -39,23 +19,13 @@ describe('Policies App', () => {
describe('when does have an environment enabled', () => { describe('when does have an environment enabled', () => {
beforeEach(() => { beforeEach(() => {
createWrapper({ provide: { defaultEnvironmentId: 22 } }); createWrapper();
}); });
it('mounts the policies header component', () => { it('mounts the policies header component', () => {
expect(findPoliciesHeader().exists()).toBe(true); expect(findPoliciesHeader().exists()).toBe(true);
}); });
it('mounts the policies list component', () => {
const policiesList = findPoliciesList();
expect(policiesList.props('hasEnvironment')).toBe(true);
});
it('fetches the environments when created', async () => {
expect(setCurrentEnvironmentIdSpy).toHaveBeenCalled();
expect(fetchEnvironmentsSpy).toHaveBeenCalled();
});
it.each` it.each`
component | findFn component | findFn
${'PolicyHeader'} | ${findPoliciesHeader} ${'PolicyHeader'} | ${findPoliciesHeader}
...@@ -70,20 +40,4 @@ describe('Policies App', () => { ...@@ -70,20 +40,4 @@ describe('Policies App', () => {
}, },
); );
}); });
describe('when does not have an environment enabled', () => {
beforeEach(() => {
createWrapper();
});
it('mounts the policies list component', () => {
const policiesList = findPoliciesList();
expect(policiesList.props('hasEnvironment')).toBe(false);
});
it('does not fetch the environments when created', () => {
expect(setCurrentEnvironmentIdSpy).not.toHaveBeenCalled();
expect(fetchEnvironmentsSpy).not.toHaveBeenCalled();
});
});
}); });
...@@ -55,6 +55,7 @@ describe('PoliciesList component', () => { ...@@ -55,6 +55,7 @@ describe('PoliciesList component', () => {
threatMonitoring: { threatMonitoring: {
...store.state.threatMonitoring, ...store.state.threatMonitoring,
environments, environments,
hasEnvironment: true,
currentEnvironmentId: environments[0].id, currentEnvironmentId: environments[0].id,
...state.threatMonitoring, ...state.threatMonitoring,
}, },
...@@ -73,7 +74,6 @@ describe('PoliciesList component', () => { ...@@ -73,7 +74,6 @@ describe('PoliciesList component', () => {
{ {
propsData: { propsData: {
documentationPath: 'documentation_path', documentationPath: 'documentation_path',
hasEnvironment: true,
newPolicyPath: '/policies/new', newPolicyPath: '/policies/new',
}, },
store, store,
...@@ -323,11 +323,7 @@ describe('PoliciesList component', () => { ...@@ -323,11 +323,7 @@ describe('PoliciesList component', () => {
describe('given no environments', () => { describe('given no environments', () => {
beforeEach(() => { beforeEach(() => {
mountWrapper({ mountWrapper({ state: { threatMonitoring: { hasEnvironment: false } } });
propsData: {
hasEnvironment: false,
},
});
}); });
it('does not make a request for network policies', () => { it('does not make a request for network policies', () => {
......
...@@ -25,7 +25,9 @@ describe('NetworkPolicyEditor component', () => { ...@@ -25,7 +25,9 @@ describe('NetworkPolicyEditor component', () => {
let store; let store;
let wrapper; let wrapper;
const defaultStore = { threatMonitoring: { environments: [{ id: 1 }], currentEnvironmentId: 1 } }; const defaultStore = {
threatMonitoring: { environments: [{ id: 1 }], currentEnvironmentId: 1, hasEnvironment: true },
};
const factory = ({ propsData, provide = {}, updatedStore = defaultStore } = {}) => { const factory = ({ propsData, provide = {}, updatedStore = defaultStore } = {}) => {
store = createStore(); store = createStore();
...@@ -49,7 +51,6 @@ describe('NetworkPolicyEditor component', () => { ...@@ -49,7 +51,6 @@ describe('NetworkPolicyEditor component', () => {
...propsData, ...propsData,
}, },
provide: { provide: {
hasEnvironment: true,
networkDocumentationPath: 'path/to/docs', networkDocumentationPath: 'path/to/docs',
noEnvironmentSvgPath: 'path/to/svg', noEnvironmentSvgPath: 'path/to/svg',
policiesPath: '/threat-monitoring', policiesPath: '/threat-monitoring',
...@@ -358,7 +359,9 @@ describe('NetworkPolicyEditor component', () => { ...@@ -358,7 +359,9 @@ describe('NetworkPolicyEditor component', () => {
describe('when loading environments', () => { describe('when loading environments', () => {
beforeEach(() => { beforeEach(() => {
factory({ factory({
updatedStore: { threatMonitoring: { environments: [], isLoadingEnvironments: true } }, updatedStore: {
threatMonitoring: { environments: [], hasEnvironment: true, isLoadingEnvironments: true },
},
}); });
}); });
...@@ -376,10 +379,7 @@ describe('NetworkPolicyEditor component', () => { ...@@ -376,10 +379,7 @@ describe('NetworkPolicyEditor component', () => {
describe('when no environments are configured', () => { describe('when no environments are configured', () => {
beforeEach(() => { beforeEach(() => {
factory({ factory({ updatedStore: { threatMonitoring: { environments: [], hasEnvironment: false } } });
provide: { hasEnvironment: false },
updatedStore: { threatMonitoring: { environments: [] } },
});
}); });
it.each` it.each`
......
...@@ -6,11 +6,9 @@ import NetworkPolicyEditor from 'ee/threat_monitoring/components/policy_editor/n ...@@ -6,11 +6,9 @@ import NetworkPolicyEditor from 'ee/threat_monitoring/components/policy_editor/n
import PolicyEditor from 'ee/threat_monitoring/components/policy_editor/policy_editor.vue'; import PolicyEditor from 'ee/threat_monitoring/components/policy_editor/policy_editor.vue';
import ScanExecutionPolicyEditor from 'ee/threat_monitoring/components/policy_editor/scan_execution_policy/scan_execution_policy_editor.vue'; import ScanExecutionPolicyEditor from 'ee/threat_monitoring/components/policy_editor/scan_execution_policy/scan_execution_policy_editor.vue';
import { DEFAULT_ASSIGNED_POLICY_PROJECT } from 'ee/threat_monitoring/constants'; import { DEFAULT_ASSIGNED_POLICY_PROJECT } from 'ee/threat_monitoring/constants';
import createStore from 'ee/threat_monitoring/store';
import { mockDastScanExecutionObject, mockL3Manifest } from '../../mocks/mock_data'; import { mockDastScanExecutionObject, mockL3Manifest } from '../../mocks/mock_data';
describe('PolicyEditor component', () => { describe('PolicyEditor component', () => {
let store;
let wrapper; let wrapper;
const findAlert = () => wrapper.findComponent(GlAlert); const findAlert = () => wrapper.findComponent(GlAlert);
...@@ -20,10 +18,6 @@ describe('PolicyEditor component', () => { ...@@ -20,10 +18,6 @@ describe('PolicyEditor component', () => {
const findScanExecutionPolicyEditor = () => wrapper.findComponent(ScanExecutionPolicyEditor); const findScanExecutionPolicyEditor = () => wrapper.findComponent(ScanExecutionPolicyEditor);
const factory = ({ propsData = {}, provide = {} } = {}) => { const factory = ({ propsData = {}, provide = {} } = {}) => {
store = createStore();
jest.spyOn(store, 'dispatch').mockImplementation(() => Promise.resolve());
wrapper = shallowMount(PolicyEditor, { wrapper = shallowMount(PolicyEditor, {
propsData: { propsData: {
assignedPolicyProject: DEFAULT_ASSIGNED_POLICY_PROJECT, assignedPolicyProject: DEFAULT_ASSIGNED_POLICY_PROJECT,
...@@ -33,7 +27,6 @@ describe('PolicyEditor component', () => { ...@@ -33,7 +27,6 @@ describe('PolicyEditor component', () => {
policyType: undefined, policyType: undefined,
...provide, ...provide,
}, },
store,
stubs: { GlFormSelect }, stubs: { GlFormSelect },
}); });
}; };
......
...@@ -7,6 +7,7 @@ import { timeRanges, defaultTimeRange } from '~/vue_shared/constants'; ...@@ -7,6 +7,7 @@ import { timeRanges, defaultTimeRange } from '~/vue_shared/constants';
import { mockEnvironmentsResponse } from '../mocks/mock_data'; import { mockEnvironmentsResponse } from '../mocks/mock_data';
const mockEnvironments = mockEnvironmentsResponse.environments; const mockEnvironments = mockEnvironmentsResponse.environments;
const currentEnvironment = mockEnvironments[1];
describe('ThreatMonitoringFilters component', () => { describe('ThreatMonitoringFilters component', () => {
let store; let store;
...@@ -14,7 +15,16 @@ describe('ThreatMonitoringFilters component', () => { ...@@ -14,7 +15,16 @@ describe('ThreatMonitoringFilters component', () => {
const factory = (state) => { const factory = (state) => {
store = createStore(); store = createStore();
Object.assign(store.state.threatMonitoring, state); store.replaceState({
...store.state,
threatMonitoring: {
...store.state.threatMonitoring,
currentEnvironmentId: currentEnvironment.id,
environments: mockEnvironments,
hasEnvironment: true,
...state,
},
});
jest.spyOn(store, 'dispatch').mockImplementation(); jest.spyOn(store, 'dispatch').mockImplementation();
...@@ -30,7 +40,7 @@ describe('ThreatMonitoringFilters component', () => { ...@@ -30,7 +40,7 @@ describe('ThreatMonitoringFilters component', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('the environments picker', () => { describe('has environments', () => {
beforeEach(() => { beforeEach(() => {
factory(); factory();
}); });
...@@ -38,20 +48,9 @@ describe('ThreatMonitoringFilters component', () => { ...@@ -38,20 +48,9 @@ describe('ThreatMonitoringFilters component', () => {
it('renders EnvironmentPicker', () => { it('renders EnvironmentPicker', () => {
expect(findEnvironmentsPicker().exists()).toBe(true); expect(findEnvironmentsPicker().exists()).toBe(true);
}); });
});
describe('the "show last" dropdown', () => { it('renders the "Show last" dropdown correctly', () => {
beforeEach(() => {
factory({
environments: mockEnvironments,
});
});
it('is not disabled', () => {
expect(findShowLastDropdown().attributes().disabled).toBe(undefined); expect(findShowLastDropdown().attributes().disabled).toBe(undefined);
});
it('has text set to the current time window name', () => {
expect(findShowLastDropdown().vm.value.label).toBe(defaultTimeRange.label); expect(findShowLastDropdown().vm.value.label).toBe(defaultTimeRange.label);
}); });
...@@ -66,26 +65,17 @@ describe('ThreatMonitoringFilters component', () => { ...@@ -66,26 +65,17 @@ describe('ThreatMonitoringFilters component', () => {
}); });
describe.each` describe.each`
context | isLoadingEnvironments | isLoadingNetworkPolicyStatistics | environments context | status | isLoadingEnvironments | environments | disabled
${'environments are loading'} | ${true} | ${false} | ${mockEnvironments} ${'environments are initially loading'} | ${'does'} | ${true} | ${[]} | ${'true'}
${'NetPol statistics are loading'} | ${false} | ${true} | ${mockEnvironments} ${'more environments are loading'} | ${'does not'} | ${true} | ${mockEnvironments} | ${undefined}
${'there are no environments'} | ${false} | ${false} | ${[]} ${'there are no environments'} | ${'does'} | ${false} | ${[]} | ${'true'}
`( `('when $context', ({ isLoadingEnvironments, environments, disabled, status }) => {
'given $context', beforeEach(() => {
({ isLoadingEnvironments, isLoadingNetworkPolicyStatistics, environments }) => { factory({ environments, isLoadingEnvironments });
beforeEach(() => { });
factory({
environments,
isLoadingEnvironments,
isLoadingNetworkPolicyStatistics,
});
return wrapper.vm.$nextTick();
});
it('disables the "show last" dropdown', () => { it(`${status} disable the "Show last" dropdown`, () => {
expect(findShowLastDropdown().attributes('disabled')).toBe('true'); expect(findShowLastDropdown().attributes('disabled')).toBe(disabled);
}); });
}, });
);
}); });
...@@ -13,6 +13,7 @@ jest.mock('~/flash'); ...@@ -13,6 +13,7 @@ jest.mock('~/flash');
const environmentsEndpoint = 'environmentsEndpoint'; const environmentsEndpoint = 'environmentsEndpoint';
const networkPolicyStatisticsEndpoint = 'networkPolicyStatisticsEndpoint'; const networkPolicyStatisticsEndpoint = 'networkPolicyStatisticsEndpoint';
const nextPage = 2;
describe('Threat Monitoring actions', () => { describe('Threat Monitoring actions', () => {
let state; let state;
...@@ -121,7 +122,9 @@ describe('Threat Monitoring actions', () => { ...@@ -121,7 +122,9 @@ describe('Threat Monitoring actions', () => {
describe('on success', () => { describe('on success', () => {
beforeEach(() => { beforeEach(() => {
mock.onGet(environmentsEndpoint).replyOnce(httpStatus.OK, mockEnvironmentsResponse); mock
.onGet(environmentsEndpoint)
.replyOnce(httpStatus.OK, mockEnvironmentsResponse, { 'x-next-page': nextPage });
}); });
it('should dispatch the request and success actions', () => it('should dispatch the request and success actions', () =>
...@@ -134,37 +137,7 @@ describe('Threat Monitoring actions', () => { ...@@ -134,37 +137,7 @@ describe('Threat Monitoring actions', () => {
{ type: 'requestEnvironments' }, { type: 'requestEnvironments' },
{ {
type: 'receiveEnvironmentsSuccess', type: 'receiveEnvironmentsSuccess',
payload: mockEnvironmentsResponse.environments, payload: { environments: mockEnvironmentsResponse.environments, nextPage },
},
],
));
});
describe('given more than one page of environments', () => {
beforeEach(() => {
const oneEnvironmentPerPage = ({ totalPages }) => (config) => {
const { page } = config.params;
const response = [httpStatus.OK, { environments: [{ id: page }] }];
if (page < totalPages) {
response.push({ 'x-next-page': page + 1 });
}
return response;
};
mock.onGet(environmentsEndpoint).reply(oneEnvironmentPerPage({ totalPages: 3 }));
});
it('should fetch all pages and dispatch the request and success actions', () =>
testAction(
actions.fetchEnvironments,
undefined,
state,
[],
[
{ type: 'requestEnvironments' },
{
type: 'receiveEnvironmentsSuccess',
payload: [{ id: 1 }, { id: 2 }, { id: 3 }],
}, },
], ],
)); ));
......
...@@ -36,10 +36,10 @@ describe('Threat Monitoring mutations', () => { ...@@ -36,10 +36,10 @@ describe('Threat Monitoring mutations', () => {
beforeEach(() => { beforeEach(() => {
environments = [{ id: 1, name: 'production' }]; environments = [{ id: 1, name: 'production' }];
mutations[types.RECEIVE_ENVIRONMENTS_SUCCESS](state, environments); mutations[types.RECEIVE_ENVIRONMENTS_SUCCESS](state, { environments, nextPage: '' });
}); });
it('sets environments to the payload', () => { it('sets environments', () => {
expect(state.environments).toBe(environments); expect(state.environments).toBe(environments);
}); });
...@@ -55,10 +55,10 @@ describe('Threat Monitoring mutations', () => { ...@@ -55,10 +55,10 @@ describe('Threat Monitoring mutations', () => {
expect(state.currentEnvironmentId).toEqual(1); expect(state.currentEnvironmentId).toEqual(1);
}); });
describe('without payload', () => { describe('without environments', () => {
beforeEach(() => { beforeEach(() => {
state.currentEnvironmentId = 1; state.currentEnvironmentId = 1;
mutations[types.RECEIVE_ENVIRONMENTS_SUCCESS](state, []); mutations[types.RECEIVE_ENVIRONMENTS_SUCCESS](state, { environments: [], nextPage: '' });
}); });
it('does not update currentEnvironmentId', () => { it('does not update currentEnvironmentId', () => {
...@@ -70,7 +70,7 @@ describe('Threat Monitoring mutations', () => { ...@@ -70,7 +70,7 @@ describe('Threat Monitoring mutations', () => {
beforeEach(() => { beforeEach(() => {
state.currentEnvironmentId = 1; state.currentEnvironmentId = 1;
environments = [{ id: 2, name: 'production' }]; environments = [{ id: 2, name: 'production' }];
mutations[types.RECEIVE_ENVIRONMENTS_SUCCESS](state, environments); mutations[types.RECEIVE_ENVIRONMENTS_SUCCESS](state, { environments, nextPage: '' });
}); });
it('does not update currentEnvironmentId', () => { it('does not update currentEnvironmentId', () => {
......
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