diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-09-16 00:11:56 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-09-16 00:11:56 +0300 |
commit | d30dfdfd05fedfa4b06f7905b5f193f3c6704284 (patch) | |
tree | 720a27bcaf375d8c02fbc267cde9620d443eeb30 /app | |
parent | 7a15fb07cf363079c4c4683850ee131d80e75f75 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
11 files changed, 4 insertions, 886 deletions
diff --git a/app/assets/javascripts/lib/utils/constants.js b/app/assets/javascripts/lib/utils/constants.js index aceae188b73..da5fb831ae5 100644 --- a/app/assets/javascripts/lib/utils/constants.js +++ b/app/assets/javascripts/lib/utils/constants.js @@ -3,15 +3,6 @@ export const DEFAULT_DEBOUNCE_AND_THROTTLE_MS = 250; export const THOUSAND = 1000; export const TRUNCATE_WIDTH_DEFAULT_WIDTH = 80; export const TRUNCATE_WIDTH_DEFAULT_FONT_SIZE = 12; - -export const DATETIME_RANGE_TYPES = { - fixed: 'fixed', - anchored: 'anchored', - rolling: 'rolling', - open: 'open', - invalid: 'invalid', -}; - export const BV_SHOW_MODAL = 'bv::show::modal'; export const BV_HIDE_MODAL = 'bv::hide::modal'; export const BV_HIDE_TOOLTIP = 'bv::hide::tooltip'; diff --git a/app/assets/javascripts/lib/utils/datetime_range.js b/app/assets/javascripts/lib/utils/datetime_range.js index 39fb26a95b7..f0a03874949 100644 --- a/app/assets/javascripts/lib/utils/datetime_range.js +++ b/app/assets/javascripts/lib/utils/datetime_range.js @@ -1,25 +1,4 @@ -import { pick, omit, isEqual, isEmpty } from 'lodash'; import dateformat from '~/lib/dateformat'; -import { DATETIME_RANGE_TYPES } from './constants'; -import { secondsToMilliseconds } from './datetime_utility'; - -const MINIMUM_DATE = new Date(0); - -const DEFAULT_DIRECTION = 'before'; - -const durationToMillis = (duration) => { - if (Object.entries(duration).length === 1 && Number.isFinite(duration.seconds)) { - return secondsToMilliseconds(duration.seconds); - } - // eslint-disable-next-line @gitlab/require-i18n-strings - throw new Error('Invalid duration: only `seconds` is supported'); -}; - -const dateMinusDuration = (date, duration) => new Date(date.getTime() - durationToMillis(duration)); - -const datePlusDuration = (date, duration) => new Date(date.getTime() + durationToMillis(duration)); - -const isValidDuration = (duration) => Boolean(duration && Number.isFinite(duration.seconds)); export const isValidDateString = (dateString) => { if (typeof dateString !== 'string' || !dateString.trim()) { @@ -38,291 +17,3 @@ export const isValidDateString = (dateString) => { } return !Number.isNaN(Date.parse(isoFormatted)); }; - -const handleRangeDirection = ({ direction = DEFAULT_DIRECTION, anchorDate, minDate, maxDate }) => { - let startDate; - let endDate; - - if (direction === DEFAULT_DIRECTION) { - startDate = minDate; - endDate = anchorDate; - } else { - startDate = anchorDate; - endDate = maxDate; - } - - return { - startDate, - endDate, - }; -}; - -/** - * Converts a fixed range to a fixed range - * @param {Object} fixedRange - A range with fixed start and - * end (e.g. "midnight January 1st 2020 to midday January31st 2020") - */ -const convertFixedToFixed = ({ start, end }) => ({ - start, - end, -}); - -/** - * Converts an anchored range to a fixed range - * @param {Object} anchoredRange - A duration of time - * relative to a fixed point in time (e.g., "the 30 minutes - * before midnight January 1st 2020", or "the 2 days - * after midday on the 11th of May 2019") - */ -const convertAnchoredToFixed = ({ anchor, duration, direction }) => { - const anchorDate = new Date(anchor); - - const { startDate, endDate } = handleRangeDirection({ - minDate: dateMinusDuration(anchorDate, duration), - maxDate: datePlusDuration(anchorDate, duration), - direction, - anchorDate, - }); - - return { - start: startDate.toISOString(), - end: endDate.toISOString(), - }; -}; - -/** - * Converts a rolling change to a fixed range - * - * @param {Object} rollingRange - A time range relative to - * now (e.g., "last 2 minutes", or "next 2 days") - */ -const convertRollingToFixed = ({ duration, direction }) => { - // Use Date.now internally for easier mocking in tests - const now = new Date(Date.now()); - - return convertAnchoredToFixed({ - duration, - direction, - anchor: now.toISOString(), - }); -}; - -/** - * Converts an open range to a fixed range - * - * @param {Object} openRange - A time range relative - * to an anchor (e.g., "before midnight on the 1st of - * January 2020", or "after midday on the 11th of May 2019") - */ -const convertOpenToFixed = ({ anchor, direction }) => { - // Use Date.now internally for easier mocking in tests - const now = new Date(Date.now()); - - const { startDate, endDate } = handleRangeDirection({ - minDate: MINIMUM_DATE, - maxDate: now, - direction, - anchorDate: new Date(anchor), - }); - - return { - start: startDate.toISOString(), - end: endDate.toISOString(), - }; -}; - -/** - * Handles invalid date ranges - */ -const handleInvalidRange = () => { - // eslint-disable-next-line @gitlab/require-i18n-strings - throw new Error('The input range does not have the right format.'); -}; - -const handlers = { - invalid: handleInvalidRange, - fixed: convertFixedToFixed, - anchored: convertAnchoredToFixed, - rolling: convertRollingToFixed, - open: convertOpenToFixed, -}; - -/** - * Validates and returns the type of range - * - * @param {Object} Date time range - * @returns {String} `key` value for one of the handlers - */ -export function getRangeType(range) { - const { start, end, anchor, duration } = range; - - if ((start || end) && !anchor && !duration) { - return isValidDateString(start) && isValidDateString(end) - ? DATETIME_RANGE_TYPES.fixed - : DATETIME_RANGE_TYPES.invalid; - } - if (anchor && duration) { - return isValidDateString(anchor) && isValidDuration(duration) - ? DATETIME_RANGE_TYPES.anchored - : DATETIME_RANGE_TYPES.invalid; - } - if (duration && !anchor) { - return isValidDuration(duration) ? DATETIME_RANGE_TYPES.rolling : DATETIME_RANGE_TYPES.invalid; - } - if (anchor && !duration) { - return isValidDateString(anchor) ? DATETIME_RANGE_TYPES.open : DATETIME_RANGE_TYPES.invalid; - } - return DATETIME_RANGE_TYPES.invalid; -} - -/** - * convertToFixedRange Transforms a `range of time` into a `fixed range of time`. - * - * The following types of a `ranges of time` can be represented: - * - * Fixed Range: A range with fixed start and end (e.g. "midnight January 1st 2020 to midday January 31st 2020") - * Anchored Range: A duration of time relative to a fixed point in time (e.g., "the 30 minutes before midnight January 1st 2020", or "the 2 days after midday on the 11th of May 2019") - * Rolling Range: A time range relative to now (e.g., "last 2 minutes", or "next 2 days") - * Open Range: A time range relative to an anchor (e.g., "before midnight on the 1st of January 2020", or "after midday on the 11th of May 2019") - * - * @param {Object} dateTimeRange - A Time Range representation - * It contains the data needed to create a fixed time range plus - * a label (recommended) to indicate the range that is covered. - * - * A definition via a TypeScript notation is presented below: - * - * - * type Duration = { // A duration of time, always in seconds - * seconds: number; - * } - * - * type Direction = 'before' | 'after'; // Direction of time relative to an anchor - * - * type FixedRange = { - * start: ISO8601; - * end: ISO8601; - * label: string; - * } - * - * type AnchoredRange = { - * anchor: ISO8601; - * duration: Duration; - * direction: Direction; // defaults to 'before' - * label: string; - * } - * - * type RollingRange = { - * duration: Duration; - * direction: Direction; // defaults to 'before' - * label: string; - * } - * - * type OpenRange = { - * anchor: ISO8601; - * direction: Direction; // defaults to 'before' - * label: string; - * } - * - * type DateTimeRange = FixedRange | AnchoredRange | RollingRange | OpenRange; - * - * - * @returns {FixedRange} An object with a start and end in ISO8601 format. - */ -export const convertToFixedRange = (dateTimeRange) => - handlers[getRangeType(dateTimeRange)](dateTimeRange); - -/** - * Returns a copy of the object only with time range - * properties relevant to time range calculation. - * - * Filtered properties are: - * - 'start' - * - 'end' - * - 'anchor' - * - 'duration' - * - 'direction': if direction is already the default, its removed. - * - * @param {Object} timeRange - A time range object - * @returns Copy of time range - */ -const pruneTimeRange = (timeRange) => { - const res = pick(timeRange, ['start', 'end', 'anchor', 'duration', 'direction']); - if (res.direction === DEFAULT_DIRECTION) { - return omit(res, 'direction'); - } - return res; -}; - -/** - * Returns true if the time ranges are equal according to - * the time range calculation properties - * - * @param {Object} timeRange - A time range object - * @param {Object} other - Time range object to compare with. - * @returns true if the time ranges are equal, false otherwise - */ -export const isEqualTimeRanges = (timeRange, other) => { - const tr1 = pruneTimeRange(timeRange); - const tr2 = pruneTimeRange(other); - return isEqual(tr1, tr2); -}; - -/** - * Searches for a time range in a array of time ranges using - * only the properies relevant to time ranges calculation. - * - * @param {Object} timeRange - Time range to search (needle) - * @param {Array} timeRanges - Array of time tanges (haystack) - */ -export const findTimeRange = (timeRange, timeRanges) => - timeRanges.find((element) => isEqualTimeRanges(element, timeRange)); - -// Time Ranges as URL Parameters Utils - -/** - * List of possible time ranges parameters - */ -export const timeRangeParamNames = ['start', 'end', 'anchor', 'duration_seconds', 'direction']; - -/** - * Converts a valid time range to a flat key-value pairs object. - * - * Duration is flatted to avoid having nested objects. - * - * @param {Object} A time range - * @returns key-value pairs object that can be used as parameters in a URL. - */ -export const timeRangeToParams = (timeRange) => { - let params = pruneTimeRange(timeRange); - if (timeRange.duration) { - const durationParms = {}; - Object.keys(timeRange.duration).forEach((key) => { - durationParms[`duration_${key}`] = timeRange.duration[key].toString(); - }); - params = { ...durationParms, ...params }; - params = omit(params, 'duration'); - } - return params; -}; - -/** - * Converts a valid set of flat params to a time range object - * - * Parameters that are not part of time range object are ignored. - * - * @param {params} params - key-value pairs object. - */ -export const timeRangeFromParams = (params) => { - const timeRangeParams = pick(params, timeRangeParamNames); - let range = Object.entries(timeRangeParams).reduce((acc, [key, val]) => { - // unflatten duration - if (key.startsWith('duration_')) { - acc.duration = acc.duration || {}; - acc.duration[key.slice('duration_'.length)] = parseInt(val, 10); - return acc; - } - return { [key]: val, ...acc }; - }, {}); - range = pruneTimeRange(range); - return !isEmpty(range) ? range : null; -}; diff --git a/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue index 65cec94253c..02488e99c0e 100644 --- a/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue +++ b/app/assets/javascripts/super_sidebar/components/sidebar_menu.vue @@ -104,10 +104,8 @@ export default { }, }, mounted() { - if (this.glFeatures.superSidebarFlyoutMenus) { - this.decideFlyoutState(); - window.addEventListener('resize', this.decideFlyoutState); - } + this.decideFlyoutState(); + window.addEventListener('resize', this.decideFlyoutState); }, beforeDestroy() { window.removeEventListener('resize', this.decideFlyoutState); diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue deleted file mode 100644 index d8a2789a419..00000000000 --- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue +++ /dev/null @@ -1,283 +0,0 @@ -<script> -import { GlIcon, GlButton, GlDropdown, GlDropdownItem, GlFormGroup } from '@gitlab/ui'; -import { convertToFixedRange, isEqualTimeRanges, findTimeRange } from '~/lib/utils/datetime_range'; -import { __, sprintf } from '~/locale'; - -import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue'; -import DateTimePickerInput from './date_time_picker_input.vue'; -import { - defaultTimeRanges, - defaultTimeRange, - isValidInputString, - inputStringToIsoDate, - isoDateToInputString, -} from './date_time_picker_lib'; - -const events = { - input: 'input', - invalid: 'invalid', -}; - -export default { - components: { - GlIcon, - GlButton, - GlDropdown, - GlDropdownItem, - GlFormGroup, - TooltipOnTruncate, - DateTimePickerInput, - }, - props: { - value: { - type: Object, - required: false, - default: () => defaultTimeRange, - }, - options: { - type: Array, - required: false, - default: () => defaultTimeRanges, - }, - customEnabled: { - type: Boolean, - required: false, - default: true, - }, - utc: { - type: Boolean, - required: false, - default: false, - }, - }, - data() { - return { - timeRange: this.value, - - /** - * Valid start iso date string, null if not valid value - */ - startDate: null, - /** - * Invalid start date string as input by the user - */ - startFallbackVal: '', - - /** - * Valid end iso date string, null if not valid value - */ - endDate: null, - /** - * Invalid end date string as input by the user - */ - endFallbackVal: '', - }; - }, - computed: { - startInputValid() { - return isValidInputString(this.startDate); - }, - endInputValid() { - return isValidInputString(this.endDate); - }, - isValid() { - return this.startInputValid && this.endInputValid; - }, - - startInput: { - get() { - return this.dateToInput(this.startDate) || this.startFallbackVal; - }, - set(val) { - try { - this.startDate = this.inputToDate(val); - this.startFallbackVal = null; - } catch (e) { - this.startDate = null; - this.startFallbackVal = val; - } - this.timeRange = null; - }, - }, - endInput: { - get() { - return this.dateToInput(this.endDate) || this.endFallbackVal; - }, - set(val) { - try { - this.endDate = this.inputToDate(val); - this.endFallbackVal = null; - } catch (e) { - this.endDate = null; - this.endFallbackVal = val; - } - this.timeRange = null; - }, - }, - - timeWindowText() { - try { - const timeRange = findTimeRange(this.value, this.options); - if (timeRange) { - return timeRange.label; - } - - const { start, end } = convertToFixedRange(this.value); - if (isValidInputString(start) && isValidInputString(end)) { - return sprintf(__('%{start} to %{end}'), { - start: this.stripZerosInDateTime(this.dateToInput(start)), - end: this.stripZerosInDateTime(this.dateToInput(end)), - }); - } - } catch { - return __('Invalid date range'); - } - return ''; - }, - - customLabel() { - if (this.utc) { - return __('Custom range (UTC)'); - } - return __('Custom range'); - }, - }, - watch: { - value(newValue) { - const { start, end } = convertToFixedRange(newValue); - this.timeRange = this.value; - this.startDate = start; - this.endDate = end; - }, - }, - mounted() { - try { - const { start, end } = convertToFixedRange(this.timeRange); - this.startDate = start; - this.endDate = end; - } catch { - // when dates cannot be parsed, emit error. - this.$emit(events.invalid); - } - - // Validate on mounted, and trigger an update if needed - if (!this.isValid) { - this.$emit(events.invalid); - } - }, - methods: { - dateToInput(date) { - if (date === null) { - return null; - } - return isoDateToInputString(date, this.utc); - }, - inputToDate(value) { - return inputStringToIsoDate(value, this.utc); - }, - stripZerosInDateTime(str = '') { - return str.replace(' 00:00:00', ''); - }, - closeDropdown() { - this.$refs.dropdown.hide(); - }, - isOptionActive(option) { - return isEqualTimeRanges(option, this.timeRange); - }, - setQuickRange(option) { - this.timeRange = option; - this.$emit(events.input, this.timeRange); - }, - setFixedRange() { - this.timeRange = convertToFixedRange({ - start: this.startDate, - end: this.endDate, - }); - this.$emit(events.input, this.timeRange); - }, - }, -}; -</script> -<template> - <tooltip-on-truncate - :title="timeWindowText" - :truncate-target="(elem) => elem.querySelector('.gl-dropdown-toggle-text')" - placement="top" - class="d-inline-block" - > - <gl-dropdown - ref="dropdown" - :text="timeWindowText" - v-bind="$attrs" - class="date-time-picker w-100" - menu-class="date-time-picker-menu" - toggle-class="date-time-picker-toggle text-truncate" - > - <template #button-content> - <span class="gl-flex-grow-1 text-truncate">{{ timeWindowText }}</span> - <span v-if="utc" class="gl-text-gray-500 gl-font-weight-bold gl-font-sm">{{ - __('UTC') - }}</span> - <gl-icon class="gl-dropdown-caret" name="chevron-down" /> - </template> - - <div class="d-flex justify-content-between gl-p-2"> - <gl-form-group - v-if="customEnabled" - :label="customLabel" - label-for="custom-from-time" - label-class="gl-pb-2" - class="custom-time-range-form-group col-md-7 gl-pl-2 gl-pr-0 m-0" - > - <div class="gl-pt-3"> - <date-time-picker-input - id="custom-time-from" - v-model="startInput" - :label="__('From')" - :state="startInputValid" - /> - <date-time-picker-input - id="custom-time-to" - v-model="endInput" - :label="__('To')" - :state="endInputValid" - /> - </div> - <gl-form-group> - <gl-button data-testid="cancelButton" @click="closeDropdown">{{ - __('Cancel') - }}</gl-button> - <gl-button - variant="confirm" - category="primary" - :disabled="!isValid" - @click="setFixedRange()" - > - {{ __('Apply') }} - </gl-button> - </gl-form-group> - </gl-form-group> - <gl-form-group label-for="group-id-dropdown" class="col-md-5 gl-px-2 m-0"> - <template #label> - <span class="gl-pl-7">{{ __('Quick range') }}</span> - </template> - - <gl-dropdown-item - v-for="(option, index) in options" - :key="index" - :active="isOptionActive(option)" - active-class="active" - @click="setQuickRange(option)" - > - <gl-icon - name="mobile-issue-close" - class="align-bottom" - :class="{ invisible: !isOptionActive(option) }" - /> - {{ option.label }} - </gl-dropdown-item> - </gl-form-group> - </div> - </gl-dropdown> - </tooltip-on-truncate> -</template> diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue deleted file mode 100644 index 190d4e1f104..00000000000 --- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue +++ /dev/null @@ -1,77 +0,0 @@ -<script> -import { GlFormGroup, GlFormInput } from '@gitlab/ui'; -import { uniqueId } from 'lodash'; -import { __, sprintf } from '~/locale'; -import { dateFormats } from './date_time_picker_lib'; - -const inputGroupText = { - invalidFeedback: sprintf(__('Format: %{dateFormat}'), { - dateFormat: dateFormats.inputFormat, - }), - placeholder: dateFormats.inputFormat, -}; - -export default { - components: { - GlFormGroup, - GlFormInput, - }, - props: { - state: { - default: null, - required: true, - validator: (prop) => typeof prop === 'boolean' || prop === null, - }, - value: { - default: null, - required: false, - validator: (prop) => typeof prop === 'string' || prop === null, - }, - label: { - type: String, - default: '', - required: true, - }, - id: { - type: String, - required: false, - default: () => uniqueId('dateTimePicker_'), - }, - }, - data() { - return { - inputGroupText, - }; - }, - computed: { - invalidFeedback() { - return this.state ? '' : this.inputGroupText.invalidFeedback; - }, - inputState() { - // When the state is valid we want to show no - // green outline. Hence passing null and not true. - if (this.state === true) { - return null; - } - return this.state; - }, - }, - methods: { - onInputBlur(e) { - this.$emit('input', e.target.value.trim() || null); - }, - }, -}; -</script> - -<template> - <gl-form-group :label="label" label-size="sm" :label-for="id" :invalid-feedback="invalidFeedback"> - <gl-form-input - :id="id" - :value="value" - :state="inputState" - :placeholder="inputGroupText.placeholder" - @blur="onInputBlur" - /> - </gl-form-group> -</template> diff --git a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js b/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js deleted file mode 100644 index 38b1a587b34..00000000000 --- a/app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js +++ /dev/null @@ -1,91 +0,0 @@ -import dateformat from '~/lib/dateformat'; -import { __ } from '~/locale'; - -/** - * Default time ranges for the date picker. - * @see app/assets/javascripts/lib/utils/datetime_range.js - */ -export const defaultTimeRanges = [ - { - duration: { seconds: 60 * 30 }, - label: __('30 minutes'), - }, - { - duration: { seconds: 60 * 60 * 3 }, - label: __('3 hours'), - }, - { - duration: { seconds: 60 * 60 * 8 }, - label: __('8 hours'), - default: true, - }, - { - duration: { seconds: 60 * 60 * 24 * 1 }, - label: __('1 day'), - }, -]; - -export const defaultTimeRange = defaultTimeRanges.find((tr) => tr.default); - -export const dateFormats = { - /** - * Format used by users to input dates - * - * Note: Should be a format that can be parsed by Date.parse. - */ - inputFormat: 'yyyy-mm-dd HH:MM:ss', - /** - * Format used to strip timezone from inputs - */ - stripTimezoneFormat: "yyyy-mm-dd'T'HH:MM:ss'Z'", -}; - -/** - * Returns true if the date can be parsed succesfully after - * being typed by a user. - * - * It allows some ambiguity so validation is not strict. - * - * @param {string} value - Value as typed by the user - * @returns true if the value can be parsed as a valid date, false otherwise - */ -export const isValidInputString = (value) => { - try { - // dateformat throws error that can be caught. - // This is better than using `new Date()` - if (value && value.trim()) { - dateformat(value, 'isoDateTime'); - return true; - } - return false; - } catch (e) { - return false; - } -}; - -/** - * Convert the input in time picker component to an ISO date. - * - * @param {string} value - * @param {Boolean} utc - If true, it forces the date to by - * formatted using UTC format, ignoring the local time. - * @returns {Date} - */ -export const inputStringToIsoDate = (value, utc = false) => { - let date = new Date(value); - if (utc) { - // Forces date to be interpreted as UTC by stripping the timezone - // by formatting to a string with 'Z' and skipping timezone - date = dateformat(date, dateFormats.stripTimezoneFormat); - } - return dateformat(date, 'isoUtcDateTime'); -}; - -/** - * Converts a iso date string to a formatted string for the Time picker component. - * - * @param {String} ISO Formatted date - * @returns {string} - */ -export const isoDateToInputString = (date, utc = false) => - dateformat(date, dateFormats.inputFormat, utc); diff --git a/app/assets/javascripts/vue_shared/components/split_button.vue b/app/assets/javascripts/vue_shared/components/split_button.vue deleted file mode 100644 index c0aef42b0f2..00000000000 --- a/app/assets/javascripts/vue_shared/components/split_button.vue +++ /dev/null @@ -1,85 +0,0 @@ -<script> -import { GlDropdown, GlDropdownDivider, GlDropdownItem } from '@gitlab/ui'; -import { isString } from 'lodash'; - -const isValidItem = (item) => - isString(item.eventName) && isString(item.title) && isString(item.description); - -export default { - components: { - GlDropdown, - GlDropdownDivider, - GlDropdownItem, - }, - - props: { - actionItems: { - type: Array, - required: true, - validator(value) { - return value.length > 1 && value.every(isValidItem); - }, - }, - menuClass: { - type: String, - required: false, - default: '', - }, - variant: { - type: String, - required: false, - default: 'default', - }, - }, - - data() { - return { - selectedItem: this.actionItems[0], - }; - }, - - computed: { - dropdownToggleText() { - return this.selectedItem.title; - }, - }, - - methods: { - triggerEvent() { - this.$emit(this.selectedItem.eventName); - }, - changeSelectedItem(item) { - this.selectedItem = item; - this.$emit('change', item); - }, - }, -}; -</script> - -<template> - <gl-dropdown - :menu-class="menuClass" - split - :text="dropdownToggleText" - :variant="variant" - v-bind="$attrs" - @click="triggerEvent" - > - <template v-for="(item, itemIndex) in actionItems"> - <gl-dropdown-item - :key="item.eventName" - is-check-item - :is-checked="selectedItem === item" - @click="changeSelectedItem(item)" - > - <strong>{{ item.title }}</strong> - <div>{{ item.description }}</div> - </gl-dropdown-item> - - <gl-dropdown-divider - v-if="itemIndex < actionItems.length - 1" - :key="`${item.eventName}-divider`" - /> - </template> - </gl-dropdown> -</template> diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index b02a636ff74..0fe31d74ae8 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -20,22 +20,6 @@ module IssuableCollections set_pagination return if redirect_out_of_range(@issuables, @total_pages) - - if params[:label_name].present? && @project - labels_params = { project_id: @project.id, title: params[:label_name] } - @labels = LabelsFinder.new(current_user, labels_params).execute - end - - @users = [] - if params[:assignee_id].present? - assignee = User.find_by_id(params[:assignee_id]) - @users.push(assignee) if assignee - end - - if params[:author_id].present? - author = User.find_by_id(params[:author_id]) - @users.push(author) if author - end end def set_pagination diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 86e914f3447..9abcc108ace 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -113,12 +113,6 @@ class Projects::IssuesController < Projects::ApplicationController respond_to do |format| format.html format.atom { render layout: 'xml' } - format.json do - render json: { - html: view_to_html_string("projects/issues/_issues"), - labels: @labels.as_json(methods: :text_color) - } - end end end @@ -281,7 +275,6 @@ class Projects::IssuesController < Projects::ApplicationController def service_desk @issues = @issuables - @users.push(Users::Internal.support_bot) end protected diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index d5a2213eda9..53fd7256b19 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -104,11 +104,6 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo respond_to do |format| format.html format.atom { render layout: 'xml' } - format.json do - render json: { - html: view_to_html_string("projects/merge_requests/_merge_requests") - } - end end end diff --git a/app/views/admin/application_settings/_visibility_and_access.html.haml b/app/views/admin/application_settings/_visibility_and_access.html.haml index f78ddade822..624f5a48c3a 100644 --- a/app/views/admin/application_settings/_visibility_and_access.html.haml +++ b/app/views/admin/application_settings/_visibility_and_access.html.haml @@ -19,6 +19,8 @@ = s_('AdminSettings|Restricted visibility levels') %small.form-text.text-gl-muted = s_('AdminSettings|Prevent non-administrators from using the selected visibility levels for groups, projects and snippets.') + = s_('AdminSettings|The selected level must be different from the selected default group and project visibility.') + = link_to _('Learn more.'), help_page_path('administration/settings/visibility_and_access_controls', anchor: 'restrict-visibility-levels'), target: '_blank', rel: 'noopener noreferrer' = hidden_field_tag 'application_setting[restricted_visibility_levels][]' .gl-form-checkbox-group - restricted_level_checkboxes(f).each do |checkbox| |