Commit d215c54b authored by Mark Florian's avatar Mark Florian

Merge branch 'network-policy-editor-fixes' into 'master'

Network policy editor fixes

See merge request gitlab-org/gitlab!42424
parents 8e4e69cd 96334aba
<script>
export default {
props: {
disabled: {
type: Boolean,
required: false,
default: false,
},
},
};
</script>
<template>
<div>
<slot name="title"></slot>
<slot v-if="disabled" name="disabled"></slot>
<slot v-else></slot>
<div
v-if="disabled"
class="gl-absolute gl-top-0 gl-bottom-0 gl-left-0 gl-right-0 gl-bg-white gl-opacity-5"
data-testid="overlay"
></div>
</div>
</template>
...@@ -19,6 +19,7 @@ import NetworkPolicyEditor from '../network_policy_editor.vue'; ...@@ -19,6 +19,7 @@ import NetworkPolicyEditor from '../network_policy_editor.vue';
import PolicyRuleBuilder from './policy_rule_builder.vue'; import PolicyRuleBuilder from './policy_rule_builder.vue';
import PolicyPreview from './policy_preview.vue'; import PolicyPreview from './policy_preview.vue';
import PolicyActionPicker from './policy_action_picker.vue'; import PolicyActionPicker from './policy_action_picker.vue';
import DimDisableContainer from './dim_disable_container.vue';
import { import {
EditorModeRule, EditorModeRule,
EditorModeYAML, EditorModeYAML,
...@@ -46,6 +47,7 @@ export default { ...@@ -46,6 +47,7 @@ export default {
PolicyRuleBuilder, PolicyRuleBuilder,
PolicyPreview, PolicyPreview,
PolicyActionPicker, PolicyActionPicker,
DimDisableContainer,
}, },
directives: { GlModal: GlModalDirective }, directives: { GlModal: GlModalDirective },
props: { props: {
...@@ -146,7 +148,7 @@ export default { ...@@ -146,7 +148,7 @@ export default {
} }
}, },
changeEditorMode(mode) { changeEditorMode(mode) {
if (mode === EditorModeYAML) { if (mode === EditorModeYAML && !this.hasParsingError) {
this.yamlEditorValue = toYaml(this.policy); this.yamlEditorValue = toYaml(this.policy);
} }
...@@ -249,43 +251,80 @@ export default { ...@@ -249,43 +251,80 @@ export default {
<hr /> <hr />
<div v-if="shouldShowRuleEditor" class="row" data-testid="rule-editor"> <div v-if="shouldShowRuleEditor" class="row" data-testid="rule-editor">
<div class="col-sm-12 col-md-6 col-lg-7 col-xl-8"> <div class="col-sm-12 col-md-6 col-lg-7 col-xl-8">
<gl-alert v-if="hasParsingError" data-testid="parsing-alert" :dismissible="false">{{ <gl-alert
$options.parsingErrorMessage v-if="hasParsingError"
}}</gl-alert> class="gl-z-index-1"
data-testid="parsing-alert"
:dismissible="false"
>{{ $options.parsingErrorMessage }}</gl-alert
>
<dim-disable-container data-testid="rule-builder-container" :disabled="hasParsingError">
<template #title>
<h4>{{ s__('NetworkPolicies|Rules') }}</h4>
</template>
<template #disabled>
<div
class="gl-bg-gray-10 gl-border-solid gl-border-1 gl-border-gray-100 gl-rounded-base gl-p-6"
></div>
</template>
<h4>{{ s__('NetworkPolicies|Rules') }}</h4> <policy-rule-builder
<policy-rule-builder v-for="(rule, idx) in policy.rules"
v-for="(rule, idx) in policy.rules" :key="idx"
:key="idx" class="gl-mb-4"
class="gl-mb-4" :rule="rule"
:rule="rule" :endpoint-match-mode="policy.endpointMatchMode"
:endpoint-match-mode="policy.endpointMatchMode" :endpoint-labels="policy.endpointLabels"
:endpoint-labels="policy.endpointLabels" :endpoint-selector-disabled="idx > 0"
:endpoint-selector-disabled="idx > 0" @rule-type-change="updateRuleType(idx, $event)"
@rule-type-change="updateRuleType(idx, $event)" @endpoint-match-mode-change="updateEndpointMatchMode"
@endpoint-match-mode-change="updateEndpointMatchMode" @endpoint-labels-change="updateEndpointLabels"
@endpoint-labels-change="updateEndpointLabels" @remove="removeRule(idx)"
@remove="removeRule(idx)" />
/>
<div class="gl-p-3 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-mb-5"> <div
<gl-button class="gl-p-3 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-mb-5"
variant="link"
category="primary"
data-testid="add-rule"
:disabled="hasParsingError"
@click="addRule"
>{{ s__('Network Policy|New rule') }}</gl-button
> >
</div> <gl-button variant="link" category="primary" data-testid="add-rule" @click="addRule">{{
s__('Network Policy|New rule')
}}</gl-button>
</div>
</dim-disable-container>
<h4>{{ s__('NetworkPolicies|Actions') }}</h4> <dim-disable-container data-testid="policy-action-container" :disabled="hasParsingError">
<p>{{ s__('NetworkPolicies|Traffic that does not match any rule will be blocked.') }}</p> <template #title>
<policy-action-picker /> <h4>{{ s__('NetworkPolicies|Actions') }}</h4>
<p>
{{ s__('NetworkPolicies|Traffic that does not match any rule will be blocked.') }}
</p>
</template>
<template #disabled>
<div
class="gl-bg-gray-10 gl-border-solid gl-border-1 gl-border-gray-100 gl-rounded-base gl-p-6"
></div>
</template>
<policy-action-picker />
</dim-disable-container>
</div> </div>
<div class="col-sm-12 col-md-6 col-lg-5 col-xl-4"> <div class="col-sm-12 col-md-6 col-lg-5 col-xl-4">
<h5>{{ s__('NetworkPolicies|Policy preview') }}</h5> <dim-disable-container data-testid="policy-preview-container" :disabled="hasParsingError">
<policy-preview :policy-yaml="policyYaml" :policy-description="humanizedPolicy" /> <template #title>
<h5>{{ s__('NetworkPolicies|Policy preview') }}</h5>
</template>
<template #disabled>
<policy-preview
:policy-yaml="s__('NetworkPolicies|Unable to parse policy')"
policy-description=""
/>
</template>
<policy-preview :policy-yaml="policyYaml" :policy-description="humanizedPolicy" />
</dim-disable-container>
</div> </div>
</div> </div>
<div v-if="shouldShowYamlEditor" class="row" data-testid="yaml-editor"> <div v-if="shouldShowYamlEditor" class="row" data-testid="yaml-editor">
......
...@@ -152,7 +152,9 @@ export default { ...@@ -152,7 +152,9 @@ export default {
</template> </template>
<template #isLabel="{ content }"> <template #isLabel="{ content }">
<label for="direction" class="gl-mr-4 gl-mb-5!">{{ content }}</label> <label for="direction" class="gl-mr-4 gl-mb-5! gl-font-weight-normal">{{
content
}}</label>
</template> </template>
<template #ruleDirection> <template #ruleDirection>
...@@ -178,7 +180,7 @@ export default { ...@@ -178,7 +180,7 @@ export default {
<gl-form-input <gl-form-input
v-if="shouldShowEndpointLabels" v-if="shouldShowEndpointLabels"
data-testid="endpoint-labels" data-testid="endpoint-labels"
class="gl-mr-4 gl-mb-5" class="gl-mr-4 gl-mb-5 gl-bg-white!"
placeholder="key:value" placeholder="key:value"
:value="endpointLabels" :value="endpointLabels"
:disabled="endpointSelectorDisabled" :disabled="endpointSelectorDisabled"
...@@ -188,7 +190,7 @@ export default { ...@@ -188,7 +190,7 @@ export default {
</template> </template>
<template #directionLabel="{ content }"> <template #directionLabel="{ content }">
<label for="ruleMode" class="gl-mr-4 gl-mb-5!">{{ content }}</label> <label for="ruleMode" class="gl-mr-4 gl-mb-5! gl-font-weight-normal">{{ content }}</label>
</template> </template>
<template #rule> <template #rule>
...@@ -204,7 +206,9 @@ export default { ...@@ -204,7 +206,9 @@ export default {
</template> </template>
<template #portsLabel="{ content }"> <template #portsLabel="{ content }">
<label for="portMatch" class="gl-mr-4 gl-mb-5!">{{ content }}</label> <label for="portMatch" class="gl-mr-4 gl-mb-5! gl-font-weight-normal">{{
content
}}</label>
</template> </template>
<template #ports> <template #ports>
...@@ -220,7 +224,7 @@ export default { ...@@ -220,7 +224,7 @@ export default {
v-if="shouldShowPorts" v-if="shouldShowPorts"
v-model="rule.ports" v-model="rule.ports"
data-testid="ports" data-testid="ports"
class="gl-mr-4 gl-mb-5" class="gl-mr-4 gl-mb-5 gl-bg-white!"
placeholder="80/tcp" placeholder="80/tcp"
/> />
<!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings --> <!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings -->
......
...@@ -17,6 +17,11 @@ export default { ...@@ -17,6 +17,11 @@ export default {
<template> <template>
<!-- placeholder is the same in all languages--> <!-- placeholder is the same in all languages-->
<!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings --> <!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings -->
<gl-form-input placeholder="0.0.0.0/24" :value="value" @input="$emit('input', $event)" /> <gl-form-input
class="gl-bg-white!"
placeholder="0.0.0.0/24"
:value="value"
@input="$emit('input', $event)"
/>
<!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings --> <!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings -->
</template> </template>
...@@ -17,6 +17,11 @@ export default { ...@@ -17,6 +17,11 @@ export default {
<template> <template>
<!-- placeholder is the same in all languages--> <!-- placeholder is the same in all languages-->
<!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings --> <!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings -->
<gl-form-input placeholder="key:value" :value="value" @input="$emit('input', $event)" /> <gl-form-input
class="gl-bg-white!"
placeholder="key:value"
:value="value"
@input="$emit('input', $event)"
/>
<!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings --> <!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings -->
</template> </template>
...@@ -17,6 +17,11 @@ export default { ...@@ -17,6 +17,11 @@ export default {
<template> <template>
<!-- placeholder is the same in all languages--> <!-- placeholder is the same in all languages-->
<!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings --> <!-- eslint-disable @gitlab/vue-require-i18n-attribute-strings -->
<gl-form-input placeholder="remote-service.com" :value="value" @input="$emit('input', $event)" /> <gl-form-input
class="gl-bg-white!"
placeholder="remote-service.com"
:value="value"
@input="$emit('input', $event)"
/>
<!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings --> <!-- eslint-enable @gitlab/vue-require-i18n-attribute-strings -->
</template> </template>
---
title: Improve policy editor layout
merge_request: 42424
author:
type: changed
...@@ -153,47 +153,45 @@ exports[`PolicyEditorApp component renders the policy editor layout 1`] = ` ...@@ -153,47 +153,45 @@ exports[`PolicyEditorApp component renders the policy editor layout 1`] = `
> >
<!----> <!---->
<h4> <dim-disable-container-stub
Rules data-testid="rule-builder-container"
</h4>
<div
class="gl-p-3 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-mb-5"
> >
<gl-button-stub
buttontextclasses="" <div
category="primary" class="gl-p-3 gl-rounded-base gl-border-1 gl-border-solid gl-border-gray-100 gl-mb-5"
data-testid="add-rule"
icon=""
size="medium"
variant="link"
> >
New rule <gl-button-stub
</gl-button-stub> buttontextclasses=""
</div> category="primary"
data-testid="add-rule"
<h4> icon=""
Actions size="medium"
</h4> variant="link"
>
<p> New rule
Traffic that does not match any rule will be blocked. </gl-button-stub>
</p> </div>
</dim-disable-container-stub>
<policy-action-picker-stub /> <dim-disable-container-stub
data-testid="policy-action-container"
>
<policy-action-picker-stub />
</dim-disable-container-stub>
</div> </div>
<div <div
class="col-sm-12 col-md-6 col-lg-5 col-xl-4" class="col-sm-12 col-md-6 col-lg-5 col-xl-4"
> >
<h5> <dim-disable-container-stub
Policy preview data-testid="policy-preview-container"
</h5> >
<policy-preview-stub <policy-preview-stub
initialtab="0" initialtab="0"
policydescription="Deny all traffic" policydescription="Deny all traffic"
policyyaml="apiVersion: cilium.io/v2 policyyaml="apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy kind: CiliumNetworkPolicy
metadata: metadata:
name: '' name: ''
...@@ -202,7 +200,8 @@ spec: ...@@ -202,7 +200,8 @@ spec:
matchLabels: matchLabels:
network-policy.gitlab.com/disabled_by: gitlab network-policy.gitlab.com/disabled_by: gitlab
" "
/> />
</dim-disable-container-stub>
</div> </div>
</div> </div>
......
import { shallowMount } from '@vue/test-utils';
import DimDisableContainer from 'ee/threat_monitoring/components/policy_editor/dim_disable_container.vue';
describe('DimDisableContainer component', () => {
let wrapper;
const factory = ({ propsData } = {}) => {
wrapper = shallowMount(DimDisableContainer, {
propsData: {
...propsData,
},
slots: {
default: '<main>Item</main>',
title: '<h1>Title</h1>',
disabled: '<span>Disabled</span>',
},
});
};
beforeEach(() => {
factory();
});
afterEach(() => {
wrapper.destroy();
});
it('renders title slot component', () => {
expect(wrapper.contains('h1')).toBe(true);
});
it('renders default slot component', () => {
expect(wrapper.contains('main')).toBe(true);
});
it('does not render disabled slot component', () => {
expect(wrapper.contains('span')).toBe(false);
});
it('does not render dim overlay', () => {
expect(wrapper.contains("[data-testid='overlay']")).toBe(false);
});
describe('give disabled is true', () => {
beforeEach(() => {
factory({
propsData: {
disabled: true,
},
});
});
it('renders title slot component', () => {
expect(wrapper.contains('h1')).toBe(true);
});
it('does not render default slot component', () => {
expect(wrapper.contains('main')).toBe(false);
});
it('renders disabled slot component', () => {
expect(wrapper.contains('span')).toBe(true);
});
it('renders dim overlay', () => {
expect(wrapper.contains("[data-testid='overlay']")).toBe(true);
});
});
});
...@@ -53,6 +53,7 @@ describe('PolicyEditorApp component', () => { ...@@ -53,6 +53,7 @@ describe('PolicyEditorApp component', () => {
const findPolicyName = () => wrapper.find("[id='policyName']"); const findPolicyName = () => wrapper.find("[id='policyName']");
const findSavePolicy = () => wrapper.find("[data-testid='save-policy']"); const findSavePolicy = () => wrapper.find("[data-testid='save-policy']");
const findDeletePolicy = () => wrapper.find("[data-testid='delete-policy']"); const findDeletePolicy = () => wrapper.find("[data-testid='delete-policy']");
const findEditorModeToggle = () => wrapper.find("[data-testid='editor-mode']");
beforeEach(() => { beforeEach(() => {
factory(); factory();
...@@ -189,7 +190,7 @@ spec: ...@@ -189,7 +190,7 @@ spec:
it('updates yaml editor value on switch to yaml editor', async () => { it('updates yaml editor value on switch to yaml editor', async () => {
findPolicyName().vm.$emit('input', 'test-policy'); findPolicyName().vm.$emit('input', 'test-policy');
wrapper.find("[data-testid='editor-mode']").vm.$emit('input', EditorModeYAML); findEditorModeToggle().vm.$emit('input', EditorModeYAML);
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
const editor = findNetworkPolicyEditor(); const editor = findNetworkPolicyEditor();
...@@ -212,8 +213,26 @@ spec: ...@@ -212,8 +213,26 @@ spec:
expect(findYAMLParsingAlert().exists()).toBe(true); expect(findYAMLParsingAlert().exists()).toBe(true);
}); });
it('disables add rule button', () => { it('disables rule builder', () => {
expect(findAddRuleButton().props('disabled')).toBe(true); expect(wrapper.find("[data-testid='rule-builder-container']").props().disabled).toBe(true);
});
it('disables action picker', () => {
expect(wrapper.find("[data-testid='policy-action-container']").props().disabled).toBe(true);
});
it('disables policy preview', () => {
expect(wrapper.find("[data-testid='policy-preview-container']").props().disabled).toBe(true);
});
it('does not update yaml editor value on switch to yaml editor', async () => {
findPolicyName().vm.$emit('input', 'test-policy');
findEditorModeToggle().vm.$emit('input', EditorModeYAML);
await wrapper.vm.$nextTick();
const editor = findNetworkPolicyEditor();
expect(editor.exists()).toBe(true);
expect(editor.props('value')).toEqual('');
}); });
}); });
......
...@@ -16814,6 +16814,9 @@ msgstr "" ...@@ -16814,6 +16814,9 @@ msgstr ""
msgid "NetworkPolicies|Traffic that does not match any rule will be blocked." msgid "NetworkPolicies|Traffic that does not match any rule will be blocked."
msgstr "" msgstr ""
msgid "NetworkPolicies|Unable to parse policy"
msgstr ""
msgid "NetworkPolicies|YAML editor" msgid "NetworkPolicies|YAML editor"
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