Commit a09c3090 authored by ap4y's avatar ap4y

Add policy toggle to the Network Policy Management

This commit adds an enforcement status toggle to the network policy
management tab's drawer. This toggle is used to enable/disable
deployed policies.
parent e999b496
<script>
import { mapState, mapActions } from 'vuex';
import { GlTable, GlEmptyState, GlDrawer, GlButton, GlAlert, GlSprintf, GlLink } from '@gitlab/ui';
import {
GlTable,
GlEmptyState,
GlDrawer,
GlButton,
GlAlert,
GlSprintf,
GlLink,
GlToggle,
} from '@gitlab/ui';
import { s__ } from '~/locale';
import { getTimeago } from '~/lib/utils/datetime_utility';
import { setUrlFragment } from '~/lib/utils/url_utility';
......@@ -16,6 +25,7 @@ export default {
GlAlert,
GlSprintf,
GlLink,
GlToggle,
EnvironmentPicker,
NetworkPolicyEditor,
},
......@@ -26,7 +36,7 @@ export default {
},
},
data() {
return { selectedPolicyName: null, initialManifest: null };
return { selectedPolicyName: null, initialManifest: null, initialEnforcementStatus: null };
},
computed: {
...mapState('networkPolicies', ['policies', 'isLoadingPolicies', 'isUpdatingPolicy']),
......@@ -43,7 +53,12 @@ export default {
return this.policies.find(policy => policy.name === this.selectedPolicyName);
},
hasPolicyChanges() {
return this.hasSelectedPolicy && this.selectedPolicy.manifest !== this.initialManifest;
if (!this.hasSelectedPolicy) return false;
return (
this.selectedPolicy.manifest !== this.initialManifest ||
this.selectedPolicy.isEnabled !== this.initialEnforcementStatus
);
},
hasAutoDevopsPolicy() {
return this.policies.some(policy => policy.isAutodevops);
......@@ -60,6 +75,7 @@ export default {
const [selectedPolicy] = rows;
this.selectedPolicyName = selectedPolicy?.name;
this.initialManifest = selectedPolicy?.manifest;
this.initialEnforcementStatus = selectedPolicy?.isEnabled;
},
deselectPolicy() {
this.selectedPolicyName = null;
......@@ -73,6 +89,7 @@ export default {
policy: this.selectedPolicy,
}).then(() => {
this.initialManifest = this.selectedPolicy.manifest;
this.initialEnforcementStatus = this.selectedPolicy.isEnabled;
});
},
},
......@@ -145,8 +162,8 @@ export default {
selected-variant="primary"
@row-selected="presentPolicyDrawer"
>
<template #cell(status)>
{{ s__('NetworkPolicies|Enabled') }}
<template #cell(status)="value">
{{ value.item.isEnabled ? __('Enabled') : __('Disabled') }}
</template>
<template #cell(creationTimestamp)="value">
......@@ -195,6 +212,16 @@ export default {
<h5>{{ s__('NetworkPolicies|Policy definition') }}</h5>
<p>{{ s__("NetworkPolicies|Define this policy's location, conditions and actions.") }}</p>
<network-policy-editor ref="policyEditor" v-model="selectedPolicy.manifest" />
<h5 class="mt-4">{{ s__('NetworkPolicies|Enforcement status') }}</h5>
<p>{{ s__('NetworkPolicies|Choose whether to enforce this policy.') }}</p>
<gl-toggle
v-model="selectedPolicy.isEnabled"
:label-on="__('Enabled')"
:label-off="__('Disabled')"
label-position="right"
data-testid="policyToggle"
/>
</div>
</template>
</gl-drawer>
......
......@@ -44,6 +44,7 @@ export const updatePolicy = ({ state, commit }, { environmentId, policy }) => {
.put(joinPaths(state.policiesEndpoint, policy.name), {
environment_id: environmentId,
manifest: policy.manifest,
enabled: policy.isEnabled,
})
.then(({ data }) => {
commit(types.RECEIVE_UPDATE_POLICY_SUCCESS, {
......
......@@ -2,9 +2,12 @@ import { mount } from '@vue/test-utils';
import createStore from 'ee/threat_monitoring/store';
import NetworkPolicyList from 'ee/threat_monitoring/components/network_policy_list.vue';
import { GlTable } from '@gitlab/ui';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { mockPoliciesResponse } from '../mock_data';
const mockData = mockPoliciesResponse.map(policy => convertObjectPropsToCamelCase(policy));
describe('NetworkPolicyList component', () => {
let store;
let wrapper;
......@@ -13,7 +16,7 @@ describe('NetworkPolicyList component', () => {
store = createStore();
Object.assign(store.state.networkPolicies, {
isLoadingPolicies: false,
policies: mockPoliciesResponse,
policies: mockData,
...state,
});
......@@ -34,6 +37,7 @@ describe('NetworkPolicyList component', () => {
const findTableEmptyState = () => wrapper.find({ ref: 'tableEmptyState' });
const findEditorDrawer = () => wrapper.find({ ref: 'editorDrawer' });
const findPolicyEditor = () => wrapper.find({ ref: 'policyEditor' });
const findPolicyToggle = () => wrapper.find('[data-testid="policyToggle"]');
const findApplyButton = () => wrapper.find({ ref: 'applyButton' });
const findCancelButton = () => wrapper.find({ ref: 'cancelButton' });
const findAutodevopsAlert = () => wrapper.find('[data-testid="autodevopsAlert"]');
......@@ -82,7 +86,8 @@ describe('NetworkPolicyList component', () => {
factory({
data: () => ({
selectedPolicyName: 'policy',
initialManifest: mockPoliciesResponse[0].manifest,
initialManifest: mockData[0].manifest,
initialEnforcementStatus: mockData[0].isEnabled,
}),
});
});
......@@ -96,7 +101,13 @@ describe('NetworkPolicyList component', () => {
it('renders network policy editor with manifest', () => {
const policyEditor = findPolicyEditor();
expect(policyEditor.exists()).toBe(true);
expect(policyEditor.props('value')).toBe(mockPoliciesResponse[0].manifest);
expect(policyEditor.props('value')).toBe(mockData[0].manifest);
});
it('renders network policy toggle', () => {
const policyToggle = findPolicyToggle();
expect(policyToggle.exists()).toBe(true);
expect(policyToggle.props('value')).toBe(mockData[0].isEnabled);
});
it('renders disabled apply button', () => {
......@@ -133,10 +144,22 @@ describe('NetworkPolicyList component', () => {
expect(store.dispatch).toHaveBeenCalledWith('networkPolicies/updatePolicy', {
environmentId: -1,
policy: mockPoliciesResponse[0],
policy: mockData[0],
});
});
});
describe('given there is a policy enforcement status change', () => {
beforeEach(() => {
findPolicyToggle().vm.$emit('change', false);
});
it('renders enabled apply button', () => {
const applyButton = findApplyButton();
expect(applyButton.exists()).toBe(true);
expect(applyButton.props('disabled')).toBe(false);
});
});
});
describe('given there is a default environment with no data to display', () => {
......
......@@ -37,6 +37,7 @@ spec:
matchLabels:
project: myproject`,
created_timestamp: '2020-04-14T00:08:30Z',
is_enabled: true,
},
];
......
......@@ -141,8 +141,8 @@ describe('Network Policy actions', () => {
describe('updatePolicy', () => {
let mock;
const environmentId = 3;
const policy = { name: 'policy', manifest: 'foo' };
const updatedPolicy = { name: 'policy', manifest: 'bar' };
const policy = { name: 'policy', manifest: 'foo', isEnabled: true };
const updatedPolicy = { name: 'policy', manifest: 'bar', isEnabled: true };
beforeEach(() => {
state.policiesEndpoint = networkPoliciesEndpoint;
......@@ -159,6 +159,7 @@ describe('Network Policy actions', () => {
.onPut(joinPaths(networkPoliciesEndpoint, policy.name), {
environment_id: environmentId,
manifest: policy.manifest,
enabled: policy.isEnabled,
})
.replyOnce(httpStatus.OK, updatedPolicy);
});
......@@ -187,6 +188,7 @@ describe('Network Policy actions', () => {
.onPut(joinPaths(networkPoliciesEndpoint, policy.name), {
environment_id: environmentId,
manifest: policy.manifest,
enabled: policy.isEnabled,
})
.replyOnce(500, error);
});
......
......@@ -14291,10 +14291,13 @@ msgstr ""
msgid "Network"
msgstr ""
msgid "NetworkPolicies|Choose whether to enforce this policy."
msgstr ""
msgid "NetworkPolicies|Define this policy's location, conditions and actions."
msgstr ""
msgid "NetworkPolicies|Enabled"
msgid "NetworkPolicies|Enforcement status"
msgstr ""
msgid "NetworkPolicies|Environment does not have deployment platform"
......
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