Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/user_lists/components')
-rw-r--r--app/assets/javascripts/user_lists/components/add_user_modal.vue72
-rw-r--r--app/assets/javascripts/user_lists/components/edit_user_list.vue74
-rw-r--r--app/assets/javascripts/user_lists/components/new_user_list.vue50
-rw-r--r--app/assets/javascripts/user_lists/components/user_list.vue142
-rw-r--r--app/assets/javascripts/user_lists/components/user_list_form.vue97
5 files changed, 435 insertions, 0 deletions
diff --git a/app/assets/javascripts/user_lists/components/add_user_modal.vue b/app/assets/javascripts/user_lists/components/add_user_modal.vue
new file mode 100644
index 00000000000..a8dde1f681e
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/add_user_modal.vue
@@ -0,0 +1,72 @@
+<script>
+import { GlModal, GlFormGroup, GlFormTextarea } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import { ADD_USER_MODAL_ID } from '../constants/show';
+
+export default {
+ components: {
+ GlFormGroup,
+ GlFormTextarea,
+ GlModal,
+ },
+ props: {
+ visible: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ modalOptions: {
+ actionPrimary: {
+ text: s__('UserLists|Add'),
+ attributes: [{ 'data-testid': 'confirm-add-user-ids' }],
+ },
+ actionCancel: {
+ text: s__('UserLists|Cancel'),
+ attributes: [{ 'data-testid': 'cancel-add-user-ids' }],
+ },
+ modalId: ADD_USER_MODAL_ID,
+ static: true,
+ },
+ translations: {
+ title: s__('UserLists|Add users'),
+ description: s__(
+ 'UserLists|Enter a comma separated list of user IDs. These IDs should be the users of the system in which the feature flag is set, not GitLab IDs',
+ ),
+ userIdsLabel: s__('UserLists|User IDs'),
+ },
+ data() {
+ return {
+ userIds: '',
+ };
+ },
+ methods: {
+ submitUsers() {
+ this.$emit('addUsers', this.userIds);
+ this.clearInput();
+ },
+ clearInput() {
+ this.userIds = '';
+ },
+ },
+};
+</script>
+<template>
+ <gl-modal
+ v-bind="$options.modalOptions"
+ :visible="visible"
+ data-testid="add-users-modal"
+ @primary="submitUsers"
+ @canceled="clearInput"
+ >
+ <template #modal-title>
+ {{ $options.translations.title }}
+ </template>
+ <template #default>
+ <p data-testid="add-userids-description">{{ $options.translations.description }}</p>
+ <gl-form-group label-for="add-user-ids" :label="$options.translations.userIdsLabel">
+ <gl-form-textarea id="add-user-ids" v-model="userIds" />
+ </gl-form-group>
+ </template>
+ </gl-modal>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/edit_user_list.vue b/app/assets/javascripts/user_lists/components/edit_user_list.vue
new file mode 100644
index 00000000000..d56c3d61027
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/edit_user_list.vue
@@ -0,0 +1,74 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
+import { s__, sprintf } from '~/locale';
+import statuses from '../constants/edit';
+import UserListForm from './user_list_form.vue';
+
+export default {
+ components: {
+ GlAlert,
+ GlLoadingIcon,
+ UserListForm,
+ },
+ inject: ['userListsDocsPath'],
+ translations: {
+ saveButtonLabel: s__('UserLists|Save'),
+ },
+ computed: {
+ ...mapState(['userList', 'status', 'errorMessage']),
+ title() {
+ return sprintf(s__('UserLists|Edit %{name}'), { name: this.userList?.name });
+ },
+ isLoading() {
+ return this.status === statuses.LOADING;
+ },
+ isError() {
+ return this.status === statuses.ERROR;
+ },
+ hasUserList() {
+ return Boolean(this.userList);
+ },
+ },
+ mounted() {
+ this.fetchUserList();
+ },
+ methods: {
+ ...mapActions(['fetchUserList', 'updateUserList', 'dismissErrorAlert']),
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert
+ v-if="isError"
+ :dismissible="hasUserList"
+ variant="danger"
+ @dismiss="dismissErrorAlert"
+ >
+ <ul class="gl-mb-0">
+ <li v-for="(message, index) in errorMessage" :key="index">
+ {{ message }}
+ </li>
+ </ul>
+ </gl-alert>
+
+ <gl-loading-icon v-if="isLoading" size="xl" />
+
+ <template v-else-if="hasUserList">
+ <h3
+ data-testid="user-list-title"
+ class="gl-font-weight-bold gl-pb-5 gl-border-b-solid gl-border-gray-100 gl-border-1"
+ >
+ {{ title }}
+ </h3>
+ <user-list-form
+ :cancel-path="userList.path"
+ :save-button-label="$options.translations.saveButtonLabel"
+ :user-lists-docs-path="userListsDocsPath"
+ :user-list="userList"
+ @submit="updateUserList"
+ />
+ </template>
+ </div>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/new_user_list.vue b/app/assets/javascripts/user_lists/components/new_user_list.vue
new file mode 100644
index 00000000000..522e077fb25
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/new_user_list.vue
@@ -0,0 +1,50 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import { GlAlert } from '@gitlab/ui';
+import { s__ } from '~/locale';
+import UserListForm from './user_list_form.vue';
+
+export default {
+ components: {
+ GlAlert,
+ UserListForm,
+ },
+ inject: ['userListsDocsPath', 'featureFlagsPath'],
+ translations: {
+ pageTitle: s__('UserLists|New list'),
+ createButtonLabel: s__('UserLists|Create'),
+ },
+ computed: {
+ ...mapState(['userList', 'errorMessage']),
+ isError() {
+ return Array.isArray(this.errorMessage) && this.errorMessage.length > 0;
+ },
+ },
+ methods: {
+ ...mapActions(['createUserList', 'dismissErrorAlert']),
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert v-if="isError" variant="danger" @dismiss="dismissErrorAlert">
+ <ul class="gl-mb-0">
+ <li v-for="(message, index) in errorMessage" :key="index">
+ {{ message }}
+ </li>
+ </ul>
+ </gl-alert>
+
+ <h3 class="gl-font-weight-bold gl-pb-5 gl-border-b-solid gl-border-gray-100 gl-border-1">
+ {{ $options.translations.pageTitle }}
+ </h3>
+
+ <user-list-form
+ :cancel-path="featureFlagsPath"
+ :save-button-label="$options.translations.createButtonLabel"
+ :user-lists-docs-path="userListsDocsPath"
+ :user-list="userList"
+ @submit="createUserList"
+ />
+ </div>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/user_list.vue b/app/assets/javascripts/user_lists/components/user_list.vue
new file mode 100644
index 00000000000..0e2b72c1423
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/user_list.vue
@@ -0,0 +1,142 @@
+<script>
+import { mapActions, mapState } from 'vuex';
+import {
+ GlAlert,
+ GlButton,
+ GlEmptyState,
+ GlLoadingIcon,
+ GlModalDirective as GlModal,
+} from '@gitlab/ui';
+import { s__, __ } from '~/locale';
+import { states, ADD_USER_MODAL_ID } from '../constants/show';
+import AddUserModal from './add_user_modal.vue';
+
+const commonTableClasses = ['gl-py-5', 'gl-border-b-1', 'gl-border-b-solid', 'gl-border-gray-100'];
+
+export default {
+ components: {
+ GlAlert,
+ GlButton,
+ GlEmptyState,
+ GlLoadingIcon,
+ AddUserModal,
+ },
+ directives: {
+ GlModal,
+ },
+ props: {
+ emptyStatePath: {
+ required: true,
+ type: String,
+ },
+ },
+ translations: {
+ addUserButtonLabel: s__('UserLists|Add Users'),
+ emptyStateTitle: s__('UserLists|There are no users'),
+ emptyStateDescription: s__(
+ 'UserLists|Define a set of users to be used within feature flag strategies',
+ ),
+ userIdLabel: s__('UserLists|User IDs'),
+ userIdColumnHeader: s__('UserLists|User ID'),
+ errorMessage: __('Something went wrong on our end. Please try again!'),
+ editButtonLabel: s__('UserLists|Edit'),
+ },
+ classes: {
+ headerClasses: [
+ 'gl-display-flex',
+ 'gl-justify-content-space-between',
+ 'gl-pb-5',
+ 'gl-border-b-1',
+ 'gl-border-b-solid',
+ 'gl-border-gray-100',
+ ].join(' '),
+ tableHeaderClasses: commonTableClasses.join(' '),
+ tableRowClasses: [
+ ...commonTableClasses,
+ 'gl-display-flex',
+ 'gl-justify-content-space-between',
+ 'gl-align-items-center',
+ ].join(' '),
+ },
+ ADD_USER_MODAL_ID,
+ computed: {
+ ...mapState(['userList', 'userIds', 'state']),
+ name() {
+ return this.userList?.name ?? '';
+ },
+ hasUserIds() {
+ return this.userIds.length > 0;
+ },
+ isLoading() {
+ return this.state === states.LOADING;
+ },
+ hasError() {
+ return this.state === states.ERROR;
+ },
+ editPath() {
+ return this.userList?.edit_path;
+ },
+ },
+ mounted() {
+ this.fetchUserList();
+ },
+ methods: {
+ ...mapActions(['fetchUserList', 'dismissErrorAlert', 'removeUserId', 'addUserIds']),
+ },
+};
+</script>
+<template>
+ <div>
+ <gl-alert v-if="hasError" variant="danger" @dismiss="dismissErrorAlert">
+ {{ $options.translations.errorMessage }}
+ </gl-alert>
+ <gl-loading-icon v-if="isLoading" size="xl" class="gl-mt-6" />
+ <div v-else>
+ <add-user-modal @addUsers="addUserIds" />
+ <div :class="$options.classes.headerClasses">
+ <div>
+ <h3>{{ name }}</h3>
+ <h4 class="gl-text-gray-500">{{ $options.translations.userIdLabel }}</h4>
+ </div>
+ <div class="gl-mt-6">
+ <gl-button v-if="editPath" :href="editPath" data-testid="edit-user-list" class="gl-mr-3">
+ {{ $options.translations.editButtonLabel }}
+ </gl-button>
+ <gl-button
+ v-gl-modal="$options.ADD_USER_MODAL_ID"
+ data-testid="add-users"
+ variant="success"
+ >
+ {{ $options.translations.addUserButtonLabel }}
+ </gl-button>
+ </div>
+ </div>
+ <div v-if="hasUserIds">
+ <div :class="$options.classes.tableHeaderClasses">
+ {{ $options.translations.userIdColumnHeader }}
+ </div>
+ <div
+ v-for="id in userIds"
+ :key="id"
+ data-testid="user-id-row"
+ :class="$options.classes.tableRowClasses"
+ >
+ <span data-testid="user-id">{{ id }}</span>
+ <gl-button
+ category="secondary"
+ variant="danger"
+ icon="remove"
+ data-testid="delete-user-id"
+ @click="removeUserId(id)"
+ />
+ </div>
+ </div>
+ <gl-empty-state
+ v-else
+ :title="$options.translations.emptyStateTitle"
+ :description="$options.translations.emptyStateDescription"
+ :svg-path="emptyStatePath"
+ />
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/user_lists/components/user_list_form.vue b/app/assets/javascripts/user_lists/components/user_list_form.vue
new file mode 100644
index 00000000000..657acb51fee
--- /dev/null
+++ b/app/assets/javascripts/user_lists/components/user_list_form.vue
@@ -0,0 +1,97 @@
+<script>
+import { GlButton, GlFormGroup, GlFormInput, GlLink, GlSprintf } from '@gitlab/ui';
+import { s__ } from '~/locale';
+
+export default {
+ components: {
+ GlButton,
+ GlFormGroup,
+ GlFormInput,
+ GlLink,
+ GlSprintf,
+ },
+ props: {
+ cancelPath: {
+ type: String,
+ required: true,
+ },
+ saveButtonLabel: {
+ type: String,
+ required: true,
+ },
+ userListsDocsPath: {
+ type: String,
+ required: true,
+ },
+ userList: {
+ type: Object,
+ required: true,
+ },
+ },
+ classes: {
+ actionContainer: [
+ 'gl-py-5',
+ 'gl-display-flex',
+ 'gl-justify-content-space-between',
+ 'gl-px-4',
+ 'gl-border-t-solid',
+ 'gl-border-gray-100',
+ 'gl-border-1',
+ 'gl-bg-gray-10',
+ ],
+ },
+ translations: {
+ formLabel: s__('UserLists|Feature flag list'),
+ formSubtitle: s__(
+ 'UserLists|Lists allow you to define a set of users to be used with feature flags. %{linkStart}Read more about feature flag lists.%{linkEnd}',
+ ),
+ nameLabel: s__('UserLists|Name'),
+ cancelButtonLabel: s__('UserLists|Cancel'),
+ },
+ data() {
+ return {
+ name: this.userList.name,
+ };
+ },
+ methods: {
+ submit() {
+ this.$emit('submit', { ...this.userList, name: this.name });
+ },
+ },
+};
+</script>
+<template>
+ <div>
+ <div class="gl-display-flex gl-mt-7">
+ <div class="gl-flex-basis-0 gl-mr-7">
+ <h4 class="gl-min-width-fit-content gl-white-space-nowrap">
+ {{ $options.translations.formLabel }}
+ </h4>
+ <gl-sprintf :message="$options.translations.formSubtitle" class="gl-text-gray-500">
+ <template #link="{ content }">
+ <gl-link :href="userListsDocsPath" data-testid="user-list-docs-link">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
+ <div class="gl-flex-fill-1 gl-ml-7">
+ <gl-form-group
+ label-for="user-list-name"
+ :label="$options.translations.nameLabel"
+ class="gl-mb-7"
+ >
+ <gl-form-input id="user-list-name" v-model="name" data-testid="user-list-name" required />
+ </gl-form-group>
+ <div :class="$options.classes.actionContainer">
+ <gl-button variant="success" data-testid="save-user-list" @click="submit">
+ {{ saveButtonLabel }}
+ </gl-button>
+ <gl-button :href="cancelPath" data-testid="user-list-cancel">
+ {{ $options.translations.cancelButtonLabel }}
+ </gl-button>
+ </div>
+ </div>
+ </div>
+ </div>
+</template>