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
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-16 00:11:56 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-16 00:11:56 +0300
commitd30dfdfd05fedfa4b06f7905b5f193f3c6704284 (patch)
tree720a27bcaf375d8c02fbc267cde9620d443eeb30 /app
parent7a15fb07cf363079c4c4683850ee131d80e75f75 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/lib/utils/constants.js9
-rw-r--r--app/assets/javascripts/lib/utils/datetime_range.js309
-rw-r--r--app/assets/javascripts/super_sidebar/components/sidebar_menu.vue6
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker.vue283
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_input.vue77
-rw-r--r--app/assets/javascripts/vue_shared/components/date_time_picker/date_time_picker_lib.js91
-rw-r--r--app/assets/javascripts/vue_shared/components/split_button.vue85
-rw-r--r--app/controllers/concerns/issuable_collections.rb16
-rw-r--r--app/controllers/projects/issues_controller.rb7
-rw-r--r--app/controllers/projects/merge_requests_controller.rb5
-rw-r--r--app/views/admin/application_settings/_visibility_and_access.html.haml2
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|