diff options
Diffstat (limited to 'app/assets/javascripts/feature_flags/components/strategies')
6 files changed, 332 insertions, 0 deletions
diff --git a/app/assets/javascripts/feature_flags/components/strategies/default.vue b/app/assets/javascripts/feature_flags/components/strategies/default.vue new file mode 100644 index 00000000000..cb8ffbddfbd --- /dev/null +++ b/app/assets/javascripts/feature_flags/components/strategies/default.vue @@ -0,0 +1,10 @@ +<script> +export default { + mounted() { + this.$emit('change', { parameters: {} }); + }, + render() { + return this.$slots.default; + }, +}; +</script> diff --git a/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue b/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue new file mode 100644 index 00000000000..020a0d43096 --- /dev/null +++ b/app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue @@ -0,0 +1,121 @@ +<script> +import { GlFormInput, GlFormSelect } from '@gitlab/ui'; +import { __ } from '~/locale'; +import { PERCENT_ROLLOUT_GROUP_ID } from '../../constants'; +import ParameterFormGroup from './parameter_form_group.vue'; + +export default { + components: { + GlFormInput, + GlFormSelect, + ParameterFormGroup, + }, + props: { + strategy: { + required: true, + type: Object, + }, + }, + i18n: { + percentageDescription: __('Enter a whole number between 0 and 100'), + percentageInvalid: __('Percent rollout must be a whole number between 0 and 100'), + percentageLabel: __('Percentage'), + stickinessDescription: __('Consistency guarantee method'), + stickinessLabel: __('Based on'), + }, + stickinessOptions: [ + { + value: 'DEFAULT', + text: __('Available ID'), + }, + { + value: 'USERID', + text: __('User ID'), + }, + { + value: 'SESSIONID', + text: __('Session ID'), + }, + { + value: 'RANDOM', + text: __('Random'), + }, + ], + computed: { + isValid() { + const percentageNum = Number(this.percentage); + return Number.isInteger(percentageNum) && percentageNum >= 0 && percentageNum <= 100; + }, + percentage() { + return this.strategy?.parameters?.rollout ?? '100'; + }, + stickiness() { + return this.strategy?.parameters?.stickiness ?? this.$options.stickinessOptions[0].value; + }, + }, + methods: { + onPercentageChange(value) { + this.$emit('change', { + parameters: { + groupId: PERCENT_ROLLOUT_GROUP_ID, + rollout: value, + stickiness: this.stickiness, + }, + }); + }, + onStickinessChange(value) { + this.$emit('change', { + parameters: { + groupId: PERCENT_ROLLOUT_GROUP_ID, + rollout: this.percentage, + stickiness: value, + }, + }); + }, + }, +}; +</script> +<template> + <div class="gl-display-flex"> + <div class="gl-mr-7" data-testid="strategy-flexible-rollout-percentage"> + <parameter-form-group + :label="$options.i18n.percentageLabel" + :description="isValid ? $options.i18n.percentageDescription : ''" + :invalid-feedback="$options.i18n.percentageInvalid" + :state="isValid" + > + <template #default="{ inputId }"> + <div class="gl-display-flex gl-align-items-center"> + <gl-form-input + :id="inputId" + :value="percentage" + :state="isValid" + class="rollout-percentage gl-text-right gl-w-9" + type="number" + min="0" + max="100" + @input="onPercentageChange" + /> + <span class="ml-1">%</span> + </div> + </template> + </parameter-form-group> + </div> + + <div class="gl-mr-7" data-testid="strategy-flexible-rollout-stickiness"> + <parameter-form-group + :label="$options.i18n.stickinessLabel" + :description="$options.i18n.stickinessDescription" + > + <template #default="{ inputId }"> + <gl-form-select + :id="inputId" + :value="stickiness" + :options="$options.stickinessOptions" + @change="onStickinessChange" + /> + </template> + </parameter-form-group> + </div> + </div> +</template> diff --git a/app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue b/app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue new file mode 100644 index 00000000000..ec97e8b1350 --- /dev/null +++ b/app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue @@ -0,0 +1,63 @@ +<script> +import { GlFormSelect } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import ParameterFormGroup from './parameter_form_group.vue'; + +export default { + components: { + GlFormSelect, + ParameterFormGroup, + }, + props: { + strategy: { + required: true, + type: Object, + }, + userLists: { + required: false, + type: Array, + default: () => [], + }, + }, + translations: { + rolloutUserListLabel: s__('FeatureFlag|List'), + rolloutUserListDescription: s__('FeatureFlag|Select a user list'), + rolloutUserListNoListError: s__('FeatureFlag|There are no configured user lists'), + }, + computed: { + userListOptions() { + return this.userLists.map(({ name, id }) => ({ value: id, text: name })); + }, + hasUserLists() { + return this.userListOptions.length > 0; + }, + userListId() { + return this.strategy?.userListId ?? ''; + }, + }, + methods: { + onUserListChange(list) { + this.$emit('change', { + userListId: list, + }); + }, + }, +}; +</script> +<template> + <parameter-form-group + :state="hasUserLists" + :invalid-feedback="$options.translations.rolloutUserListNoListError" + :label="$options.translations.rolloutUserListLabel" + :description="hasUserLists ? $options.translations.rolloutUserListDescription : ''" + > + <template #default="{ inputId }"> + <gl-form-select + :id="inputId" + :value="userListId" + :options="userListOptions" + @change="onUserListChange" + /> + </template> + </parameter-form-group> +</template> diff --git a/app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue b/app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue new file mode 100644 index 00000000000..7f2c6d55db8 --- /dev/null +++ b/app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue @@ -0,0 +1,22 @@ +<script> +import { uniqueId } from 'lodash'; +import { GlFormGroup } from '@gitlab/ui'; + +export default { + components: { + GlFormGroup, + }, + props: { + inputId: { + required: false, + type: String, + default: () => uniqueId('feature_flag_strategies_'), + }, + }, +}; +</script> +<template> + <gl-form-group :label-for="inputId" v-bind="$attrs"> + <slot v-bind="{ inputId }"></slot> + </gl-form-group> +</template> diff --git a/app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue b/app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue new file mode 100644 index 00000000000..d262769c891 --- /dev/null +++ b/app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue @@ -0,0 +1,69 @@ +<script> +import { GlFormInput } from '@gitlab/ui'; +import { s__, __ } from '~/locale'; +import { PERCENT_ROLLOUT_GROUP_ID } from '../../constants'; +import ParameterFormGroup from './parameter_form_group.vue'; + +export default { + components: { + GlFormInput, + ParameterFormGroup, + }, + props: { + strategy: { + required: true, + type: Object, + }, + }, + i18n: { + rolloutPercentageDescription: __('Enter a whole number between 0 and 100'), + rolloutPercentageInvalid: s__( + 'FeatureFlags|Percent rollout must be a whole number between 0 and 100', + ), + rolloutPercentageLabel: s__('FeatureFlag|Percentage'), + }, + computed: { + isValid() { + const percentageNum = Number(this.percentage); + return Number.isInteger(percentageNum) && percentageNum >= 0 && percentageNum <= 100; + }, + percentage() { + return this.strategy?.parameters?.percentage ?? '100'; + }, + }, + methods: { + onPercentageChange(value) { + this.$emit('change', { + parameters: { + percentage: value, + groupId: PERCENT_ROLLOUT_GROUP_ID, + }, + }); + }, + }, +}; +</script> +<template> + <parameter-form-group + :label="$options.i18n.rolloutPercentageLabel" + :description="isValid ? $options.i18n.rolloutPercentageDescription : ''" + :invalid-feedback="$options.i18n.rolloutPercentageInvalid" + :state="isValid" + > + <template #default="{ inputId }"> + <div class="gl-display-flex gl-align-items-center"> + <gl-form-input + :id="inputId" + :value="percentage" + :state="isValid" + class="rollout-percentage gl-text-right gl-w-9" + type="number" + min="0" + max="100" + @input="onPercentageChange" + /> + <span class="gl-ml-2">%</span> + </div> + </template> + </parameter-form-group> +</template> diff --git a/app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue b/app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue new file mode 100644 index 00000000000..094127fb710 --- /dev/null +++ b/app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue @@ -0,0 +1,47 @@ +<script> +import { GlFormTextarea } from '@gitlab/ui'; +import { __, s__ } from '~/locale'; + +import ParameterFormGroup from './parameter_form_group.vue'; + +export default { + components: { + ParameterFormGroup, + GlFormTextarea, + }, + props: { + strategy: { + required: true, + type: Object, + }, + }, + translations: { + rolloutUserIdsDescription: __('Enter one or more user ID separated by commas'), + rolloutUserIdsLabel: s__('FeatureFlag|User IDs'), + }, + computed: { + userIds() { + return this.strategy?.parameters?.userIds ?? ''; + }, + }, + methods: { + onUserIdsChange(value) { + this.$emit('change', { + parameters: { + userIds: value, + }, + }); + }, + }, +}; +</script> +<template> + <parameter-form-group + :label="$options.translations.rolloutUserIdsLabel" + :description="$options.translations.rolloutUserIdsDescription" + > + <template #default="{ inputId }"> + <gl-form-textarea :id="inputId" :value="userIds" @input="onUserIdsChange" /> + </template> + </parameter-form-group> +</template> |