summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/frequent_items/components/frequent_items_list.vue2
-rw-r--r--app/assets/javascripts/lib/utils/unit_format/formatter_factory.js20
-rw-r--r--app/assets/javascripts/lib/utils/unit_format/index.js106
-rw-r--r--app/assets/javascripts/notes/services/notes_service.js41
-rw-r--r--app/assets/javascripts/notes/stores/actions.js73
-rw-r--r--app/assets/javascripts/prometheus_metrics/prometheus_metrics.js6
-rw-r--r--app/assets/stylesheets/framework/typography.scss2
-rw-r--r--app/policies/project_policy.rb1
-rw-r--r--app/views/projects/_wiki.html.haml2
-rw-r--r--app/views/projects/blob/preview.html.haml2
-rw-r--r--app/views/projects/blob/viewers/_markup.html.haml2
-rw-r--r--app/views/projects/wikis/show.html.haml2
-rw-r--r--app/views/search/results/_snippet_blob.html.haml2
13 files changed, 176 insertions, 85 deletions
diff --git a/app/assets/javascripts/frequent_items/components/frequent_items_list.vue b/app/assets/javascripts/frequent_items/components/frequent_items_list.vue
index 0ece64692ae..9d898d1a1a1 100644
--- a/app/assets/javascripts/frequent_items/components/frequent_items_list.vue
+++ b/app/assets/javascripts/frequent_items/components/frequent_items_list.vue
@@ -58,7 +58,7 @@ export default {
<template>
<div class="frequent-items-list-container">
- <ul class="list-unstyled">
+ <ul ref="frequentItemsList" class="list-unstyled">
<li v-if="isListEmpty" :class="{ 'section-failure': isFetchFailed }" class="section-empty">
{{ listEmptyMessage }}
</li>
diff --git a/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js b/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js
index 432a9254558..98bcb8348e2 100644
--- a/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js
+++ b/app/assets/javascripts/lib/utils/unit_format/formatter_factory.js
@@ -117,3 +117,23 @@ export const scaledSIFormatter = (unit = '', prefixOffset = 0) => {
return scaledFormatter(units);
};
+
+/**
+ * Returns a function that formats a number scaled using SI units notation.
+ */
+export const scaledBinaryFormatter = (unit = '', prefixOffset = 0) => {
+ // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ const multiplicative = ['Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei', 'Zi', 'Yi'];
+ const symbols = ['', ...multiplicative];
+
+ const units = symbols.slice(prefixOffset).map(prefix => {
+ return `${prefix}${unit}`;
+ });
+
+ if (!units.length) {
+ // eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings
+ throw new RangeError('The unit cannot be converted, please try a different scale');
+ }
+
+ return scaledFormatter(units, 1024);
+};
diff --git a/app/assets/javascripts/lib/utils/unit_format/index.js b/app/assets/javascripts/lib/utils/unit_format/index.js
index daf70ebb5d7..d3aea37e677 100644
--- a/app/assets/javascripts/lib/utils/unit_format/index.js
+++ b/app/assets/javascripts/lib/utils/unit_format/index.js
@@ -1,9 +1,18 @@
import { s__ } from '~/locale';
-import { suffixFormatter, scaledSIFormatter, numberFormatter } from './formatter_factory';
+import {
+ suffixFormatter,
+ scaledSIFormatter,
+ scaledBinaryFormatter,
+ numberFormatter,
+} from './formatter_factory';
/**
* Supported formats
+ *
+ * Based on:
+ *
+ * https://tc39.es/proposal-unified-intl-numberformat/section6/locales-currencies-tz_proposed_out.html#sec-issanctionedsimpleunitidentifier
*/
export const SUPPORTED_FORMATS = {
// Number
@@ -13,15 +22,23 @@ export const SUPPORTED_FORMATS = {
// Duration
seconds: 'seconds',
- miliseconds: 'miliseconds',
+ milliseconds: 'milliseconds',
- // Digital
- bytes: 'bytes',
+ // Digital (Metric)
+ decimalBytes: 'decimalBytes',
kilobytes: 'kilobytes',
megabytes: 'megabytes',
gigabytes: 'gigabytes',
terabytes: 'terabytes',
petabytes: 'petabytes',
+
+ // Digital (IEC)
+ bytes: 'bytes',
+ kibibytes: 'kibibytes',
+ mebibytes: 'mebibytes',
+ gibibytes: 'gibibytes',
+ tebibytes: 'tebibytes',
+ pebibytes: 'pebibytes',
};
/**
@@ -32,6 +49,7 @@ export const SUPPORTED_FORMATS = {
*/
export const getFormatter = (format = SUPPORTED_FORMATS.number) => {
// Number
+
if (format === SUPPORTED_FORMATS.number) {
/**
* Formats a number
@@ -70,6 +88,7 @@ export const getFormatter = (format = SUPPORTED_FORMATS.number) => {
}
// Durations
+
if (format === SUPPORTED_FORMATS.seconds) {
/**
* Formats a number of seconds
@@ -82,9 +101,9 @@ export const getFormatter = (format = SUPPORTED_FORMATS.number) => {
*/
return suffixFormatter(s__('Units|s'));
}
- if (format === SUPPORTED_FORMATS.miliseconds) {
+ if (format === SUPPORTED_FORMATS.milliseconds) {
/**
- * Formats a number of miliseconds with ms as units
+ * Formats a number of milliseconds with ms as units
*
* @function
* @param {Number} value - Number to format, `1` is formatted as `1ms`
@@ -95,8 +114,9 @@ export const getFormatter = (format = SUPPORTED_FORMATS.number) => {
return suffixFormatter(s__('Units|ms'));
}
- // Digital
- if (format === SUPPORTED_FORMATS.bytes) {
+ // Digital (Metric)
+
+ if (format === SUPPORTED_FORMATS.decimalBytes) {
/**
* Formats a number of bytes scaled up to larger digital
* units for larger numbers.
@@ -162,6 +182,76 @@ export const getFormatter = (format = SUPPORTED_FORMATS.number) => {
*/
return scaledSIFormatter('B', 5);
}
+
+ // Digital (IEC)
+
+ if (format === SUPPORTED_FORMATS.bytes) {
+ /**
+ * Formats a number of bytes scaled up to larger digital
+ * units for larger numbers.
+ *
+ * @function
+ * @param {Number} value - Number to format, `1` is formatted as `1B`
+ * @param {Number} fractionDigits - number of precision decimals
+ */
+ return scaledBinaryFormatter('B');
+ }
+ if (format === SUPPORTED_FORMATS.kibibytes) {
+ /**
+ * Formats a number of kilobytes scaled up to larger digital
+ * units for larger numbers.
+ *
+ * @function
+ * @param {Number} value - Number to format, `1` is formatted as `1kB`
+ * @param {Number} fractionDigits - number of precision decimals
+ */
+ return scaledBinaryFormatter('B', 1);
+ }
+ if (format === SUPPORTED_FORMATS.mebibytes) {
+ /**
+ * Formats a number of megabytes scaled up to larger digital
+ * units for larger numbers.
+ *
+ * @function
+ * @param {Number} value - Number to format, `1` is formatted as `1MB`
+ * @param {Number} fractionDigits - number of precision decimals
+ */
+ return scaledBinaryFormatter('B', 2);
+ }
+ if (format === SUPPORTED_FORMATS.gibibytes) {
+ /**
+ * Formats a number of gigabytes scaled up to larger digital
+ * units for larger numbers.
+ *
+ * @function
+ * @param {Number} value - Number to format, `1` is formatted as `1GB`
+ * @param {Number} fractionDigits - number of precision decimals
+ */
+ return scaledBinaryFormatter('B', 3);
+ }
+ if (format === SUPPORTED_FORMATS.tebibytes) {
+ /**
+ * Formats a number of terabytes scaled up to larger digital
+ * units for larger numbers.
+ *
+ * @function
+ * @param {Number} value - Number to format, `1` is formatted as `1GB`
+ * @param {Number} fractionDigits - number of precision decimals
+ */
+ return scaledBinaryFormatter('B', 4);
+ }
+ if (format === SUPPORTED_FORMATS.pebibytes) {
+ /**
+ * Formats a number of petabytes scaled up to larger digital
+ * units for larger numbers.
+ *
+ * @function
+ * @param {Number} value - Number to format, `1` is formatted as `1PB`
+ * @param {Number} fractionDigits - number of precision decimals
+ */
+ return scaledBinaryFormatter('B', 5);
+ }
+
// Fail so client library addresses issue
throw TypeError(`${format} is not a valid number format`);
};
diff --git a/app/assets/javascripts/notes/services/notes_service.js b/app/assets/javascripts/notes/services/notes_service.js
deleted file mode 100644
index 4d3dbec435f..00000000000
--- a/app/assets/javascripts/notes/services/notes_service.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import axios from '~/lib/utils/axios_utils';
-import * as constants from '../constants';
-
-export default {
- fetchDiscussions(endpoint, filter, persistFilter = true) {
- const config =
- filter !== undefined
- ? { params: { notes_filter: filter, persist_filter: persistFilter } }
- : null;
- return axios.get(endpoint, config);
- },
- replyToDiscussion(endpoint, data) {
- return axios.post(endpoint, data);
- },
- updateNote(endpoint, data) {
- return axios.put(endpoint, data);
- },
- createNewNote(endpoint, data) {
- return axios.post(endpoint, data);
- },
- toggleResolveNote(endpoint, isResolved) {
- const { RESOLVE_NOTE_METHOD_NAME, UNRESOLVE_NOTE_METHOD_NAME } = constants;
- const method = isResolved ? UNRESOLVE_NOTE_METHOD_NAME : RESOLVE_NOTE_METHOD_NAME;
-
- return axios[method](endpoint);
- },
- poll(data = {}) {
- const endpoint = data.notesData.notesPath;
- const { lastFetchedAt } = data;
- const options = {
- headers: {
- 'X-Last-Fetched-At': lastFetchedAt ? `${lastFetchedAt}` : undefined,
- },
- };
-
- return axios.get(endpoint, options);
- },
- toggleIssueState(endpoint, data) {
- return axios.put(endpoint, data);
- },
-};
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index 594e3a14d56..a4b9c64645c 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -8,7 +8,6 @@ import Poll from '../../lib/utils/poll';
import * as types from './mutation_types';
import * as utils from './utils';
import * as constants from '../constants';
-import service from '../services/notes_service';
import loadAwardsHandler from '../../awards_handler';
import sidebarTimeTrackingEventHub from '../../sidebar/event_hub';
import { isInViewport, scrollToElement, isInMRPage } from '../../lib/utils/common_utils';
@@ -47,11 +46,17 @@ export const setNotesFetchedState = ({ commit }, state) =>
export const toggleDiscussion = ({ commit }, data) => commit(types.TOGGLE_DISCUSSION, data);
-export const fetchDiscussions = ({ commit, dispatch }, { path, filter, persistFilter }) =>
- service.fetchDiscussions(path, filter, persistFilter).then(({ data }) => {
+export const fetchDiscussions = ({ commit, dispatch }, { path, filter, persistFilter }) => {
+ const config =
+ filter !== undefined
+ ? { params: { notes_filter: filter, persist_filter: persistFilter } }
+ : null;
+
+ return axios.get(path, config).then(({ data }) => {
commit(types.SET_INITIAL_DISCUSSIONS, data);
dispatch('updateResolvableDiscussionsCounts');
});
+};
export const updateDiscussion = ({ commit, state }, discussion) => {
commit(types.UPDATE_DISCUSSION, discussion);
@@ -78,7 +83,7 @@ export const deleteNote = ({ dispatch }, note) =>
});
export const updateNote = ({ commit, dispatch }, { endpoint, note }) =>
- service.updateNote(endpoint, note).then(({ data }) => {
+ axios.put(endpoint, note).then(({ data }) => {
commit(types.UPDATE_NOTE, data);
dispatch('startTaskList');
});
@@ -109,7 +114,7 @@ export const replyToDiscussion = (
{ commit, state, getters, dispatch },
{ endpoint, data: reply },
) =>
- service.replyToDiscussion(endpoint, reply).then(({ data }) => {
+ axios.post(endpoint, reply).then(({ data }) => {
if (data.discussion) {
commit(types.UPDATE_DISCUSSION, data.discussion);
@@ -126,7 +131,7 @@ export const replyToDiscussion = (
});
export const createNewNote = ({ commit, dispatch }, { endpoint, data: reply }) =>
- service.createNewNote(endpoint, reply).then(({ data }) => {
+ axios.post(endpoint, reply).then(({ data }) => {
if (!data.errors) {
commit(types.ADD_NEW_NOTE, data);
@@ -156,20 +161,24 @@ export const resolveDiscussion = ({ state, dispatch, getters }, { discussionId }
});
};
-export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved, discussion }) =>
- service.toggleResolveNote(endpoint, isResolved).then(({ data }) => {
- const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE;
+export const toggleResolveNote = ({ commit, dispatch }, { endpoint, isResolved, discussion }) => {
+ const method = isResolved
+ ? constants.UNRESOLVE_NOTE_METHOD_NAME
+ : constants.RESOLVE_NOTE_METHOD_NAME;
+ const mutationType = discussion ? types.UPDATE_DISCUSSION : types.UPDATE_NOTE;
+ return axios[method](endpoint).then(({ data }) => {
commit(mutationType, data);
dispatch('updateResolvableDiscussionsCounts');
dispatch('updateMergeRequestWidget');
});
+};
export const closeIssue = ({ commit, dispatch, state }) => {
dispatch('toggleStateButtonLoading', true);
- return service.toggleIssueState(state.notesData.closePath).then(({ data }) => {
+ return axios.put(state.notesData.closePath).then(({ data }) => {
commit(types.CLOSE_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
@@ -178,7 +187,7 @@ export const closeIssue = ({ commit, dispatch, state }) => {
export const reopenIssue = ({ commit, dispatch, state }) => {
dispatch('toggleStateButtonLoading', true);
- return service.toggleIssueState(state.notesData.reopenPath).then(({ data }) => {
+ return axios.put(state.notesData.reopenPath).then(({ data }) => {
commit(types.REOPEN_ISSUE);
dispatch('emitStateChangedEvent', data);
dispatch('toggleStateButtonLoading', false);
@@ -355,11 +364,35 @@ const pollSuccessCallBack = (resp, commit, state, getters, dispatch) => {
return resp;
};
+const getFetchDataParams = state => {
+ const endpoint = state.notesData.notesPath;
+ const options = {
+ headers: {
+ 'X-Last-Fetched-At': state.lastFetchedAt ? `${state.lastFetchedAt}` : undefined,
+ },
+ };
+
+ return { endpoint, options };
+};
+
+export const fetchData = ({ commit, state, getters }) => {
+ const { endpoint, options } = getFetchDataParams(state);
+
+ axios
+ .get(endpoint, options)
+ .then(({ data }) => pollSuccessCallBack(data, commit, state, getters))
+ .catch(() => Flash(__('Something went wrong while fetching latest comments.')));
+};
+
export const poll = ({ commit, state, getters, dispatch }) => {
eTagPoll = new Poll({
- resource: service,
+ resource: {
+ poll: () => {
+ const { endpoint, options } = getFetchDataParams(state);
+ return axios.get(endpoint, options);
+ },
+ },
method: 'poll',
- data: state,
successCallback: ({ data }) => pollSuccessCallBack(data, commit, state, getters, dispatch),
errorCallback: () => Flash(__('Something went wrong while fetching latest comments.')),
});
@@ -367,7 +400,7 @@ export const poll = ({ commit, state, getters, dispatch }) => {
if (!Visibility.hidden()) {
eTagPoll.makeRequest();
} else {
- service.poll(state);
+ fetchData({ commit, state, getters });
}
Visibility.change(() => {
@@ -387,18 +420,6 @@ export const restartPolling = () => {
if (eTagPoll) eTagPoll.restart();
};
-export const fetchData = ({ commit, state, getters }) => {
- const requestData = {
- endpoint: state.notesData.notesPath,
- lastFetchedAt: state.lastFetchedAt,
- };
-
- service
- .poll(requestData)
- .then(({ data }) => pollSuccessCallBack(data, commit, state, getters))
- .catch(() => Flash(__('Something went wrong while fetching latest comments.')));
-};
-
export const toggleAward = ({ commit, getters }, { awardName, noteId }) => {
commit(types.TOGGLE_AWARD, { awardName, note: getters.notesById[noteId] });
};
diff --git a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
index 8380cfb6c59..8d779e04673 100644
--- a/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
+++ b/app/assets/javascripts/prometheus_metrics/prometheus_metrics.js
@@ -1,5 +1,5 @@
import $ from 'jquery';
-import _ from 'underscore';
+import { escape } from 'lodash';
import { s__, n__, sprintf } from '~/locale';
import axios from '../lib/utils/axios_utils';
import PANEL_STATE from './constants';
@@ -69,13 +69,13 @@ export default class PrometheusMetrics {
if (metric.active_metrics > 0) {
totalExporters += 1;
this.$monitoredMetricsList.append(
- `<li>${_.escape(metric.group)}<span class="badge">${_.escape(
+ `<li>${escape(metric.group)}<span class="badge">${escape(
metric.active_metrics,
)}</span></li>`,
);
totalMonitoredMetrics += metric.active_metrics;
if (metric.metrics_missing_requirements > 0) {
- this.$missingEnvVarMetricsList.append(`<li>${_.escape(metric.group)}</li>`);
+ this.$missingEnvVarMetricsList.append(`<li>${escape(metric.group)}</li>`);
totalMissingEnvVarMetrics += 1;
}
}
diff --git a/app/assets/stylesheets/framework/typography.scss b/app/assets/stylesheets/framework/typography.scss
index a1bfa03a5ac..0de5aae4b0e 100644
--- a/app/assets/stylesheets/framework/typography.scss
+++ b/app/assets/stylesheets/framework/typography.scss
@@ -59,7 +59,7 @@
max-width: 100%;
}
- &:not(.md-file) img:not(.emoji) {
+ &:not(.md) img:not(.emoji) {
border: 1px solid $white-normal;
padding: 5px;
margin: 5px 0;
diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb
index 507e227c952..4d49c96d268 100644
--- a/app/policies/project_policy.rb
+++ b/app/policies/project_policy.rb
@@ -312,6 +312,7 @@ class ProjectPolicy < BasePolicy
enable :destroy_artifacts
enable :daily_statistics
enable :admin_operations
+ enable :read_deploy_token
end
rule { (mirror_available & can?(:admin_project)) | admin }.enable :admin_remote_mirror
diff --git a/app/views/projects/_wiki.html.haml b/app/views/projects/_wiki.html.haml
index 6103d86bf5a..57a5d3e2e83 100644
--- a/app/views/projects/_wiki.html.haml
+++ b/app/views/projects/_wiki.html.haml
@@ -1,6 +1,6 @@
- if @wiki_home.present?
%div{ class: container_class }
- .md.md-file.prepend-top-default.append-bottom-default
+ .md.prepend-top-default.append-bottom-default
= render_wiki_content(@wiki_home)
- else
- can_create_wiki = can?(current_user, :create_wiki, @project)
diff --git a/app/views/projects/blob/preview.html.haml b/app/views/projects/blob/preview.html.haml
index 46e76e4d175..41a0045be89 100644
--- a/app/views/projects/blob/preview.html.haml
+++ b/app/views/projects/blob/preview.html.haml
@@ -1,5 +1,5 @@
- if markup?(@blob.name)
- .file-content.md.md-file
+ .file-content.md
= markup(@blob.name, @content)
- else
.diff-file
diff --git a/app/views/projects/blob/viewers/_markup.html.haml b/app/views/projects/blob/viewers/_markup.html.haml
index c71df29354b..8134adcbc32 100644
--- a/app/views/projects/blob/viewers/_markup.html.haml
+++ b/app/views/projects/blob/viewers/_markup.html.haml
@@ -1,4 +1,4 @@
- blob = viewer.blob
- context = blob.respond_to?(:rendered_markup) ? { rendered: blob.rendered_markup } : {}
-.file-content.md.md-file
+.file-content.md
= markup(blob.name, blob.data, context)
diff --git a/app/views/projects/wikis/show.html.haml b/app/views/projects/wikis/show.html.haml
index ebd99cf8605..74798311c2e 100644
--- a/app/views/projects/wikis/show.html.haml
+++ b/app/views/projects/wikis/show.html.haml
@@ -26,7 +26,7 @@
= (s_("WikiHistoricalPage|You can view the %{most_recent_link} or browse the %{history_link}.") % { most_recent_link: most_recent_link, history_link: history_link }).html_safe
.prepend-top-default.append-bottom-default
- .md.md-file{ data: { qa_selector: 'wiki_page_content' } }
+ .md{ data: { qa_selector: 'wiki_page_content' } }
= render_wiki_content(@page)
= render 'sidebar'
diff --git a/app/views/search/results/_snippet_blob.html.haml b/app/views/search/results/_snippet_blob.html.haml
index 5126351b0bb..fa77566dddb 100644
--- a/app/views/search/results/_snippet_blob.html.haml
+++ b/app/views/search/results/_snippet_blob.html.haml
@@ -23,7 +23,7 @@
%i.fa.fa-file
%strong= snippet.file_name
- if markup?(snippet.file_name)
- .file-content.md.md-file
+ .file-content.md
- snippet_chunks.each do |chunk|
- unless chunk[:data].empty?
= markup(snippet.file_name, chunk[:data])