summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/feature_flags/components/strategies
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/feature_flags/components/strategies')
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/default.vue10
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/flexible_rollout.vue121
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/gitlab_user_list.vue63
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/parameter_form_group.vue22
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/percent_rollout.vue69
-rw-r--r--app/assets/javascripts/feature_flags/components/strategies/users_with_id.vue47
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>