gitlab-ce/app/assets/javascripts/groups/components/new_edit_form.vue

263 lines
7.8 KiB
Vue

<script>
import { GlForm, GlFormFields, GlButton, GlLink, GlAlert, GlSprintf } from '@gitlab/ui';
import { formValidators } from '@gitlab/ui/dist/utils';
import { __, s__, sprintf } from '~/locale';
import { slugify } from '~/lib/utils/text_utility';
import VisibilityLevelRadioButtons from '~/visibility_level/components/visibility_level_radio_buttons.vue';
import { GROUP_VISIBILITY_LEVEL_DESCRIPTIONS } from '~/visibility_level/constants';
import { restrictedVisibilityLevelsMessage } from '~/visibility_level/utils';
import { helpPagePath } from '~/helpers/help_page_helper';
import HelpPageLink from '~/vue_shared/components/help_page_link/help_page_link.vue';
import {
FORM_FIELD_NAME,
FORM_FIELD_PATH,
FORM_FIELD_ID,
FORM_FIELD_VISIBILITY_LEVEL,
} from '../constants';
import GroupPathField from './group_path_field.vue';
export default {
name: 'NewEditForm',
components: {
GlForm,
GlFormFields,
GlButton,
GlLink,
GlAlert,
GlSprintf,
GroupPathField,
VisibilityLevelRadioButtons,
HelpPageLink,
},
i18n: {
cancel: __('Cancel'),
warningForUsingDotInName: s__(
'Groups|Your group name must not contain a period if you intend to use SCIM integration, as it can lead to errors.',
),
warningForChangingUrl: s__(
'Groups|Changing group URL can have unintended side effects. %{linkStart}Learn more%{linkEnd}.',
),
},
GROUP_VISIBILITY_LEVEL_DESCRIPTIONS,
formId: 'organization-new-group-form',
props: {
loading: {
type: Boolean,
required: true,
},
basePath: {
type: String,
required: true,
},
submitButtonText: {
type: String,
required: false,
default: __('Create group'),
},
cancelPath: {
type: String,
required: true,
},
pathMaxlength: {
required: true,
type: Number,
},
pathPattern: {
required: true,
type: String,
},
availableVisibilityLevels: {
type: Array,
required: true,
},
restrictedVisibilityLevels: {
type: Array,
required: true,
},
initialFormValues: {
type: Object,
required: true,
},
},
data() {
return {
hasPathBeenManuallySet: this.initialFormValues[FORM_FIELD_PATH],
isPathLoading: false,
formValues: this.initialFormValues,
};
},
computed: {
fields() {
return {
[FORM_FIELD_NAME]: {
label: s__('Groups|Group name'),
validators: [
formValidators.required(s__('Groups|Enter a descriptive name for your group.')),
],
inputAttrs: {
width: { md: 'lg' },
placeholder: __('My awesome group'),
},
groupAttrs: {
description: s__(
'Groups|Must start with letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses.',
),
},
},
[FORM_FIELD_PATH]: {
label: s__('Groups|Group URL'),
validators: [
formValidators.required(s__('Groups|Enter a path for your group.')),
formValidators.factory(
sprintf(s__('GroupSettings|Group path cannot be longer than %{length} characters.'), {
length: this.pathMaxlength,
}),
(val) => val.length <= this.pathMaxlength,
),
formValidators.factory(
s__(
'GroupSettings|Choose a group path that does not start with a dash or end with a period. It can also contain alphanumeric characters and underscores.',
),
(val) => {
return new RegExp(`^(${this.pathPattern})$`).test(val);
},
),
],
groupAttrs: {
description: this.isPathLoading ? s__('Groups|Checking group URL availability…') : null,
},
},
...(this.isEditing
? {
[FORM_FIELD_ID]: {
label: s__('Groups|Group ID'),
groupAttrs: {
class: 'gl-w-full',
},
inputAttrs: {
class: 'gl-md-form-input-lg',
disabled: true,
},
},
}
: {}),
[FORM_FIELD_VISIBILITY_LEVEL]: {
label: __('Visibility level'),
labelDescription: {
text: __('Who will be able to see this group?'),
linkText: __('Learn more'),
linkHref: helpPagePath('user/public_access'),
},
groupAttrs: {
// eslint-disable-next-line @gitlab/require-i18n-strings
'data-testid': `${FORM_FIELD_VISIBILITY_LEVEL}-group`,
description: restrictedVisibilityLevelsMessage({
availableVisibilityLevels: this.availableVisibilityLevels,
restrictedVisibilityLevels: this.restrictedVisibilityLevels,
}),
},
},
};
},
isEditing() {
return Boolean(this.initialFormValues[FORM_FIELD_ID]);
},
},
watch: {
[`formValues.${FORM_FIELD_NAME}`](newName) {
if (this.hasPathBeenManuallySet) {
return;
}
this.formValues[FORM_FIELD_PATH] = slugify(newName);
},
},
methods: {
onPathInput(event, formFieldsInputEvent) {
formFieldsInputEvent(event);
this.hasPathBeenManuallySet = true;
},
onPathLoading(value) {
this.isPathLoading = value;
},
},
};
</script>
<template>
<gl-form :id="$options.formId">
<gl-form-fields
v-model="formValues"
:form-id="$options.formId"
:fields="fields"
@submit="$emit('submit', formValues)"
>
<template #after(name)>
<gl-alert
class="gl-mb-5"
:dismissible="false"
variant="warning"
data-testid="dot-in-path-alert"
>
{{ $options.i18n.warningForUsingDotInName }}
</gl-alert>
</template>
<template #input(path)="{ id, value, validation, input, blur }">
<group-path-field
:id="id"
:value="value"
:state="validation.state"
:base-path="basePath"
:is-editing="isEditing"
@input="onPathInput($event, input)"
@input-suggested-path="input"
@blur="blur"
@loading-change="onPathLoading"
/>
</template>
<template v-if="isEditing" #after(path)>
<gl-alert
class="gl-mb-5"
:dismissible="false"
variant="warning"
data-testid="changing-url-alert"
>
<gl-sprintf :message="$options.i18n.warningForChangingUrl">
<template #link="{ content }">
<help-page-link href="user/group/manage" anchor="change-a-groups-path">{{
content
}}</help-page-link>
</template>
</gl-sprintf>
</gl-alert>
</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>
<template #group(visibilityLevel)-label-description>
{{ fields.visibilityLevel.labelDescription.text }}
<gl-link :href="fields.visibilityLevel.labelDescription.linkHref">{{
fields.visibilityLevel.labelDescription.linkText
}}</gl-link
>.
</template>
</gl-form-fields>
<div class="gl-flex gl-gap-3">
<gl-button
type="submit"
variant="confirm"
:loading="loading"
class="js-no-auto-disable"
data-testid="submit-button"
>{{ submitButtonText }}</gl-button
>
<gl-button :href="cancelPath">{{ $options.i18n.cancel }}</gl-button>
</div>
</gl-form>
</template>