diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-24 18:10:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-07-24 18:10:11 +0300 |
commit | 7308ec9d13fb69018200a40f287e76ef499ed47c (patch) | |
tree | 06c75f7ddceebd61d09f925a48fef2789338f3cd /app/assets/javascripts/admin | |
parent | f296f23500b4b3758670ae0c5ce2e1779f533e8b (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/admin')
5 files changed, 92 insertions, 40 deletions
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 b229dd9e993..291833959f2 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 @@ -14,6 +14,13 @@ export default { ListItem, AbuseCategory, }, + i18n: { + updatedAt: __('Updated %{timeAgo}'), + createdAt: __('Created %{timeAgo}'), + deletedUser: s__('AbuseReports|Deleted user'), + row: s__('AbuseReports|%{reportedUser} reported for %{category} by %{reporter}'), + rowWithCount: s__('AbuseReports|%{reportedUser} reported for %{category} by %{count} users'), + }, props: { report: { type: Object, @@ -25,18 +32,24 @@ export default { 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 }; + ? { template: this.$options.i18n.updatedAt, timeAgo: updatedAt } + : { template: this.$options.i18n.createdAt, timeAgo: createdAt }; return sprintf(template, { timeAgo: getTimeago().format(timeAgo) }); }, title() { - const { reportedUser, category, reporter } = this.report; - const template = s__('AbuseReports|%{reportedUser} reported for %{category} by %{reporter}'); - return sprintf(template, { - reportedUser: reportedUser?.name || s__('AbuseReports|Deleted user'), - reporter: reporter?.name || s__('AbuseReports|Deleted user'), + const { reportedUser, category, reporter, count } = this.report; + + const reportedUserName = reportedUser?.name || this.$options.i18n.deletedUser; + const reporterName = reporter?.name || this.$options.i18n.deletedUser; + + const i18nRowCount = count > 1 ? this.$options.i18n.rowWithCount : this.$options.i18n.row; + + return sprintf(i18nRowCount, { + reportedUser: reportedUserName, + reporter: reporterName, category, + count, }); }, }, 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 b1eb5371a35..bab0fe6dd7d 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 @@ -4,43 +4,52 @@ import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_ba import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import { FILTERED_SEARCH_TOKENS, - DEFAULT_SORT, - SORT_OPTIONS, - isValidSortKey, + DEFAULT_SORT_STATUS_OPEN, + DEFAULT_SORT_STATUS_CLOSED, } from '~/admin/abuse_reports/constants'; -import { buildFilteredSearchCategoryToken, isValidStatus } from '~/admin/abuse_reports/utils'; + +import { + buildFilteredSearchCategoryToken, + isValidStatus, + isOpenStatus, + isValidSortKey, + sortOptions, +} from '~/admin/abuse_reports/utils'; export default { name: 'AbuseReportsFilteredSearchBar', components: { FilteredSearchBar }, - sortOptions: SORT_OPTIONS, inject: ['categories'], data() { return { initialFilterValue: [], - initialSortBy: DEFAULT_SORT, + initialSortBy: DEFAULT_SORT_STATUS_OPEN, }; }, computed: { tokens() { return [...FILTERED_SEARCH_TOKENS, buildFilteredSearchCategoryToken(this.categories)]; }, + query() { + return queryToObject(window.location.search); + }, + currentSortOptions() { + return sortOptions(this.query.status); + }, }, created() { - const query = queryToObject(window.location.search); + const { query } = this; // 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. + // query when no status is specified on load. if (!isValidStatus(query.status)) { query.status = 'open'; updateHistory({ url: setUrlParams(query), replace: true }); } - const sort = this.currentSortKey(); - if (sort) { - this.initialSortBy = query.sort; - } + const sortKey = this.currentSortKey(); + this.initialSortBy = sortKey; const tokens = this.tokens .filter((token) => query[token.type]) @@ -56,9 +65,13 @@ export default { }, methods: { currentSortKey() { - const { sort } = queryToObject(window.location.search); + const { status, sort } = this.query; - return isValidSortKey(sort) ? sort : undefined; + if (!isValidSortKey(status, sort) || !sort) { + return isOpenStatus(status) ? DEFAULT_SORT_STATUS_OPEN : DEFAULT_SORT_STATUS_CLOSED; + } + + return sort; }, handleFilter(tokens) { let params = tokens.reduce((accumulator, token) => { @@ -76,6 +89,7 @@ export default { }, {}); const sort = this.currentSortKey(); + if (sort) { params = { ...params, sort }; } @@ -83,7 +97,7 @@ export default { redirectTo(setUrlParams(params, window.location.href, true)); // eslint-disable-line import/no-deprecated }, handleSort(sort) { - const { page, ...query } = queryToObject(window.location.search); + const { page, ...query } = this.query; redirectTo(setUrlParams({ ...query, sort }, window.location.href, true)); // eslint-disable-line import/no-deprecated }, @@ -101,7 +115,7 @@ export default { :search-input-placeholder="__('Filter reports')" :initial-filter-value="initialFilterValue" :initial-sort-by="initialSortBy" - :sort-options="$options.sortOptions" + :sort-options="currentSortOptions" data-testid="abuse-reports-filtered-search-bar" @onFilter="handleFilter" @onSort="handleSort" diff --git a/app/assets/javascripts/admin/abuse_reports/constants.js b/app/assets/javascripts/admin/abuse_reports/constants.js index acb79293dfb..8b14745543e 100644 --- a/app/assets/javascripts/admin/abuse_reports/constants.js +++ b/app/assets/javascripts/admin/abuse_reports/constants.js @@ -7,10 +7,9 @@ import { } from '~/vue_shared/components/filtered_search_bar/constants'; import { s__, __ } from '~/locale'; -const STATUS_OPTIONS = [ - { value: 'closed', title: __('Closed') }, - { value: 'open', title: __('Open') }, -]; +export const STATUS_OPEN = { value: 'open', title: __('Open') }; + +const STATUS_OPTIONS = [{ value: 'closed', title: __('Closed') }, STATUS_OPEN]; export const FILTERED_SEARCH_TOKEN_USER = { type: 'user', @@ -39,30 +38,39 @@ export const FILTERED_SEARCH_TOKEN_STATUS = { operators: OPERATORS_IS, }; -export const DEFAULT_SORT = 'created_at_desc'; -export const SORT_UPDATED_AT = Object.freeze({ +export const DEFAULT_SORT_STATUS_OPEN = 'number_of_reports_desc'; +export const DEFAULT_SORT_STATUS_CLOSED = 'created_at_desc'; + +export const SORT_UPDATED_AT = { id: 20, title: __('Updated date'), sortDirection: { descending: 'updated_at_desc', ascending: 'updated_at_asc', }, -}); -const SORT_CREATED_AT = Object.freeze({ +}; + +const SORT_CREATED_AT = { id: 10, title: __('Created date'), sortDirection: { - descending: DEFAULT_SORT, + descending: DEFAULT_SORT_STATUS_CLOSED, ascending: 'created_at_asc', }, -}); +}; + +const SORT_NUMBER_OF_REPORTS = { + id: 30, + title: __('Number of Reports'), + sortDirection: { + descending: DEFAULT_SORT_STATUS_OPEN, + }, +}; -export const SORT_OPTIONS = [SORT_CREATED_AT, SORT_UPDATED_AT]; +export const SORT_OPTIONS_STATUS_CLOSED = [SORT_CREATED_AT, SORT_UPDATED_AT]; -export const isValidSortKey = (key) => - SORT_OPTIONS.some( - (sort) => sort.sortDirection.ascending === key || sort.sortDirection.descending === key, - ); +// when filtered for status=open reports, add an additional sorting option -> number of reports +export const SORT_OPTIONS_STATUS_OPEN = [SORT_NUMBER_OF_REPORTS, ...SORT_OPTIONS_STATUS_CLOSED]; export const FILTERED_SEARCH_TOKEN_CATEGORY = { type: 'category', @@ -74,9 +82,9 @@ export const FILTERED_SEARCH_TOKEN_CATEGORY = { }; export const FILTERED_SEARCH_TOKENS = [ + FILTERED_SEARCH_TOKEN_STATUS, FILTERED_SEARCH_TOKEN_USER, FILTERED_SEARCH_TOKEN_REPORTER, - FILTERED_SEARCH_TOKEN_STATUS, ]; export const ABUSE_CATEGORIES = { diff --git a/app/assets/javascripts/admin/abuse_reports/index.js b/app/assets/javascripts/admin/abuse_reports/index.js index dbc466af2d2..e4174e6c851 100644 --- a/app/assets/javascripts/admin/abuse_reports/index.js +++ b/app/assets/javascripts/admin/abuse_reports/index.js @@ -19,6 +19,7 @@ export const initAbuseReportsApp = () => { return new Vue({ el, + name: 'AbuseReportsAppRoot', provide: { categories }, render: (createElement) => createElement(AbuseReportsApp, { diff --git a/app/assets/javascripts/admin/abuse_reports/utils.js b/app/assets/javascripts/admin/abuse_reports/utils.js index d30e8fb0ae5..a3d05e4dcb3 100644 --- a/app/assets/javascripts/admin/abuse_reports/utils.js +++ b/app/assets/javascripts/admin/abuse_reports/utils.js @@ -1,4 +1,10 @@ -import { FILTERED_SEARCH_TOKEN_CATEGORY, FILTERED_SEARCH_TOKEN_STATUS } from './constants'; +import { + FILTERED_SEARCH_TOKEN_CATEGORY, + FILTERED_SEARCH_TOKEN_STATUS, + STATUS_OPEN, + SORT_OPTIONS_STATUS_OPEN, + SORT_OPTIONS_STATUS_CLOSED, +} from './constants'; export const buildFilteredSearchCategoryToken = (categories) => { const options = categories.map((c) => ({ value: c, title: c })); @@ -7,3 +13,13 @@ export const buildFilteredSearchCategoryToken = (categories) => { export const isValidStatus = (status) => FILTERED_SEARCH_TOKEN_STATUS.options.map((o) => o.value).includes(status); + +export const isOpenStatus = (status) => status === STATUS_OPEN.value; + +export const sortOptions = (status) => + isOpenStatus(status) ? SORT_OPTIONS_STATUS_OPEN : SORT_OPTIONS_STATUS_CLOSED; + +export const isValidSortKey = (status, key) => + sortOptions(status).some( + (sort) => sort.sortDirection.ascending === key || sort.sortDirection.descending === key, + ); |