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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-04-20 14:43:17 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-04-20 14:43:17 +0300
commitdfc94207fec2d84314b1a5410cface22e8b369bd (patch)
treec54022f61ced104305889a64de080998a0dc773b /app/assets/javascripts/admin
parentb874efeff674f6bf0355d5d242ecf81c6f7155df (diff)
Add latest changes from gitlab-org/gitlab@15-11-stable-eev15.11.0-rc42
Diffstat (limited to 'app/assets/javascripts/admin')
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_report_actions.vue148
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_report_details.vue66
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue54
-rw-r--r--app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue4
-rw-r--r--app/assets/javascripts/admin/abuse_reports/constants.js42
-rw-r--r--app/assets/javascripts/admin/abuse_reports/utils.js5
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/message_form.vue38
-rw-r--r--app/assets/javascripts/admin/broadcast_messages/components/message_form_group.vue34
-rw-r--r--app/assets/javascripts/admin/users/components/actions/activate.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/approve.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/ban.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/block.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/deactivate.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/delete.vue16
-rw-r--r--app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue24
-rw-r--r--app/assets/javascripts/admin/users/components/actions/reject.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/unban.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/unblock.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/actions/unlock.vue12
-rw-r--r--app/assets/javascripts/admin/users/components/user_actions.vue77
-rw-r--r--app/assets/javascripts/admin/users/components/users_table.vue2
21 files changed, 441 insertions, 177 deletions
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_actions.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_actions.vue
new file mode 100644
index 00000000000..f2271f8af24
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_actions.vue
@@ -0,0 +1,148 @@
+<script>
+import { GlButton, GlDropdown, GlModal } from '@gitlab/ui';
+import axios from '~/lib/utils/axios_utils';
+import { __, sprintf } from '~/locale';
+import { createAlert, VARIANT_SUCCESS } from '~/alert';
+import { ACTIONS_I18N } from '../constants';
+
+const modalActionButtonAttributes = {
+ block: {
+ text: __('OK'),
+ attributes: {
+ variant: 'confirm',
+ },
+ },
+ removeUserAndReport: {
+ text: __('OK'),
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ secondary: {
+ text: __('Cancel'),
+ attributes: {
+ variant: 'default',
+ },
+ },
+};
+
+export default {
+ name: 'AbuseReportActions',
+ components: {
+ GlButton,
+ GlDropdown,
+ GlModal,
+ },
+ modalId: 'abuse-report-row-action-confirm-modal',
+ modalActionButtonAttributes,
+ i18n: ACTIONS_I18N,
+ props: {
+ report: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ userBlocked: this.report.userBlocked,
+ confirmModalShown: false,
+ actionToConfirm: 'block',
+ };
+ },
+ computed: {
+ blockUserButtonText() {
+ const { alreadyBlocked, blockUser } = this.$options.i18n;
+
+ return this.userBlocked ? alreadyBlocked : blockUser;
+ },
+ removeUserAndReportConfirmText() {
+ return sprintf(this.$options.i18n.removeUserAndReportConfirm, {
+ user: this.report.reportedUser.name,
+ });
+ },
+ modalData() {
+ return {
+ block: {
+ action: this.blockUser,
+ confirmText: this.$options.i18n.blockUserConfirm,
+ },
+ removeUserAndReport: {
+ action: this.removeUserAndReport,
+ confirmText: this.removeUserAndReportConfirmText,
+ },
+ };
+ },
+ },
+ methods: {
+ showConfirmModal(action) {
+ this.confirmModalShown = true;
+ this.actionToConfirm = action;
+ },
+ blockUser() {
+ axios
+ .put(this.report.blockUserPath)
+ .then(this.handleBlockUserResponse)
+ .catch(this.handleError);
+ },
+ removeUserAndReport() {
+ axios
+ .delete(this.report.removeUserAndReportPath)
+ .then(this.handleRemoveReportResponse)
+ .catch(this.handleError);
+ },
+ removeReport() {
+ axios
+ .delete(this.report.removeReportPath)
+ .then(this.handleRemoveReportResponse)
+ .catch(this.handleError);
+ },
+ handleRemoveReportResponse() {
+ window.location.reload();
+ },
+ handleBlockUserResponse({ data }) {
+ const message = data?.error || data?.notice;
+ const alertOptions = data?.notice ? { variant: VARIANT_SUCCESS } : {};
+
+ if (message) {
+ createAlert({ message, ...alertOptions });
+ }
+
+ if (!data?.error) {
+ this.userBlocked = true;
+ }
+ },
+ handleError(error) {
+ createAlert({
+ message: __('Something went wrong. Please try again.'),
+ captureError: true,
+ error,
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <gl-dropdown text="Actions" text-sr-only icon="ellipsis_v" category="tertiary" no-caret right>
+ <div class="gl-px-2">
+ <gl-button block variant="danger" @click="showConfirmModal('removeUserAndReport')">
+ {{ $options.i18n.removeUserAndReport }}
+ </gl-button>
+ <gl-button block :disabled="userBlocked" @click="showConfirmModal('block')">
+ {{ blockUserButtonText }}
+ </gl-button>
+ <gl-button block @click="removeReport">
+ {{ $options.i18n.removeReport }}
+ </gl-button>
+ </div>
+ <gl-modal
+ v-model="confirmModalShown"
+ :modal-id="$options.modalId"
+ :title="modalData[actionToConfirm].confirmText"
+ size="sm"
+ :action-primary="$options.modalActionButtonAttributes[actionToConfirm]"
+ :action-secondary="$options.modalActionButtonAttributes.secondary"
+ @primary="modalData[actionToConfirm].action"
+ />
+ </gl-dropdown>
+</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_details.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_details.vue
new file mode 100644
index 00000000000..f49411604f1
--- /dev/null
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_details.vue
@@ -0,0 +1,66 @@
+<script>
+import { uniqueId } from 'lodash';
+import { GlButton, GlCollapse } from '@gitlab/ui';
+import { getTimeago } from '~/lib/utils/datetime_utility';
+import { __, sprintf } from '~/locale';
+import SafeHtml from '~/vue_shared/directives/safe_html';
+
+export default {
+ components: {
+ GlButton,
+ GlCollapse,
+ },
+ directives: { SafeHtml },
+ props: {
+ report: {
+ type: Object,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ isVisible: false,
+ collapseId: uniqueId('abuse-report-detail-'),
+ };
+ },
+ computed: {
+ toggleText() {
+ return this.isVisible ? __('Hide details') : __('Show details');
+ },
+ reportedUserCreatedAt() {
+ const { reportedUser } = this.report;
+ return sprintf(__('User joined %{timeAgo}'), {
+ timeAgo: getTimeago().format(reportedUser.createdAt),
+ });
+ },
+ },
+ methods: {
+ toggleCollapse() {
+ this.isVisible = !this.isVisible;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="gl-display-flex gl-flex-direction-column">
+ <gl-collapse :id="collapseId" v-model="isVisible">
+ <dl class="gl-mb-2">
+ <dd>{{ reportedUserCreatedAt }}</dd>
+
+ <dt>{{ __('Message') }}</dt>
+ <dd v-safe-html="report.message"></dd>
+ </dl>
+ </gl-collapse>
+ <div>
+ <gl-button
+ :aria-expanded="`${isVisible}`"
+ :aria-controls="collapseId"
+ size="small"
+ variant="link"
+ @click="toggleCollapse"
+ >{{ toggleText }}
+ </gl-button>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
index a4211002f71..a9fe59a7b85 100644
--- a/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_report_row.vue
@@ -1,11 +1,20 @@
<script>
+import { GlSprintf, GlLink } from '@gitlab/ui';
import { getTimeago } from '~/lib/utils/datetime_utility';
+import { queryToObject } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import ListItem from '~/vue_shared/components/registry/list_item.vue';
+import { SORT_UPDATED_AT } from '../constants';
+import AbuseReportActions from './abuse_report_actions.vue';
+import AbuseReportDetails from './abuse_report_details.vue';
export default {
name: 'AbuseReportRow',
components: {
+ AbuseReportDetails,
+ GlLink,
+ GlSprintf,
+ AbuseReportActions,
ListItem,
},
props: {
@@ -15,14 +24,31 @@ export default {
},
},
computed: {
- updatedAt() {
- const template = __('Updated %{timeAgo}');
- return sprintf(template, { timeAgo: getTimeago().format(this.report.updatedAt) });
+ displayDate() {
+ const { sort } = queryToObject(window.location.search);
+ const { createdAt, updatedAt } = this.report;
+ const { template, timeAgo } = Object.values(SORT_UPDATED_AT.sortDirection).includes(sort)
+ ? { template: __('Updated %{timeAgo}'), timeAgo: updatedAt }
+ : { template: __('Created %{timeAgo}'), timeAgo: createdAt };
+
+ return sprintf(template, { timeAgo: getTimeago().format(timeAgo) });
+ },
+ reported() {
+ const { reportedUser } = this.report;
+ return sprintf('%{userLinkStart}%{reported}%{userLinkEnd}', {
+ reported: reportedUser.name,
+ });
+ },
+ reporter() {
+ const { reporter } = this.report;
+ return sprintf('%{reporterLinkStart}%{reporter}%{reporterLinkEnd}', {
+ reporter: reporter.name,
+ });
},
title() {
- const { reportedUser, reporter, category } = this.report;
+ const { category } = this.report;
const template = __('%{reported} reported for %{category} by %{reporter}');
- return sprintf(template, { reported: reportedUser.name, reporter: reporter.name, category });
+ return sprintf(template, { reported: this.reported, reporter: this.reporter, category });
},
},
};
@@ -31,11 +57,25 @@ export default {
<template>
<list-item data-testid="abuse-report-row">
<template #left-primary>
- <div class="gl-font-weight-normal" data-testid="title">{{ title }}</div>
+ <div class="gl-font-weight-normal gl-mb-2" data-testid="title">
+ <gl-sprintf :message="title">
+ <template #userLink="{ content }">
+ <gl-link :href="report.reportedUserPath">{{ content }}</gl-link>
+ </template>
+ <template #reporterLink="{ content }">
+ <gl-link :href="report.reporterPath">{{ content }}</gl-link>
+ </template>
+ </gl-sprintf>
+ </div>
+ </template>
+
+ <template #left-secondary>
+ <abuse-report-details :report="report" />
</template>
<template #right-secondary>
- <div data-testid="updated-at">{{ updatedAt }}</div>
+ <div data-testid="abuse-report-date">{{ displayDate }}</div>
+ <abuse-report-actions :report="report" />
</template>
</list-item>
</template>
diff --git a/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue
index b60fe3ae9b8..e1989cadd86 100644
--- a/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue
+++ b/app/assets/javascripts/admin/abuse_reports/components/abuse_reports_filtered_search_bar.vue
@@ -8,7 +8,7 @@ import {
SORT_OPTIONS,
isValidSortKey,
} from '~/admin/abuse_reports/constants';
-import { buildFilteredSearchCategoryToken } from '~/admin/abuse_reports/utils';
+import { buildFilteredSearchCategoryToken, isValidStatus } from '~/admin/abuse_reports/utils';
export default {
name: 'AbuseReportsFilteredSearchBar',
@@ -32,7 +32,7 @@ export default {
// Backend shows open reports by default if status param is not specified.
// To match that behavior, update the current URL to include status=open
// query when no status query is specified on load.
- if (!query.status) {
+ if (!isValidStatus(query.status)) {
query.status = 'open';
updateHistory({ url: setUrlParams(query), replace: true });
}
diff --git a/app/assets/javascripts/admin/abuse_reports/constants.js b/app/assets/javascripts/admin/abuse_reports/constants.js
index ee2e9ab2cbf..ee002f269ac 100644
--- a/app/assets/javascripts/admin/abuse_reports/constants.js
+++ b/app/assets/javascripts/admin/abuse_reports/constants.js
@@ -40,25 +40,24 @@ export const FILTERED_SEARCH_TOKEN_STATUS = {
};
export const DEFAULT_SORT = 'created_at_desc';
-
-export const SORT_OPTIONS = [
- {
- id: 10,
- title: __('Created date'),
- sortDirection: {
- descending: DEFAULT_SORT,
- ascending: 'created_at_asc',
- },
+export const SORT_UPDATED_AT = Object.freeze({
+ id: 20,
+ title: __('Updated date'),
+ sortDirection: {
+ descending: 'updated_at_desc',
+ ascending: 'updated_at_asc',
},
- {
- id: 20,
- title: __('Updated date'),
- sortDirection: {
- descending: 'updated_at_desc',
- ascending: 'updated_at_asc',
- },
+});
+const SORT_CREATED_AT = Object.freeze({
+ id: 10,
+ title: __('Created date'),
+ sortDirection: {
+ descending: DEFAULT_SORT,
+ ascending: 'created_at_asc',
},
-];
+});
+
+export const SORT_OPTIONS = [SORT_CREATED_AT, SORT_UPDATED_AT];
export const isValidSortKey = (key) =>
SORT_OPTIONS.some(
@@ -79,3 +78,12 @@ export const FILTERED_SEARCH_TOKENS = [
FILTERED_SEARCH_TOKEN_REPORTER,
FILTERED_SEARCH_TOKEN_STATUS,
];
+
+export const ACTIONS_I18N = {
+ blockUserConfirm: __('USER WILL BE BLOCKED! Are you sure?'),
+ blockUser: __('Block user'),
+ alreadyBlocked: __('Already blocked'),
+ removeUserAndReportConfirm: __('USER %{user} WILL BE REMOVED! Are you sure?'),
+ removeUserAndReport: __('Remove user & report'),
+ removeReport: __('Remove report'),
+};
diff --git a/app/assets/javascripts/admin/abuse_reports/utils.js b/app/assets/javascripts/admin/abuse_reports/utils.js
index 84221901089..d30e8fb0ae5 100644
--- a/app/assets/javascripts/admin/abuse_reports/utils.js
+++ b/app/assets/javascripts/admin/abuse_reports/utils.js
@@ -1,6 +1,9 @@
-import { FILTERED_SEARCH_TOKEN_CATEGORY } from './constants';
+import { FILTERED_SEARCH_TOKEN_CATEGORY, FILTERED_SEARCH_TOKEN_STATUS } from './constants';
export const buildFilteredSearchCategoryToken = (categories) => {
const options = categories.map((c) => ({ value: c, title: c }));
return { ...FILTERED_SEARCH_TOKEN_CATEGORY, options };
};
+
+export const isValidStatus = (status) =>
+ FILTERED_SEARCH_TOKEN_STATUS.options.map((o) => o.value).includes(status);
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
index 4482198675d..3168d693234 100644
--- a/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
+++ b/app/assets/javascripts/admin/broadcast_messages/components/message_form.vue
@@ -3,6 +3,7 @@ import {
GlButton,
GlBroadcastMessage,
GlForm,
+ GlFormGroup,
GlFormCheckbox,
GlFormCheckboxGroup,
GlFormInput,
@@ -18,7 +19,6 @@ import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { THEMES, TYPES, TYPE_BANNER } from '../constants';
-import MessageFormGroup from './message_form_group.vue';
import DatetimePicker from './datetime_picker.vue';
const FORM_HEADERS = { headers: { 'Content-Type': 'application/json; charset=utf-8' } };
@@ -31,13 +31,13 @@ export default {
GlButton,
GlBroadcastMessage,
GlForm,
+ GlFormGroup,
GlFormCheckbox,
GlFormCheckboxGroup,
GlFormInput,
GlFormSelect,
GlFormText,
GlFormTextarea,
- MessageFormGroup,
},
directives: {
SafeHtml,
@@ -189,7 +189,7 @@ export default {
<div v-safe-html:[$options.safeHtmlConfig]="messagePreview"></div>
</gl-broadcast-message>
- <message-form-group :label="$options.i18n.message" label-for="message-textarea">
+ <gl-form-group :label="$options.i18n.message" label-for="message-textarea">
<gl-form-textarea
id="message-textarea"
v-model="message"
@@ -198,23 +198,23 @@ export default {
:placeholder="$options.i18n.messagePlaceholder"
data-testid="message-input"
/>
- </message-form-group>
+ </gl-form-group>
- <message-form-group :label="$options.i18n.type" label-for="type-select">
+ <gl-form-group :label="$options.i18n.type" label-for="type-select">
<gl-form-select id="type-select" v-model="type" :options="$options.messageTypes" />
- </message-form-group>
+ </gl-form-group>
<template v-if="isBanner">
- <message-form-group :label="$options.i18n.theme" label-for="theme-select">
+ <gl-form-group :label="$options.i18n.theme" label-for="theme-select">
<gl-form-select
id="theme-select"
v-model="theme"
:options="$options.messageThemes"
data-testid="theme-select"
/>
- </message-form-group>
+ </gl-form-group>
- <message-form-group :label="$options.i18n.dismissable" label-for="dismissable-checkbox">
+ <gl-form-group :label="$options.i18n.dismissable" label-for="dismissable-checkbox">
<gl-form-checkbox
id="dismissable-checkbox"
v-model="dismissable"
@@ -223,10 +223,10 @@ export default {
>
<span>{{ $options.i18n.dismissableDescription }}</span>
</gl-form-checkbox>
- </message-form-group>
+ </gl-form-group>
</template>
- <message-form-group
+ <gl-form-group
v-if="glFeatures.roleTargetedBroadcastMessages"
:label="$options.i18n.targetRoles"
data-testid="target-roles-checkboxes"
@@ -235,24 +235,24 @@ export default {
<gl-form-text>
{{ $options.i18n.targetRolesDescription }}
</gl-form-text>
- </message-form-group>
+ </gl-form-group>
- <message-form-group :label="$options.i18n.targetPath" label-for="target-path-input">
+ <gl-form-group :label="$options.i18n.targetPath" label-for="target-path-input">
<gl-form-input id="target-path-input" v-model="targetPath" />
<gl-form-text>
{{ $options.i18n.targetPathDescription }}
</gl-form-text>
- </message-form-group>
+ </gl-form-group>
- <message-form-group :label="$options.i18n.startsAt">
+ <gl-form-group :label="$options.i18n.startsAt">
<datetime-picker v-model="startsAt" />
- </message-form-group>
+ </gl-form-group>
- <message-form-group :label="$options.i18n.endsAt">
+ <gl-form-group :label="$options.i18n.endsAt">
<datetime-picker v-model="endsAt" />
- </message-form-group>
+ </gl-form-group>
- <div class="form-actions gl-my-3">
+ <div class="gl-my-5">
<gl-button
type="submit"
variant="confirm"
diff --git a/app/assets/javascripts/admin/broadcast_messages/components/message_form_group.vue b/app/assets/javascripts/admin/broadcast_messages/components/message_form_group.vue
deleted file mode 100644
index eec51c0c28b..00000000000
--- a/app/assets/javascripts/admin/broadcast_messages/components/message_form_group.vue
+++ /dev/null
@@ -1,34 +0,0 @@
-<script>
-import { GlFormGroup } from '@gitlab/ui';
-
-export default {
- name: 'MessageFormGroup',
- components: {
- GlFormGroup,
- },
- props: {
- label: {
- type: String,
- required: true,
- },
- labelFor: {
- type: String,
- required: false,
- default: '',
- },
- },
-};
-</script>
-<template>
- <div>
- <gl-form-group
- :label="label"
- :label-for="labelFor"
- label-cols-sm="2"
- label-class="gl-mt-3"
- label-align-sm="right"
- >
- <slot></slot>
- </gl-form-group>
- </div>
-</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/activate.vue b/app/assets/javascripts/admin/users/components/actions/activate.vue
index 0099c8da8e6..af09c7618e2 100644
--- a/app/assets/javascripts/admin/users/components/actions/activate.vue
+++ b/app/assets/javascripts/admin/users/components/actions/activate.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
import { I18N_USER_ACTIONS } from '../../constants';
@@ -15,7 +15,7 @@ const messageHtml = `
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -52,7 +52,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/approve.vue b/app/assets/javascripts/admin/users/components/actions/approve.vue
index 52560ebe5b1..2060528c7a0 100644
--- a/app/assets/javascripts/admin/users/components/actions/approve.vue
+++ b/app/assets/javascripts/admin/users/components/actions/approve.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
import { I18N_USER_ACTIONS } from '../../constants';
@@ -17,7 +17,7 @@ const messageHtml = `
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -54,7 +54,9 @@ export default {
</script>
<template>
- <gl-dropdown-item data-qa-selector="approve_user_button" @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item data-qa-selector="approve_user_button" @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/ban.vue b/app/assets/javascripts/admin/users/components/actions/ban.vue
index 203d076914f..d7bdceb4798 100644
--- a/app/assets/javascripts/admin/users/components/actions/ban.vue
+++ b/app/assets/javascripts/admin/users/components/actions/ban.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
@@ -30,7 +30,7 @@ const messageHtml = `
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -67,7 +67,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/block.vue b/app/assets/javascripts/admin/users/components/actions/block.vue
index d50b76aaa92..534e1c76b8f 100644
--- a/app/assets/javascripts/admin/users/components/actions/block.vue
+++ b/app/assets/javascripts/admin/users/components/actions/block.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
import { I18N_USER_ACTIONS } from '../../constants';
@@ -18,7 +18,7 @@ const messageHtml = `
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -53,7 +53,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/deactivate.vue b/app/assets/javascripts/admin/users/components/actions/deactivate.vue
index ab1069601d2..40911131d6d 100644
--- a/app/assets/javascripts/admin/users/components/actions/deactivate.vue
+++ b/app/assets/javascripts/admin/users/components/actions/deactivate.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
import { I18N_USER_ACTIONS } from '../../constants';
@@ -25,7 +25,7 @@ const messageHtml = `
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -62,7 +62,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/delete.vue b/app/assets/javascripts/admin/users/components/actions/delete.vue
index d4f9ff4e529..83aa78c9f03 100644
--- a/app/assets/javascripts/admin/users/components/actions/delete.vue
+++ b/app/assets/javascripts/admin/users/components/actions/delete.vue
@@ -1,11 +1,11 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { s__ } from '~/locale';
import eventHub, { EVENT_OPEN_DELETE_USER_MODAL } from '../modals/delete_user_modal_event_hub';
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -49,9 +49,11 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <span class="gl-text-red-500">
- <slot></slot>
- </span>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <span class="gl-text-red-500">
+ <slot></slot>
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue b/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
index 413804c9a3b..24f0cac73f5 100644
--- a/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
+++ b/app/assets/javascripts/admin/users/components/actions/delete_with_contributions.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import { GlDisclosureDropdownItem, GlLoadingIcon } from '@gitlab/ui';
import { s__, __ } from '~/locale';
import { associationsCount } from '~/api/user_api';
import eventHub, { EVENT_OPEN_DELETE_USER_MODAL } from '../modals/delete_user_modal_event_hub';
@@ -9,7 +9,7 @@ export default {
loading: __('Loading'),
},
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
GlLoadingIcon,
},
props: {
@@ -71,13 +71,15 @@ export default {
</script>
<template>
- <gl-dropdown-item :disabled="loading" :aria-busy="loading" @click.capture.native.stop="onClick">
- <div v-if="loading" class="gl-display-flex gl-align-items-center">
- <gl-loading-icon class="gl-mr-3" />
- {{ $options.i18n.loading }}
- </div>
- <span v-else class="gl-text-red-500">
- <slot></slot>
- </span>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item :disabled="loading" :aria-busy="loading" @action="onClick">
+ <template #list-item>
+ <div v-if="loading" class="gl-display-flex gl-align-items-center">
+ <gl-loading-icon class="gl-mr-3" />
+ {{ $options.i18n.loading }}
+ </div>
+ <span v-else class="gl-text-red-500">
+ <slot></slot>
+ </span>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/reject.vue b/app/assets/javascripts/admin/users/components/actions/reject.vue
index 2b9c4acfcb5..7f786991709 100644
--- a/app/assets/javascripts/admin/users/components/actions/reject.vue
+++ b/app/assets/javascripts/admin/users/components/actions/reject.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
@@ -28,7 +28,7 @@ const messageHtml = `
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -65,7 +65,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/unban.vue b/app/assets/javascripts/admin/users/components/actions/unban.vue
index 42b6fb3bdd4..f84c7594f87 100644
--- a/app/assets/javascripts/admin/users/components/actions/unban.vue
+++ b/app/assets/javascripts/admin/users/components/actions/unban.vue
@@ -1,5 +1,5 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
import { I18N_USER_ACTIONS } from '../../constants';
@@ -11,7 +11,7 @@ const messageHtml = `<p>${s__(
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -48,7 +48,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/unblock.vue b/app/assets/javascripts/admin/users/components/actions/unblock.vue
index f94e128a945..064f05ef8b1 100644
--- a/app/assets/javascripts/admin/users/components/actions/unblock.vue
+++ b/app/assets/javascripts/admin/users/components/actions/unblock.vue
@@ -1,12 +1,12 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
import { I18N_USER_ACTIONS } from '../../constants';
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -42,7 +42,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/actions/unlock.vue b/app/assets/javascripts/admin/users/components/actions/unlock.vue
index c78c260b4fe..039ab3d651e 100644
--- a/app/assets/javascripts/admin/users/components/actions/unlock.vue
+++ b/app/assets/javascripts/admin/users/components/actions/unlock.vue
@@ -1,12 +1,12 @@
<script>
-import { GlDropdownItem } from '@gitlab/ui';
+import { GlDisclosureDropdownItem } from '@gitlab/ui';
import { sprintf, s__, __ } from '~/locale';
import eventHub, { EVENT_OPEN_CONFIRM_MODAL } from '~/vue_shared/components/confirm_modal_eventhub';
import { I18N_USER_ACTIONS } from '../../constants';
export default {
components: {
- GlDropdownItem,
+ GlDisclosureDropdownItem,
},
props: {
username: {
@@ -41,7 +41,9 @@ export default {
</script>
<template>
- <gl-dropdown-item @click="onClick">
- <slot></slot>
- </gl-dropdown-item>
+ <gl-disclosure-dropdown-item @action="onClick">
+ <template #list-item>
+ <slot></slot>
+ </template>
+ </gl-disclosure-dropdown-item>
</template>
diff --git a/app/assets/javascripts/admin/users/components/user_actions.vue b/app/assets/javascripts/admin/users/components/user_actions.vue
index c1fb80959cf..38c7d3f9b90 100644
--- a/app/assets/javascripts/admin/users/components/user_actions.vue
+++ b/app/assets/javascripts/admin/users/components/user_actions.vue
@@ -1,10 +1,9 @@
<script>
import {
GlButton,
- GlDropdown,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlDropdownDivider,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdownGroup,
GlTooltipDirective,
} from '@gitlab/ui';
import { convertArrayToCamelCase } from '~/lib/utils/common_utils';
@@ -17,10 +16,9 @@ import Actions from './actions';
export default {
components: {
GlButton,
- GlDropdown,
- GlDropdownItem,
- GlDropdownSectionHeader,
- GlDropdownDivider,
+ GlDisclosureDropdown,
+ GlDisclosureDropdownItem,
+ GlDisclosureDropdownGroup,
...Actions,
},
directives: {
@@ -63,6 +61,9 @@ export default {
hasEditAction() {
return this.userActions.includes('edit');
},
+ hasEditActionOnly() {
+ return this.hasEditAction === true && this.hasDeleteActions === false;
+ },
userPaths() {
return generateUserPaths(this.paths, this.user.username);
},
@@ -93,10 +94,13 @@ export default {
class="gl-display-flex gl-justify-content-end gl-my-n2 gl-mx-n2"
:data-testid="`user-actions-${user.id}`"
>
- <div v-if="hasEditAction" class="gl-p-2">
- <gl-button v-if="showButtonLabels" v-bind="editButtonAttrs" icon="pencil-square">{{
- $options.i18n.edit
- }}</gl-button>
+ <div v-if="hasEditAction" class="gl-p-2" :class="{ 'gl-mr-3': hasEditActionOnly }">
+ <gl-button
+ v-if="showButtonLabels"
+ v-bind="editButtonAttrs"
+ :class="{ 'gl-mr-7': hasEditActionOnly }"
+ >{{ $options.i18n.edit }}</gl-button
+ >
<gl-button
v-else
v-gl-tooltip="$options.i18n.edit"
@@ -107,12 +111,15 @@ export default {
</div>
<div v-if="hasDropdownActions" class="gl-p-2">
- <gl-dropdown
- :text="$options.i18n.userAdministration"
+ <gl-disclosure-dropdown
+ icon="ellipsis_v"
+ category="tertiary"
+ :toggle-text="$options.i18n.userAdministration"
+ text-sr-only
data-testid="dropdown-toggle"
data-qa-selector="user_actions_dropdown_toggle"
:data-qa-username="user.username"
- left
+ no-caret
>
<template v-for="action in dropdownSafeActions">
<component
@@ -125,28 +132,32 @@ export default {
>
{{ $options.i18n[action] }}
</component>
- <gl-dropdown-item v-else-if="isLdapAction(action)" :key="action" :data-testid="action">
- {{ $options.i18n[action] }}
- </gl-dropdown-item>
- </template>
-
- <gl-dropdown-divider v-if="hasDeleteActions" />
-
- <template v-for="action in dropdownDeleteActions">
- <component
- :is="getActionComponent(action)"
- v-if="getActionComponent(action)"
+ <gl-disclosure-dropdown-item
+ v-else-if="isLdapAction(action)"
:key="action"
- :paths="userPaths"
- :username="user.name"
- :user-id="user.id"
- :user-deletion-obstacles="obstaclesForUserDeletion"
- :data-testid="`delete-${action}`"
+ :data-testid="action"
>
{{ $options.i18n[action] }}
- </component>
+ </gl-disclosure-dropdown-item>
</template>
- </gl-dropdown>
+
+ <gl-disclosure-dropdown-group v-if="hasDeleteActions" bordered>
+ <template v-for="action in dropdownDeleteActions">
+ <component
+ :is="getActionComponent(action)"
+ v-if="getActionComponent(action)"
+ :key="action"
+ :paths="userPaths"
+ :username="user.name"
+ :user-id="user.id"
+ :user-deletion-obstacles="obstaclesForUserDeletion"
+ :data-testid="`delete-${action}`"
+ >
+ {{ $options.i18n[action] }}
+ </component>
+ </template>
+ </gl-disclosure-dropdown-group>
+ </gl-disclosure-dropdown>
</div>
</div>
</template>
diff --git a/app/assets/javascripts/admin/users/components/users_table.vue b/app/assets/javascripts/admin/users/components/users_table.vue
index e55622d40ba..2d2c598f953 100644
--- a/app/assets/javascripts/admin/users/components/users_table.vue
+++ b/app/assets/javascripts/admin/users/components/users_table.vue
@@ -135,7 +135,7 @@ export default {
</template>
<template #cell(settings)="{ item: user }">
- <user-actions :user="user" :paths="paths" />
+ <user-actions :user="user" :paths="paths" :show-button-labels="true" />
</template>
</gl-table>
</div>