Commit ab0560cd authored by Mark Florian's avatar Mark Florian

Merge branch '238603-analyzer-configuration-part-2' into 'master'

Implement dynamic fields inside Analyzer Component Part II

Closes #238603

See merge request gitlab-org/gitlab!41772
parents 987279df 0b9ff82f
<script> <script>
import { GlFormCheckbox } from '@gitlab/ui'; import { GlFormCheckbox, GlFormGroup } from '@gitlab/ui';
import DynamicFields from './dynamic_fields.vue';
import { isValidAnalyzerEntity } from './utils'; import { isValidAnalyzerEntity } from './utils';
export default { export default {
components: { components: {
GlFormGroup,
GlFormCheckbox, GlFormCheckbox,
DynamicFields,
}, },
model: { model: {
prop: 'entity', prop: 'entity',
...@@ -18,9 +21,18 @@ export default { ...@@ -18,9 +21,18 @@ export default {
validator: isValidAnalyzerEntity, validator: isValidAnalyzerEntity,
}, },
}, },
computed: {
hasConfiguration() {
return this.entity.configuration?.length > 0;
},
},
methods: { methods: {
onToggle(value) { onToggle(enabled) {
const entity = { ...this.entity, enabled: value }; const entity = { ...this.entity, enabled };
this.$emit('input', entity);
},
onConfigurationUpdate(configuration) {
const entity = { ...this.entity, configuration };
this.$emit('input', entity); this.$emit('input', entity);
}, },
}, },
...@@ -28,8 +40,18 @@ export default { ...@@ -28,8 +40,18 @@ export default {
</script> </script>
<template> <template>
<gl-form-checkbox :id="entity.name" :checked="entity.enabled" @input="onToggle"> <gl-form-group>
<span class="gl-font-weight-bold">{{ entity.label }}</span> <gl-form-checkbox :id="entity.name" :checked="entity.enabled" @input="onToggle">
<span v-if="entity.description" class="gl-text-gray-500">({{ entity.description }})</span> <span class="gl-font-weight-bold">{{ entity.label }}</span>
</gl-form-checkbox> <span v-if="entity.description" class="gl-text-gray-500">({{ entity.description }})</span>
</gl-form-checkbox>
<dynamic-fields
v-if="hasConfiguration"
:disabled="!entity.enabled"
class="gl-ml-6"
:entities="entity.configuration"
@input="onConfigurationUpdate"
/>
</gl-form-group>
</template> </template>
<script> <script>
import { GlFormGroup } from '@gitlab/ui';
import FormInput from './form_input.vue'; import FormInput from './form_input.vue';
import { isValidConfigurationEntity } from './utils'; import { isValidConfigurationEntity } from './utils';
export default { export default {
components: { components: {
GlFormGroup,
FormInput, FormInput,
}, },
model: { model: {
...@@ -16,6 +18,11 @@ export default { ...@@ -16,6 +18,11 @@ export default {
required: true, required: true,
validator: value => value.every(isValidConfigurationEntity), validator: value => value.every(isValidConfigurationEntity),
}, },
disabled: {
type: Boolean,
required: false,
default: false,
},
}, },
methods: { methods: {
componentForEntity({ type }) { componentForEntity({ type }) {
...@@ -47,7 +54,7 @@ export default { ...@@ -47,7 +54,7 @@ export default {
</script> </script>
<template> <template>
<div> <gl-form-group :disabled="disabled">
<component <component
:is="componentForEntity(entity)" :is="componentForEntity(entity)"
v-for="entity in entities" v-for="entity in entities"
...@@ -56,5 +63,5 @@ export default { ...@@ -56,5 +63,5 @@ export default {
v-bind="entity" v-bind="entity"
@input="onInput(entity.field, $event)" @input="onInput(entity.field, $event)"
/> />
</div> </gl-form-group>
</template> </template>
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import AnalyzerConfiguration from 'ee/security_configuration/sast/components/analyzer_configuration.vue'; import AnalyzerConfiguration from 'ee/security_configuration/sast/components/analyzer_configuration.vue';
import DynamicFields from 'ee/security_configuration/sast/components/dynamic_fields.vue';
describe('AnalyzerConfiguration component', () => { describe('AnalyzerConfiguration component', () => {
let wrapper; let wrapper;
...@@ -20,6 +21,7 @@ describe('AnalyzerConfiguration component', () => { ...@@ -20,6 +21,7 @@ describe('AnalyzerConfiguration component', () => {
}; };
const findInputElement = () => wrapper.find('input[type="checkbox"]'); const findInputElement = () => wrapper.find('input[type="checkbox"]');
const findDynamicFields = () => wrapper.find(DynamicFields);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -66,4 +68,60 @@ describe('AnalyzerConfiguration component', () => { ...@@ -66,4 +68,60 @@ describe('AnalyzerConfiguration component', () => {
}); });
}); });
}); });
describe('configuration form', () => {
describe('when there are no SastCiConfigurationEntity', () => {
beforeEach(() => {
createComponent({
props: { entity },
});
});
it('does not render the nested dynamic forms', () => {
expect(findDynamicFields().exists()).toBe(false);
});
});
describe('when there are one or more SastCiConfigurationEntity', () => {
const analyzerEntity = {
...entity,
enabled: false,
configuration: [
{
defaultValue: 'defaultVal',
description: 'desc',
field: 'field',
type: 'string',
value: 'val',
label: 'label',
},
],
};
beforeEach(() => {
createComponent({
props: { entity: analyzerEntity },
});
});
it('it renders the nested dynamic forms', () => {
expect(findDynamicFields().exists()).toBe(true);
});
it('it emits an input event when dynamic form fields emits an input event', () => {
findDynamicFields().vm.$emit('input', analyzerEntity.configuration);
const [[payload]] = wrapper.emitted('input');
expect(payload).toEqual(analyzerEntity);
});
it('passes the disabled prop to dynamic fields component', () => {
expect(findDynamicFields().props('disabled')).toBe(!analyzerEntity.enabled);
});
it('passes the entities prop to the dynamic fields component', () => {
expect(findDynamicFields().props('entities')).toBe(analyzerEntity.configuration);
});
});
});
}); });
import { shallowMount } from '@vue/test-utils'; import { shallowMount, mount } from '@vue/test-utils';
import DynamicFields from 'ee/security_configuration/sast/components/dynamic_fields.vue'; import DynamicFields from 'ee/security_configuration/sast/components/dynamic_fields.vue';
import { makeEntities } from './helpers'; import { makeEntities } from './helpers';
describe('DynamicFields component', () => { describe('DynamicFields component', () => {
let wrapper; let wrapper;
const createComponent = (props = {}) => { const createComponent = (props = {}, mountFn = shallowMount) => {
wrapper = shallowMount(DynamicFields, { wrapper = mountFn(DynamicFields, {
propsData: { propsData: {
...props, ...props,
}, },
...@@ -34,6 +34,21 @@ describe('DynamicFields component', () => { ...@@ -34,6 +34,21 @@ describe('DynamicFields component', () => {
}); });
}); });
describe.each([true, false])('given the disabled prop is %p', disabled => {
beforeEach(() => {
createComponent({ entities: [], disabled }, mount);
});
it('uses a fieldset as the root element', () => {
expect(wrapper.element.tagName).toBe('FIELDSET');
});
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/fieldset#attr-disabled
it(`${disabled ? 'sets' : 'does not set'} the disabled attribute on the root element`, () => {
expect('disabled' in wrapper.attributes()).toBe(disabled);
});
});
describe('given valid entities', () => { describe('given valid entities', () => {
let entities; let entities;
let fields; let fields;
......
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