diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-17 14:33:21 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-17 14:33:21 +0300 |
commit | 7021455bd1ed7b125c55eb1b33c5a01f2bc55ee0 (patch) | |
tree | 5bdc2229f5198d516781f8d24eace62fc7e589e9 /app/assets/javascripts/lib/utils | |
parent | 185b095e93520f96e9cfc31d9c3e69b498cdab7c (diff) |
Add latest changes from gitlab-org/gitlab@15-6-stable-eev15.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/lib/utils')
7 files changed, 118 insertions, 127 deletions
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js index 4448a106bb6..beced4f9144 100644 --- a/app/assets/javascripts/lib/utils/common_utils.js +++ b/app/assets/javascripts/lib/utils/common_utils.js @@ -634,66 +634,6 @@ export const NavigationType = { }; /** - * Method to perform case-insensitive search for a string - * within multiple properties and return object containing - * properties in case there are multiple matches or `null` - * if there's no match. - * - * Eg; Suppose we want to allow user to search using for a string - * within `iid`, `title`, `url` or `reference` props of a target object; - * - * const objectToSearch = { - * "iid": 1, - * "title": "Error omnis quos consequatur ullam a vitae sed omnis libero cupiditate. &3", - * "url": "/groups/gitlab-org/-/epics/1", - * "reference": "&1", - * }; - * - * Following is how we call searchBy and the return values it will yield; - * - * - `searchBy('omnis', objectToSearch);`: This will return `{ title: ... }` as our - * query was found within title prop we only return that. - * - `searchBy('1', objectToSearch);`: This will return `{ "iid": ..., "reference": ..., "url": ... }`. - * - `searchBy('https://gitlab.com/groups/gitlab-org/-/epics/1', objectToSearch);`: - * This will return `{ "url": ... }`. - * - `searchBy('foo', objectToSearch);`: This will return `null` as no property value - * matched with our query. - * - * You can learn more about behaviour of this method by referring to tests - * within `spec/frontend/lib/utils/common_utils_spec.js`. - * - * @param {string} query String to search for - * @param {object} searchSpace Object containing properties to search in for `query` - */ -export const searchBy = (query = '', searchSpace = {}) => { - const targetKeys = searchSpace !== null ? Object.keys(searchSpace) : []; - - if (!query || !targetKeys.length) { - return null; - } - - const normalizedQuery = query.toLowerCase(); - const matches = targetKeys - .filter((item) => { - const searchItem = `${searchSpace[item]}`.toLowerCase(); - - return ( - searchItem.indexOf(normalizedQuery) > -1 || - normalizedQuery.indexOf(searchItem) > -1 || - normalizedQuery === searchItem - ); - }) - .reduce((acc, prop) => { - const match = acc; - match[prop] = searchSpace[prop]; - - return acc; - }, {}); - - return Object.keys(matches).length ? matches : null; -}; - -/** * Checks if the given Label has a special syntax `::` in * it's title. * diff --git a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_action.js b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_action.js new file mode 100644 index 00000000000..3bfbfea7f22 --- /dev/null +++ b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_action.js @@ -0,0 +1,57 @@ +import Vue from 'vue'; + +export function confirmAction( + message, + { + primaryBtnVariant, + primaryBtnText, + secondaryBtnVariant, + secondaryBtnText, + cancelBtnVariant, + cancelBtnText, + modalHtmlMessage, + title, + hideCancel, + } = {}, +) { + return new Promise((resolve) => { + let confirmed = false; + let component; + + const ConfirmAction = Vue.extend({ + components: { + ConfirmModal: () => import('./confirm_modal.vue'), + }, + render(h) { + return h( + 'confirm-modal', + { + props: { + secondaryText: secondaryBtnText, + secondaryVariant: secondaryBtnVariant, + primaryVariant: primaryBtnVariant, + primaryText: primaryBtnText, + cancelVariant: cancelBtnVariant, + cancelText: cancelBtnText, + title, + modalHtmlMessage, + hideCancel, + }, + on: { + confirmed() { + confirmed = true; + }, + closed() { + component.$destroy(); + resolve(confirmed); + }, + }, + }, + [message], + ); + }, + }); + + component = new ConfirmAction().$mount(); + }); +} diff --git a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js index 2dc479db80a..0e959e899e9 100644 --- a/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js +++ b/app/assets/javascripts/lib/utils/confirm_via_gl_modal/confirm_via_gl_modal.js @@ -1,75 +1,21 @@ -import Vue from 'vue'; +import { confirmAction } from './confirm_action'; -export function confirmAction( - message, - { - primaryBtnVariant, - primaryBtnText, - secondaryBtnVariant, - secondaryBtnText, - cancelBtnVariant, - cancelBtnText, - modalHtmlMessage, - title, - hideCancel, - } = {}, -) { - return new Promise((resolve) => { - let confirmed = false; - - const component = new Vue({ - components: { - ConfirmModal: () => import('./confirm_modal.vue'), - }, - render(h) { - return h( - 'confirm-modal', - { - props: { - secondaryText: secondaryBtnText, - secondaryVariant: secondaryBtnVariant, - primaryVariant: primaryBtnVariant, - primaryText: primaryBtnText, - cancelVariant: cancelBtnVariant, - cancelText: cancelBtnText, - title, - modalHtmlMessage, - hideCancel, - }, - on: { - confirmed() { - confirmed = true; - }, - closed() { - component.$destroy(); - resolve(confirmed); - }, - }, - }, - [message], - ); - }, - }).$mount(); - }); -} - -export function confirmViaGlModal(message, element) { - const primaryBtnConfig = {}; - - const { confirmBtnVariant } = element.dataset; - - if (confirmBtnVariant) { - primaryBtnConfig.primaryBtnVariant = confirmBtnVariant; - } +function confirmViaGlModal(message, element) { + const { confirmBtnVariant, title, isHtmlMessage } = element.dataset; const screenReaderText = element.querySelector('.gl-sr-only')?.textContent || element.querySelector('.sr-only')?.textContent || element.getAttribute('aria-label'); - if (screenReaderText) { - primaryBtnConfig.primaryBtnText = screenReaderText; - } + const config = { + ...(screenReaderText && { primaryBtnText: screenReaderText }), + ...(confirmBtnVariant && { primaryBtnVariant: confirmBtnVariant }), + ...(title && { title }), + ...(isHtmlMessage && { modalHtmlMessage: message }), + }; - return confirmAction(message, primaryBtnConfig); + return confirmAction(message, config); } + +export { confirmAction, confirmViaGlModal }; diff --git a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js index c11cf1a7882..4e0a59d0a38 100644 --- a/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js +++ b/app/assets/javascripts/lib/utils/datetime/date_calculation_utility.js @@ -271,6 +271,25 @@ export const secondsToMilliseconds = (seconds) => seconds * 1000; export const secondsToDays = (seconds) => Math.round(seconds / 86400); /** + * Returns the date `n` seconds after the date provided + * + * @param {Date} date the initial date + * @param {Number} numberOfSeconds number of seconds after + * @return {Date} A `Date` object `n` seconds after the provided `Date` + */ +export const nSecondsAfter = (date, numberOfSeconds) => + new Date(date.getTime() + numberOfSeconds * 1000); + +/** + * Returns the date `n` seconds before the date provided + * + * @param {Date} date the initial date + * @param {Number} numberOfSeconds number of seconds before + * @return {Date} A `Date` object `n` seconds before the provided `Date` + */ +export const nSecondsBefore = (date, numberOfSeconds) => nSecondsAfter(date, -numberOfSeconds); + +/** * Returns the date `n` days after the date provided * * @param {Date} date the initial date diff --git a/app/assets/javascripts/lib/utils/dom_utils.js b/app/assets/javascripts/lib/utils/dom_utils.js index bca6978c206..cafee641174 100644 --- a/app/assets/javascripts/lib/utils/dom_utils.js +++ b/app/assets/javascripts/lib/utils/dom_utils.js @@ -106,3 +106,15 @@ export const setAttributes = (el, attributes) => { el.setAttribute(key, attributes[key]); }); }; + +/** + * Get the height of the wrapper page element + * This height can be used to determine where the highest element goes in a page + * Useful for gl-drawer's header-height prop + * @param {String} contentWrapperClass the content wrapper class + * @returns {String} height in px + */ +export const getContentWrapperHeight = (contentWrapperClass) => { + const wrapperEl = document.querySelector(contentWrapperClass); + return wrapperEl ? `${wrapperEl.offsetTop}px` : ''; +}; diff --git a/app/assets/javascripts/lib/utils/unit_format/index.js b/app/assets/javascripts/lib/utils/unit_format/index.js index 5c5210027e4..bec7e48addc 100644 --- a/app/assets/javascripts/lib/utils/unit_format/index.js +++ b/app/assets/javascripts/lib/utils/unit_format/index.js @@ -22,6 +22,7 @@ export const SUPPORTED_FORMATS = { percentHundred: 'percentHundred', // Duration + days: 'days', seconds: 'seconds', milliseconds: 'milliseconds', @@ -65,6 +66,9 @@ export const getFormatter = (format = SUPPORTED_FORMATS.engineering) => { } // Durations + if (format === SUPPORTED_FORMATS.days) { + return suffixFormatter(s__('Units|d')); + } if (format === SUPPORTED_FORMATS.seconds) { return suffixFormatter(s__('Units|s')); } @@ -161,6 +165,19 @@ export const percent = getFormatter(SUPPORTED_FORMATS.percent); export const percentHundred = getFormatter(SUPPORTED_FORMATS.percentHundred); /** + * Formats a number of days + * + * @function + * @param {Number} value - Number to format, `1` is rendered as `1d` + * @param {Object} options - Formatting options + * @param {Number} options.fractionDigits - number of precision decimals + * @param {Number} options.maxLength - Max length of formatted number + * if length is exceeded, exponential format is used. + * @param {String} options.unitSeparator - Separator between value and unit + */ +export const days = getFormatter(SUPPORTED_FORMATS.days); + +/** * Formats a number of seconds * * @function diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js index ca90eee69c7..b1a0baf8150 100644 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ b/app/assets/javascripts/lib/utils/url_utility.js @@ -178,7 +178,7 @@ export function mergeUrlParams(params, url, options = {}) { const mergedKeys = sort ? Object.keys(merged).sort() : Object.keys(merged); const newQuery = mergedKeys - .filter((key) => merged[key] !== null) + .filter((key) => merged[key] !== null && merged[key] !== undefined) .map((key) => { let value = merged[key]; const encodedKey = encodeURIComponent(key); |