Skip to content
代码片段 群组 项目
提交 58eae6d9 编辑于 作者: Peter Hegman's avatar Peter Hegman
浏览文件

Add visibility level field

To form for adding new group to organization.
上级 f97767af
No related branches found
No related tags found
无相关合并请求
显示
281 个添加3 个删除
......@@ -11,7 +11,7 @@ const DEBOUNCE_DURATION = 1000;
export default {
i18n: {
placeholder: __('My awesome group'),
placeholder: __('my-awesome-group'),
apiErrorMessage: __(
'An error occurred while checking group path. Please refresh and try again.',
),
......
......@@ -3,7 +3,13 @@ import { GlForm, GlFormFields, GlButton } from '@gitlab/ui';
import { formValidators } from '@gitlab/ui/dist/utils';
import { __, s__, sprintf } from '~/locale';
import { slugify } from '~/lib/utils/text_utility';
import { FORM_FIELD_NAME, FORM_FIELD_PATH } from '../constants';
import VisibilityLevelRadioButtons from '~/visibility_level/components/visibility_level_radio_buttons.vue';
import {
VISIBILITY_LEVEL_PRIVATE_INTEGER,
GROUP_VISIBILITY_LEVEL_DESCRIPTIONS,
} from '~/visibility_level/constants';
import { restrictedVisibilityLevelsMessage } from '~/visibility_level/utils';
import { FORM_FIELD_NAME, FORM_FIELD_PATH, FORM_FIELD_VISIBILITY_LEVEL } from '../constants';
import GroupPathField from './group_path_field.vue';
export default {
......@@ -13,11 +19,13 @@ export default {
GlFormFields,
GlButton,
GroupPathField,
VisibilityLevelRadioButtons,
},
i18n: {
cancel: __('Cancel'),
submitButtonText: __('Create group'),
},
GROUP_VISIBILITY_LEVEL_DESCRIPTIONS,
formId: 'organization-new-group-form',
props: {
basePath: {
......@@ -36,6 +44,14 @@ export default {
required: true,
type: String,
},
availableVisibilityLevels: {
type: Array,
required: true,
},
restrictedVisibilityLevels: {
type: Array,
required: true,
},
},
data() {
return {
......@@ -44,6 +60,7 @@ export default {
formValues: {
[FORM_FIELD_NAME]: '',
[FORM_FIELD_PATH]: '',
[FORM_FIELD_VISIBILITY_LEVEL]: VISIBILITY_LEVEL_PRIVATE_INTEGER,
},
};
},
......@@ -90,6 +107,15 @@ export default {
: null,
},
},
[FORM_FIELD_VISIBILITY_LEVEL]: {
label: __('Visibility level'),
groupAttrs: {
description: restrictedVisibilityLevelsMessage({
availableVisibilityLevels: this.availableVisibilityLevels,
restrictedVisibilityLevels: this.restrictedVisibilityLevels,
}),
},
},
};
},
},
......@@ -134,6 +160,14 @@ export default {
@loading-change="onPathLoading"
/>
</template>
<template #input(visibilityLevel)="{ value, input }">
<visibility-level-radio-buttons
:checked="value"
:visibility-levels="availableVisibilityLevels"
:visibility-level-descriptions="$options.GROUP_VISIBILITY_LEVEL_DESCRIPTIONS"
@input="input"
/>
</template>
</gl-form-fields>
<div class="gl-display-flex gl-gap-3">
<gl-button
......
......@@ -64,3 +64,4 @@ export const OVERVIEW_TABS_ARCHIVED_PROJECTS_SORTING_ITEMS = [
export const FORM_FIELD_NAME = 'name';
export const FORM_FIELD_PATH = 'path';
export const FORM_FIELD_VISIBILITY_LEVEL = 'visibilityLevel';
......@@ -57,6 +57,8 @@ export default {
:path-maxlength="pathMaxlength"
:path-pattern="pathPattern"
:cancel-path="groupsOrganizationPath"
:available-visibility-levels="availableVisibilityLevels"
:restricted-visibility-levels="restrictedVisibilityLevels"
/>
</div>
</template>
<script>
import { GlIcon, GlFormRadio, GlFormRadioGroup } from '@gitlab/ui';
import {
VISIBILITY_LEVEL_LABELS,
VISIBILITY_TYPE_ICON,
VISIBILITY_LEVELS_INTEGER_TO_STRING,
} from '~/visibility_level/constants';
export default {
name: 'VisibilityLevelRadioButtons',
components: {
GlIcon,
GlFormRadio,
GlFormRadioGroup,
},
model: {
prop: 'checked',
},
props: {
checked: {
type: Number,
required: true,
},
visibilityLevels: {
type: Array,
required: true,
},
visibilityLevelDescriptions: {
type: Object,
required: true,
},
},
computed: {
visibilityLevelsOptions() {
return this.visibilityLevels.map((visibilityLevel) => {
const stringValue = VISIBILITY_LEVELS_INTEGER_TO_STRING[visibilityLevel];
return {
label: VISIBILITY_LEVEL_LABELS[stringValue],
description: this.visibilityLevelDescriptions[stringValue],
icon: VISIBILITY_TYPE_ICON[stringValue],
value: visibilityLevel,
};
});
},
},
};
</script>
<template>
<gl-form-radio-group :checked="checked" @input="$emit('input', $event)">
<gl-form-radio
v-for="{ label, description, icon, value } in visibilityLevelsOptions"
:key="value"
:value="value"
>
<div>
<gl-icon :name="icon" />
<span>{{ label }}</span>
</div>
<template #help>{{ description }}</template>
</gl-form-radio>
</gl-form-radio-group>
</template>
......@@ -51,6 +51,24 @@ export const ORGANIZATION_VISIBILITY_TYPE = {
),
};
export const GROUP_VISIBILITY_LEVEL_DESCRIPTIONS = {
[VISIBILITY_LEVEL_PUBLIC_STRING]: s__(
'VisibilityLevel|The group and any public projects can be viewed without any authentication.',
),
[VISIBILITY_LEVEL_INTERNAL_STRING]: s__(
'VisibilityLevel|The group and any internal projects can be viewed by any logged in user except external users.',
),
[VISIBILITY_LEVEL_PRIVATE_STRING]: s__(
'VisibilityLevel|The group and its projects can only be viewed by members.',
),
};
export const VISIBILITY_LEVEL_LABELS = {
[VISIBILITY_LEVEL_PUBLIC_STRING]: s__('VisibilityLevel|Public'),
[VISIBILITY_LEVEL_INTERNAL_STRING]: s__('VisibilityLevel|Internal'),
[VISIBILITY_LEVEL_PRIVATE_STRING]: s__('VisibilityLevel|Private'),
};
export const VISIBILITY_TYPE_ICON = {
[VISIBILITY_LEVEL_PUBLIC_STRING]: 'earth',
[VISIBILITY_LEVEL_INTERNAL_STRING]: 'shield',
......
import { __ } from '~/locale';
export const restrictedVisibilityLevelsMessage = ({
availableVisibilityLevels,
restrictedVisibilityLevels,
}) => {
if (!restrictedVisibilityLevels.length) {
return '';
}
if (!availableVisibilityLevels.length) {
return __('Visibility settings have been disabled by the administrator.');
}
return __('Other visibility settings have been disabled by the administrator.');
};
......@@ -2,6 +2,13 @@ import { nextTick } from 'vue';
import NewGroupForm from '~/groups/components/new_group_form.vue';
import GroupPathField from '~/groups/components/group_path_field.vue';
import VisibilityLevelRadioButtons from '~/visibility_level/components/visibility_level_radio_buttons.vue';
import {
VISIBILITY_LEVELS_STRING_TO_INTEGER,
VISIBILITY_LEVEL_PRIVATE_INTEGER,
VISIBILITY_LEVEL_PUBLIC_INTEGER,
GROUP_VISIBILITY_LEVEL_DESCRIPTIONS,
} from '~/visibility_level/constants';
import { mountExtended } from 'helpers/vue_test_utils_helper';
describe('NewGroupForm', () => {
......@@ -12,6 +19,8 @@ describe('NewGroupForm', () => {
cancelPath: '/-/organizations/default/groups_and_projects?display=groups',
pathMaxlength: 10,
pathPattern: '[a-zA-Z0-9_\\.][a-zA-Z0-9_\\-\\.]{0,254}[a-zA-Z0-9_\\-]|[a-zA-Z0-9_]',
availableVisibilityLevels: Object.values(VISIBILITY_LEVELS_STRING_TO_INTEGER),
restrictedVisibilityLevels: [],
};
const createComponent = ({ propsData = {} } = {}) => {
......@@ -29,11 +38,16 @@ describe('NewGroupForm', () => {
const findNameField = () => wrapper.findByLabelText('Group name');
const findPathField = () => wrapper.findComponent(GroupPathField);
const findVisibilityLevelField = () => wrapper.findComponent(VisibilityLevelRadioButtons);
const setPathFieldValue = async (value) => {
findPathField().vm.$emit('input', value);
await nextTick();
};
const setVisibilityLevelFieldValue = async (value) => {
findVisibilityLevelField().vm.$emit('input', value);
await nextTick();
};
const submitForm = async () => {
await wrapper.findByRole('button', { name: 'Create group' }).trigger('click');
};
......@@ -50,6 +64,16 @@ describe('NewGroupForm', () => {
expect(findPathField().exists()).toBe(true);
});
it('renders `Visibility level` field with correct props', () => {
createComponent();
expect(findVisibilityLevelField().props()).toMatchObject({
checked: VISIBILITY_LEVEL_PRIVATE_INTEGER,
visibilityLevels: defaultPropsData.availableVisibilityLevels,
visibilityLevelDescriptions: GROUP_VISIBILITY_LEVEL_DESCRIPTIONS,
});
});
describe('when form is submitted without filling in required fields', () => {
beforeEach(async () => {
createComponent();
......@@ -127,11 +151,14 @@ describe('NewGroupForm', () => {
createComponent();
await findNameField().setValue('Foo bar');
await setVisibilityLevelFieldValue(VISIBILITY_LEVEL_PUBLIC_INTEGER);
await submitForm();
});
it('emits `submit` event with form values', () => {
expect(wrapper.emitted('submit')).toEqual([[{ name: 'Foo bar', path: 'foo-bar' }]]);
expect(wrapper.emitted('submit')).toEqual([
[{ name: 'Foo bar', path: 'foo-bar', visibilityLevel: VISIBILITY_LEVEL_PUBLIC_INTEGER }],
]);
});
});
......
......@@ -56,6 +56,8 @@ describe('OrganizationGroupsNewApp', () => {
cancelPath: '/-/organizations/carrot/groups_and_projects?display=groups',
pathMaxlength: 10,
pathPattern: 'mockPattern',
availableVisibilityLevels: defaultProvide.availableVisibilityLevels,
restrictedVisibilityLevels: defaultProvide.restrictedVisibilityLevels,
});
});
});
import { GlIcon, GlFormRadio, GlFormRadioGroup } from '@gitlab/ui';
import {
VISIBILITY_LEVEL_PRIVATE_INTEGER,
VISIBILITY_LEVEL_PUBLIC_INTEGER,
VISIBILITY_LEVELS_STRING_TO_INTEGER,
GROUP_VISIBILITY_LEVEL_DESCRIPTIONS,
} from '~/visibility_level/constants';
import VisibilityLevelRadioButtons from '~/visibility_level/components/visibility_level_radio_buttons.vue';
import { mountExtended } from 'helpers/vue_test_utils_helper';
describe('VisibilityLevelRadioButtons', () => {
let wrapper;
const defaultPropsData = {
checked: VISIBILITY_LEVEL_PRIVATE_INTEGER,
visibilityLevels: Object.values(VISIBILITY_LEVELS_STRING_TO_INTEGER),
visibilityLevelDescriptions: GROUP_VISIBILITY_LEVEL_DESCRIPTIONS,
};
const createComponent = ({ propsData = {} } = {}) => {
wrapper = mountExtended(VisibilityLevelRadioButtons, {
propsData: {
...defaultPropsData,
...propsData,
},
});
};
const findRadioGroup = () => wrapper.findComponent(GlFormRadioGroup);
it('renders radio group with `checked` prop correctly set', () => {
createComponent();
expect(findRadioGroup().vm.$attrs.checked).toBe(defaultPropsData.checked);
});
describe('when radio group emits `input` event', () => {
beforeEach(() => {
createComponent();
findRadioGroup().vm.$emit('input', VISIBILITY_LEVEL_PUBLIC_INTEGER);
});
it('emits `input` event', () => {
expect(wrapper.emitted('input')).toEqual([[VISIBILITY_LEVEL_PUBLIC_INTEGER]]);
});
});
it('renders visibility level radio buttons with label, description, and icon', () => {
createComponent();
const radioButtons = wrapper.findAllComponents(GlFormRadio);
expect(radioButtons.at(0).text()).toMatchInterpolatedText(
'Private The group and its projects can only be viewed by members.',
);
expect(radioButtons.at(0).findComponent(GlIcon).props('name')).toBe('lock');
expect(radioButtons.at(1).text()).toMatchInterpolatedText(
'Internal The group and any internal projects can be viewed by any logged in user except external users.',
);
expect(radioButtons.at(1).findComponent(GlIcon).props('name')).toBe('shield');
expect(radioButtons.at(2).text()).toMatchInterpolatedText(
'Public The group and any public projects can be viewed without any authentication.',
);
expect(radioButtons.at(2).findComponent(GlIcon).props('name')).toBe('earth');
});
});
import { restrictedVisibilityLevelsMessage } from '~/visibility_level/utils';
import {
VISIBILITY_LEVELS_STRING_TO_INTEGER,
VISIBILITY_LEVEL_PRIVATE_INTEGER,
VISIBILITY_LEVEL_INTERNAL_INTEGER,
VISIBILITY_LEVEL_PUBLIC_INTEGER,
} from '~/visibility_level/constants';
describe('restrictedVisibilityLevelsMessage', () => {
describe('when no levels are restricted', () => {
it('returns empty string', () => {
expect(
restrictedVisibilityLevelsMessage({
availableVisibilityLevels: Object.values(VISIBILITY_LEVELS_STRING_TO_INTEGER),
restrictedVisibilityLevels: [],
}),
).toBe('');
});
});
describe('when some levels have been restricted', () => {
it('returns expected message', () => {
expect(
restrictedVisibilityLevelsMessage({
availableVisibilityLevels: [VISIBILITY_LEVEL_PRIVATE_INTEGER],
restrictedVisibilityLevels: [
VISIBILITY_LEVEL_INTERNAL_INTEGER,
VISIBILITY_LEVEL_PUBLIC_INTEGER,
],
}),
).toBe('Other visibility settings have been disabled by the administrator.');
});
});
describe('when all visibility levels are restricted', () => {
it('returns expected message', () => {
expect(
restrictedVisibilityLevelsMessage({
availableVisibilityLevels: [],
restrictedVisibilityLevels: Object.values(VISIBILITY_LEVELS_STRING_TO_INTEGER),
}),
).toBe('Visibility settings have been disabled by the administrator.');
});
});
});
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册