summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/lib/utils
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/lib/utils')
-rw-r--r--app/assets/javascripts/lib/utils/ace_utils.js6
-rw-r--r--app/assets/javascripts/lib/utils/apollo_startup_js_link.js106
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js21
-rw-r--r--app/assets/javascripts/lib/utils/constants.js1
-rw-r--r--app/assets/javascripts/lib/utils/css_utils.js2
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js4
-rw-r--r--app/assets/javascripts/lib/utils/dom_utils.js22
-rw-r--r--app/assets/javascripts/lib/utils/http_status.js1
-rw-r--r--app/assets/javascripts/lib/utils/number_utils.js14
-rw-r--r--app/assets/javascripts/lib/utils/text_utility.js12
10 files changed, 162 insertions, 27 deletions
diff --git a/app/assets/javascripts/lib/utils/ace_utils.js b/app/assets/javascripts/lib/utils/ace_utils.js
deleted file mode 100644
index ee71ae0e61a..00000000000
--- a/app/assets/javascripts/lib/utils/ace_utils.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/* global ace */
-
-export default function getModeByFileExtension(path) {
- const modelist = ace.require('ace/ext/modelist');
- return modelist.getModeForPath(path).mode;
-}
diff --git a/app/assets/javascripts/lib/utils/apollo_startup_js_link.js b/app/assets/javascripts/lib/utils/apollo_startup_js_link.js
new file mode 100644
index 00000000000..5c120dd532f
--- /dev/null
+++ b/app/assets/javascripts/lib/utils/apollo_startup_js_link.js
@@ -0,0 +1,106 @@
+import { ApolloLink, Observable } from 'apollo-link';
+import { parse } from 'graphql';
+import { isEqual, pickBy } from 'lodash';
+
+/**
+ * Remove undefined values from object
+ * @param obj
+ * @returns {Dictionary<unknown>}
+ */
+const pickDefinedValues = obj => pickBy(obj, x => x !== undefined);
+
+/**
+ * Compares two set of variables, order independent
+ *
+ * Ignores undefined values (in the top level) and supports arrays etc.
+ */
+const variablesMatch = (var1 = {}, var2 = {}) => {
+ return isEqual(pickDefinedValues(var1), pickDefinedValues(var2));
+};
+
+export class StartupJSLink extends ApolloLink {
+ constructor() {
+ super();
+ this.startupCalls = new Map();
+ this.parseStartupCalls(window.gl?.startup_graphql_calls || []);
+ }
+
+ // Extract operationNames from the queries and ensure that we can
+ // match operationName => element from result array
+ parseStartupCalls(calls) {
+ calls.forEach(call => {
+ const { query, variables, fetchCall } = call;
+ const operationName = parse(query)?.definitions?.find(x => x.kind === 'OperationDefinition')
+ ?.name?.value;
+
+ if (operationName) {
+ this.startupCalls.set(operationName, {
+ variables,
+ fetchCall,
+ });
+ }
+ });
+ }
+
+ static noopRequest = (operation, forward) => forward(operation);
+
+ disable() {
+ this.request = StartupJSLink.noopRequest;
+ this.startupCalls = null;
+ }
+
+ request(operation, forward) {
+ // Disable StartupJSLink in case all calls are done or none are set up
+ if (this.startupCalls && this.startupCalls.size === 0) {
+ this.disable();
+ return forward(operation);
+ }
+
+ const { operationName } = operation;
+
+ // Skip startup call if the operationName doesn't match
+ if (!this.startupCalls.has(operationName)) {
+ return forward(operation);
+ }
+
+ const { variables: startupVariables, fetchCall } = this.startupCalls.get(operationName);
+ this.startupCalls.delete(operationName);
+
+ // Skip startup call if the variables values do not match
+ if (!variablesMatch(startupVariables, operation.variables)) {
+ return forward(operation);
+ }
+
+ return new Observable(observer => {
+ fetchCall
+ .then(response => {
+ // Handle HTTP errors
+ if (!response.ok) {
+ throw new Error('fetchCall failed');
+ }
+ operation.setContext({ response });
+ return response.json();
+ })
+ .then(result => {
+ if (result && (result.errors || !result.data)) {
+ throw new Error('Received GraphQL error');
+ }
+
+ // we have data and can send it to back up the link chain
+ observer.next(result);
+ observer.complete();
+ })
+ .catch(() => {
+ forward(operation).subscribe({
+ next: result => {
+ observer.next(result);
+ },
+ error: error => {
+ observer.error(error);
+ },
+ complete: observer.complete.bind(observer),
+ });
+ });
+ });
+ }
+}
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index fe1ac00fd1d..42a5de68cfa 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -61,9 +61,6 @@ export const rstrip = val => {
return val;
};
-export const updateTooltipTitle = ($tooltipEl, newTitle) =>
- $tooltipEl.attr('title', newTitle).tooltip('_fixTitle');
-
export const disableButtonIfEmptyField = (fieldSelector, buttonSelector, eventName = 'input') => {
const field = $(fieldSelector);
const closestSubmit = field.closest('form').find(buttonSelector);
@@ -744,6 +741,24 @@ export const roundOffFloat = (number, precision = 0) => {
};
/**
+ * Method to round down values with decimal places
+ * with provided precision.
+ *
+ * Eg; roundDownFloat(3.141592, 3) = 3.141
+ *
+ * Refer to spec/javascripts/lib/utils/common_utils_spec.js for
+ * more supported examples.
+ *
+ * @param {Float} number
+ * @param {Number} precision
+ */
+export const roundDownFloat = (number, precision = 0) => {
+ // eslint-disable-next-line no-restricted-properties
+ const multiplier = Math.pow(10, precision);
+ return Math.floor(number * multiplier) / multiplier;
+};
+
+/**
* Represents navigation type constants of the Performance Navigation API.
* Detailed explanation see https://developer.mozilla.org/en-US/docs/Web/API/PerformanceNavigation.
*/
diff --git a/app/assets/javascripts/lib/utils/constants.js b/app/assets/javascripts/lib/utils/constants.js
index 1a4ecc12f01..993d51370ec 100644
--- a/app/assets/javascripts/lib/utils/constants.js
+++ b/app/assets/javascripts/lib/utils/constants.js
@@ -1,5 +1,4 @@
export const BYTES_IN_KIB = 1024;
-export const BYTES_IN_KB = 1000;
export const HIDDEN_CLASS = 'hidden';
export const TRUNCATE_WIDTH_DEFAULT_WIDTH = 80;
export const TRUNCATE_WIDTH_DEFAULT_FONT_SIZE = 12;
diff --git a/app/assets/javascripts/lib/utils/css_utils.js b/app/assets/javascripts/lib/utils/css_utils.js
index 90213221443..02f092e73e1 100644
--- a/app/assets/javascripts/lib/utils/css_utils.js
+++ b/app/assets/javascripts/lib/utils/css_utils.js
@@ -1,5 +1,7 @@
export function loadCSSFile(path) {
return new Promise(resolve => {
+ if (!path) resolve();
+
if (document.querySelector(`link[href="${path}"]`)) {
resolve();
} else {
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index 753245147d2..46b0f0cbc70 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -206,10 +206,6 @@ export const localTimeAgo = ($timeagoEls, setTimeago = true) => {
$timeagoEls.each((i, el) => {
// Recreate with custom template
el.setAttribute('title', formatDate(el.dateTime));
- $(el).tooltip({
- template:
- '<div class="tooltip local-timeago" role="tooltip"><div class="arrow"></div><div class="tooltip-inner"></div></div>',
- });
});
}
diff --git a/app/assets/javascripts/lib/utils/dom_utils.js b/app/assets/javascripts/lib/utils/dom_utils.js
index d9b0e8c4476..7bba7ba2f45 100644
--- a/app/assets/javascripts/lib/utils/dom_utils.js
+++ b/app/assets/javascripts/lib/utils/dom_utils.js
@@ -47,3 +47,25 @@ export const parseBooleanDataAttributes = ({ dataset }, names) =>
return acc;
}, {});
+
+/**
+ * Returns whether or not the provided element is currently visible.
+ * This function operates identically to jQuery's `:visible` pseudo-selector.
+ * Documentation for this selector: https://api.jquery.com/visible-selector/
+ * Implementation of this selector: https://github.com/jquery/jquery/blob/d0ce00cdfa680f1f0c38460bc51ea14079ae8b07/src/css/hiddenVisibleSelectors.js#L8
+ * @param {HTMLElement} element The element to test
+ * @returns {Boolean} `true` if the element is currently visible, otherwise false
+ */
+export const isElementVisible = element =>
+ Boolean(element.offsetWidth || element.offsetHeight || element.getClientRects().length);
+
+/**
+ * The opposite of `isElementVisible`.
+ * Returns whether or not the provided element is currently hidden.
+ * This function operates identically to jQuery's `:hidden` pseudo-selector.
+ * Documentation for this selector: https://api.jquery.com/hidden-selector/
+ * Implementation of this selector: https://github.com/jquery/jquery/blob/d0ce00cdfa680f1f0c38460bc51ea14079ae8b07/src/css/hiddenVisibleSelectors.js#L6
+ * @param {HTMLElement} element The element to test
+ * @returns {Boolean} `true` if the element is currently hidden, otherwise false
+ */
+export const isElementHidden = element => !isElementVisible(element);
diff --git a/app/assets/javascripts/lib/utils/http_status.js b/app/assets/javascripts/lib/utils/http_status.js
index 7132986a7e6..06529f06a66 100644
--- a/app/assets/javascripts/lib/utils/http_status.js
+++ b/app/assets/javascripts/lib/utils/http_status.js
@@ -22,6 +22,7 @@ const httpStatusCodes = {
CONFLICT: 409,
GONE: 410,
UNPROCESSABLE_ENTITY: 422,
+ TOO_MANY_REQUESTS: 429,
INTERNAL_SERVER_ERROR: 500,
SERVICE_UNAVAILABLE: 503,
};
diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js
index 2424d6cbf3b..bc87232f40b 100644
--- a/app/assets/javascripts/lib/utils/number_utils.js
+++ b/app/assets/javascripts/lib/utils/number_utils.js
@@ -1,4 +1,4 @@
-import { BYTES_IN_KIB, BYTES_IN_KB } from './constants';
+import { BYTES_IN_KIB } from './constants';
import { sprintf, __ } from '~/locale';
/**
@@ -35,18 +35,6 @@ export function formatRelevantDigits(number) {
}
/**
- * Utility function that calculates KB of the given bytes.
- * Note: This method calculates KiloBytes as opposed to
- * Kibibytes. For Kibibytes, bytesToKiB should be used.
- *
- * @param {Number} number bytes
- * @return {Number} KiB
- */
-export function bytesToKB(number) {
- return number / BYTES_IN_KB;
-}
-
-/**
* Utility function that calculates KiB of the given bytes.
*
* @param {Number} number bytes
diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js
index 8ac6a44cba9..a81ca3f211f 100644
--- a/app/assets/javascripts/lib/utils/text_utility.js
+++ b/app/assets/javascripts/lib/utils/text_utility.js
@@ -399,3 +399,15 @@ export const truncateNamespace = (string = '') => {
* @returns {Boolean}
*/
export const hasContent = obj => isString(obj) && obj.trim() !== '';
+
+/**
+ * A utility function that validates if a
+ * string is valid SHA1 hash format.
+ *
+ * @param {String} hash to validate
+ *
+ * @return {Boolean} true if valid
+ */
+export const isValidSha1Hash = str => {
+ return /^[0-9a-f]{5,40}$/.test(str);
+};