diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-09 15:09:29 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-09 15:09:29 +0000 |
commit | 209bd8cf1f542f6ba2a069b368a9187faa871e96 (patch) | |
tree | 6b77dc8183135b8316cc70c8dbc9c4e7c18cf05a /app | |
parent | a9ced7da447785c57477b3d8dbccc73a78cface1 (diff) | |
download | gitlab-ce-209bd8cf1f542f6ba2a069b368a9187faa871e96.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
25 files changed, 171 insertions, 60 deletions
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js index 3c00ae98e75..cc9bfa2e174 100644 --- a/app/assets/javascripts/diffs/store/mutations.js +++ b/app/assets/javascripts/diffs/store/mutations.js @@ -326,6 +326,7 @@ export default { }, [types.SET_SHOW_WHITESPACE](state, showWhitespace) { state.showWhitespace = showWhitespace; + state.diffFiles = []; }, [types.TOGGLE_FILE_FINDER_VISIBLE](state, visible) { state.fileFinderVisible = visible; diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index fdd27e08793..1678991b1ea 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -5,6 +5,7 @@ import { highCountTrim } from '~/lib/utils/text_utility'; import SetStatusModalTrigger from './set_status_modal/set_status_modal_trigger.vue'; import SetStatusModalWrapper from './set_status_modal/set_status_modal_wrapper.vue'; import { parseBoolean } from '~/lib/utils/common_utils'; +import Tracking from '~/tracking'; /** * Updates todo counter when todos are toggled. @@ -73,6 +74,24 @@ function initStatusTriggers() { } } +export function initNavUserDropdownTracking() { + const el = document.querySelector('.js-nav-user-dropdown'); + const buyEl = document.querySelector('.js-buy-ci-minutes-link'); + + if (el && buyEl) { + const { trackLabel, trackProperty } = buyEl.dataset; + const trackEvent = 'show_buy_ci_minutes'; + + $(el).on('shown.bs.dropdown', () => { + Tracking.event(undefined, trackEvent, { + label: trackLabel, + property: trackProperty, + }); + }); + } +} + document.addEventListener('DOMContentLoaded', () => { requestIdleCallback(initStatusTriggers); + initNavUserDropdownTracking(); }); diff --git a/app/assets/javascripts/helpers/monitor_helper.js b/app/assets/javascripts/helpers/monitor_helper.js index 87b4b14f6bf..94a0d38f05f 100644 --- a/app/assets/javascripts/helpers/monitor_helper.js +++ b/app/assets/javascripts/helpers/monitor_helper.js @@ -1,4 +1,64 @@ /** + * @param {String} queryLabel - Default query label for chart + * @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance) + * @returns {String} The formatted query label + * @example + * singleAttributeLabel('app', {__name__: "up", app: "prometheus"}) -> "app: prometheus" + */ +const singleAttributeLabel = (queryLabel, metricAttributes) => { + if (!queryLabel) return ''; + const relevantAttribute = queryLabel.toLowerCase().replace(' ', '_'); + const value = metricAttributes[relevantAttribute]; + if (!value) return ''; + return `${queryLabel}: ${value}`; +}; + +/** + * @param {String} queryLabel - Default query label for chart + * @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance) + * @returns {String} The formatted query label + * @example + * templatedLabel('__name__', {__name__: "up", app: "prometheus"}) -> "__name__" + */ +const templatedLabel = (queryLabel, metricAttributes) => { + if (!queryLabel) return ''; + // eslint-disable-next-line array-callback-return + Object.entries(metricAttributes).map(([templateVar, label]) => { + const regex = new RegExp(`{{\\s*${templateVar}\\s*}}`, 'g'); + // eslint-disable-next-line no-param-reassign + queryLabel = queryLabel.replace(regex, label); + }); + + return queryLabel; +}; + +/** + * @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance) + * @returns {String} The formatted query label + * @example + * multiMetricLabel('', {__name__: "up", app: "prometheus"}) -> "__name__: up, app: prometheus" + */ +const multiMetricLabel = metricAttributes => { + return Object.entries(metricAttributes) + .map(([templateVar, label]) => `${templateVar}: ${label}`) + .join(', '); +}; + +/** + * @param {String} queryLabel - Default query label for chart + * @param {Object} metricAttributes - Default metric attribute values (e.g. method, instance) + * @returns {String} The formatted query label + */ +const getSeriesLabel = (queryLabel, metricAttributes) => { + return ( + singleAttributeLabel(queryLabel, metricAttributes) || + templatedLabel(queryLabel, metricAttributes) || + multiMetricLabel(metricAttributes) || + queryLabel + ); +}; + +/** * @param {Array} queryResults - Array of Result objects * @param {Object} defaultConfig - Default chart config values (e.g. lineStyle, name) * @returns {Array} The formatted values @@ -12,21 +72,11 @@ export const makeDataSeries = (queryResults, defaultConfig) => if (!data.length) { return null; } - const relevantMetric = defaultConfig.name.toLowerCase().replace(' ', '_'); - const name = result.metric[relevantMetric]; const series = { data }; - if (name) { - series.name = `${defaultConfig.name}: ${name}`; - } else { - series.name = defaultConfig.name; - Object.keys(result.metric).forEach(templateVar => { - const value = result.metric[templateVar]; - const regex = new RegExp(`{{\\s*${templateVar}\\s*}}`, 'g'); - - series.name = series.name.replace(regex, value); - }); - } - - return { ...defaultConfig, ...series }; + return { + ...defaultConfig, + ...series, + name: getSeriesLabel(defaultConfig.name, result.metric), + }; }) .filter(series => series !== null); diff --git a/app/assets/javascripts/monitoring/components/charts/bar.vue b/app/assets/javascripts/monitoring/components/charts/bar.vue index 01fd8940dad..e1018cd5952 100644 --- a/app/assets/javascripts/monitoring/components/charts/bar.vue +++ b/app/assets/javascripts/monitoring/components/charts/bar.vue @@ -58,7 +58,7 @@ export default { }, methods: { formatLegendLabel(query) { - return `${query.label}`; + return query.label; }, onResize() { if (!this.$refs.barChart) return; diff --git a/app/assets/javascripts/monitoring/components/charts/column.vue b/app/assets/javascripts/monitoring/components/charts/column.vue index 0ed801e6e57..7a2e3e1b511 100644 --- a/app/assets/javascripts/monitoring/components/charts/column.vue +++ b/app/assets/javascripts/monitoring/components/charts/column.vue @@ -76,7 +76,7 @@ export default { }, methods: { formatLegendLabel(query) { - return `${query.label}`; + return query.label; }, onResize() { if (!this.$refs.columnChart) return; diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue index e43a0131528..f4cd6bbbb34 100644 --- a/app/assets/javascripts/monitoring/components/charts/time_series.vue +++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue @@ -251,7 +251,7 @@ export default { }, methods: { formatLegendLabel(query) { - return `${query.label}`; + return query.label; }, isTooltipOfType(tooltipType, defaultType) { return tooltipType === defaultType; diff --git a/app/assets/javascripts/monitoring/stores/utils.js b/app/assets/javascripts/monitoring/stores/utils.js index 5e620d6c2f5..d01acdd031b 100644 --- a/app/assets/javascripts/monitoring/stores/utils.js +++ b/app/assets/javascripts/monitoring/stores/utils.js @@ -68,12 +68,11 @@ export const parseEnvironmentsResponse = (response = [], projectPath) => * https://gitlab.com/gitlab-org/gitlab/issues/207198 * * @param {Array} metrics - Array of prometheus metrics - * @param {String} defaultLabel - Default label for metrics * @returns {Object} */ -const mapToMetricsViewModel = (metrics, defaultLabel) => +const mapToMetricsViewModel = metrics => metrics.map(({ label, id, metric_id, query_range, prometheus_endpoint_path, ...metric }) => ({ - label: label || defaultLabel, + label, queryRange: query_range, prometheusEndpointPath: prometheus_endpoint_path, metricId: uniqMetricsId({ metric_id, id }), diff --git a/app/assets/javascripts/repository/router.js b/app/assets/javascripts/repository/router.js index d74447dd566..b2636f910fe 100644 --- a/app/assets/javascripts/repository/router.js +++ b/app/assets/javascripts/repository/router.js @@ -12,7 +12,7 @@ export default function createRouter(base, baseRef) { base: joinPaths(gon.relative_url_root || '', base), routes: [ { - path: `(/-)?/tree/(${encodeURIComponent(baseRef)}|${baseRef})/:path*`, + path: `(/-)?/tree/(${encodeURIComponent(baseRef).replace(/%2F/g, '/')}|${baseRef})/:path*`, name: 'treePath', component: TreePage, props: route => ({ diff --git a/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue b/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue new file mode 100644 index 00000000000..83b50b2f8eb --- /dev/null +++ b/app/assets/javascripts/static_site_editor/components/publish_toolbar.vue @@ -0,0 +1,23 @@ +<script> +import { GlNewButton } from '@gitlab/ui'; + +export default { + components: { + GlNewButton, + }, + props: { + saveable: { + type: Boolean, + required: false, + default: false, + }, + }, +}; +</script> +<template> + <div class="d-flex bg-light border-top justify-content-between align-items-center py-3 px-4"> + <gl-new-button variant="success" :disabled="!saveable"> + {{ __('Submit Changes') }} + </gl-new-button> + </div> +</template> diff --git a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue b/app/assets/javascripts/static_site_editor/components/static_site_editor.vue index f06d48ee4f5..80a55d5ee11 100644 --- a/app/assets/javascripts/static_site_editor/components/static_site_editor.vue +++ b/app/assets/javascripts/static_site_editor/components/static_site_editor.vue @@ -3,27 +3,29 @@ import { mapState, mapGetters, mapActions } from 'vuex'; import { GlSkeletonLoader } from '@gitlab/ui'; import EditArea from './edit_area.vue'; +import Toolbar from './publish_toolbar.vue'; export default { components: { EditArea, GlSkeletonLoader, + Toolbar, }, computed: { ...mapState(['content', 'isLoadingContent']), - ...mapGetters(['isContentLoaded']), + ...mapGetters(['isContentLoaded', 'contentChanged']), }, mounted() { this.loadContent(); }, methods: { - ...mapActions(['loadContent']), + ...mapActions(['loadContent', 'setContent']), }, }; </script> <template> - <div class="d-flex justify-content-center h-100"> - <div v-if="isLoadingContent" class="w-50 h-50 mt-2"> + <div class="d-flex justify-content-center h-100 pt-2"> + <div v-if="isLoadingContent" class="w-50 h-50"> <gl-skeleton-loader :width="500" :height="102"> <rect width="500" height="16" rx="4" /> <rect y="20" width="375" height="16" rx="4" /> @@ -33,6 +35,13 @@ export default { <rect x="410" y="40" width="90" height="16" rx="4" /> </gl-skeleton-loader> </div> - <edit-area v-if="isContentLoaded" class="w-75 h-100 shadow-none" :value="content" /> + <div v-if="isContentLoaded" class="d-flex flex-grow-1 flex-column"> + <edit-area + class="w-75 h-100 shadow-none align-self-center" + :value="content" + @input="setContent" + /> + <toolbar :saveable="contentChanged" /> + </div> </div> </template> diff --git a/app/assets/javascripts/static_site_editor/store/actions.js b/app/assets/javascripts/static_site_editor/store/actions.js index 192345f3749..141148de1e0 100644 --- a/app/assets/javascripts/static_site_editor/store/actions.js +++ b/app/assets/javascripts/static_site_editor/store/actions.js @@ -15,4 +15,8 @@ export const loadContent = ({ commit, state: { sourcePath, projectId } }) => { }); }; +export const setContent = ({ commit }, content) => { + commit(mutationTypes.SET_CONTENT, content); +}; + export default () => {}; diff --git a/app/assets/javascripts/static_site_editor/store/getters.js b/app/assets/javascripts/static_site_editor/store/getters.js index 8baa2941594..41256201c26 100644 --- a/app/assets/javascripts/static_site_editor/store/getters.js +++ b/app/assets/javascripts/static_site_editor/store/getters.js @@ -1,2 +1,2 @@ -// eslint-disable-next-line import/prefer-default-export -export const isContentLoaded = ({ content }) => Boolean(content); +export const isContentLoaded = ({ originalContent }) => Boolean(originalContent); +export const contentChanged = ({ originalContent, content }) => originalContent !== content; diff --git a/app/assets/javascripts/static_site_editor/store/mutation_types.js b/app/assets/javascripts/static_site_editor/store/mutation_types.js index cbe51180541..2bb201f5d24 100644 --- a/app/assets/javascripts/static_site_editor/store/mutation_types.js +++ b/app/assets/javascripts/static_site_editor/store/mutation_types.js @@ -1,3 +1,4 @@ export const LOAD_CONTENT = 'loadContent'; export const RECEIVE_CONTENT_SUCCESS = 'receiveContentSuccess'; export const RECEIVE_CONTENT_ERROR = 'receiveContentError'; +export const SET_CONTENT = 'setContent'; diff --git a/app/assets/javascripts/static_site_editor/store/mutations.js b/app/assets/javascripts/static_site_editor/store/mutations.js index 88cb74d2b11..8b8bacf35c2 100644 --- a/app/assets/javascripts/static_site_editor/store/mutations.js +++ b/app/assets/javascripts/static_site_editor/store/mutations.js @@ -8,8 +8,12 @@ export default { state.isLoadingContent = false; state.title = title; state.content = content; + state.originalContent = content; }, [types.RECEIVE_CONTENT_ERROR](state) { state.isLoadingContent = false; }, + [types.SET_CONTENT](state, content) { + state.content = content; + }, }; diff --git a/app/assets/javascripts/static_site_editor/store/state.js b/app/assets/javascripts/static_site_editor/store/state.js index b68e73f06f5..1ae11b3343d 100644 --- a/app/assets/javascripts/static_site_editor/store/state.js +++ b/app/assets/javascripts/static_site_editor/store/state.js @@ -3,7 +3,9 @@ const createState = (initialState = {}) => ({ sourcePath: null, isLoadingContent: false, + isSavingChanges: false, + originalContent: '', content: '', title: '', diff --git a/app/models/ci/build_dependencies.rb b/app/models/ci/build_dependencies.rb index b5d67ef8e96..d3ff870e36a 100644 --- a/app/models/ci/build_dependencies.rb +++ b/app/models/ci/build_dependencies.rb @@ -67,7 +67,6 @@ module Ci end def from_needs(scope) - return scope unless Feature.enabled?(:ci_dag_support, project, default_enabled: true) return scope unless processable.scheduling_type_dag? needs_names = processable.needs.artifacts.select(:name) diff --git a/app/models/ci/processable.rb b/app/models/ci/processable.rb index 55518f32316..4bc8f26ec92 100644 --- a/app/models/ci/processable.rb +++ b/app/models/ci/processable.rb @@ -25,8 +25,6 @@ module Ci end def self.select_with_aggregated_needs(project) - return all unless Feature.enabled?(:ci_dag_support, project, default_enabled: true) - aggregated_needs_names = Ci::BuildNeed .scoped_build .select("ARRAY_AGG(name)") diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 2edb1a45100..b9acb539404 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -555,22 +555,28 @@ class MergeRequest < ApplicationRecord end end + def diff_stats + return unless diff_refs + + strong_memoize(:diff_stats) do + project.repository.diff_stats(diff_refs.base_sha, diff_refs.head_sha) + end + end + def diff_size # Calling `merge_request_diff.diffs.real_size` will also perform # highlighting, which we don't need here. - merge_request_diff&.real_size || diffs.real_size + merge_request_diff&.real_size || diff_stats&.real_size || diffs.real_size end def modified_paths(past_merge_request_diff: nil) - diffs = if past_merge_request_diff - past_merge_request_diff - elsif compare - compare - else - self.merge_request_diff - end - - diffs.modified_paths + if past_merge_request_diff + past_merge_request_diff.modified_paths + elsif compare + diff_stats&.paths || compare.modified_paths + else + merge_request_diff.modified_paths + end end def new_paths diff --git a/app/models/snippet.rb b/app/models/snippet.rb index 821de70f9d9..dbf600cf0df 100644 --- a/app/models/snippet.rb +++ b/app/models/snippet.rb @@ -267,7 +267,7 @@ class Snippet < ApplicationRecord def repository_size_checker strong_memoize(:repository_size_checker) do ::Gitlab::RepositorySizeChecker.new( - current_size_proc: -> { repository._uncached_size.megabytes }, + current_size_proc: -> { repository.size.megabytes }, limit: Gitlab::CurrentSettings.snippet_size_limit ) end diff --git a/app/services/ci/compare_reports_base_service.rb b/app/services/ci/compare_reports_base_service.rb index 83ba70e8437..2e84f914db3 100644 --- a/app/services/ci/compare_reports_base_service.rb +++ b/app/services/ci/compare_reports_base_service.rb @@ -8,7 +8,8 @@ module Ci # issue: https://gitlab.com/gitlab-org/gitlab/issues/34224 class CompareReportsBaseService < ::BaseService def execute(base_pipeline, head_pipeline) - comparer = comparer_class.new(get_report(base_pipeline), get_report(head_pipeline)) + comparer = build_comparer(base_pipeline, head_pipeline) + { status: :parsed, key: key(base_pipeline, head_pipeline), @@ -28,6 +29,12 @@ module Ci data&.fetch(:key, nil) == key(base_pipeline, head_pipeline) end + protected + + def build_comparer(base_pipeline, head_pipeline) + comparer_class.new(get_report(base_pipeline), get_report(head_pipeline)) + end + private def key(base_pipeline, head_pipeline) diff --git a/app/services/ci/pipeline_processing/atomic_processing_service.rb b/app/services/ci/pipeline_processing/atomic_processing_service.rb index 55846c3cb5c..2a1bf15b9a3 100644 --- a/app/services/ci/pipeline_processing/atomic_processing_service.rb +++ b/app/services/ci/pipeline_processing/atomic_processing_service.rb @@ -93,7 +93,7 @@ module Ci end def processable_status(processable) - if Feature.enabled?(:ci_dag_support, project, default_enabled: true) && processable.scheduling_type_dag? + if processable.scheduling_type_dag? # Processable uses DAG, get status of all dependent needs @collection.status_for_names(processable.aggregated_needs_names.to_a) else diff --git a/app/services/ci/pipeline_processing/legacy_processing_service.rb b/app/services/ci/pipeline_processing/legacy_processing_service.rb index 8d7b80282fc..c471f7f0011 100644 --- a/app/services/ci/pipeline_processing/legacy_processing_service.rb +++ b/app/services/ci/pipeline_processing/legacy_processing_service.rb @@ -43,8 +43,6 @@ module Ci end def process_dag_builds_without_needs - return false unless Feature.enabled?(:ci_dag_support, project, default_enabled: true) - created_processables.scheduling_type_dag.without_needs.each do |build| process_build(build, 'success') end @@ -52,7 +50,6 @@ module Ci def process_dag_builds_with_needs(trigger_build_ids) return false unless trigger_build_ids.present? - return false unless Feature.enabled?(:ci_dag_support, project, default_enabled: true) # we find processables that are dependent: # 1. because of current dependency, @@ -110,11 +107,7 @@ module Ci end def created_stage_scheduled_processables - if Feature.enabled?(:ci_dag_support, project, default_enabled: true) - created_processables.scheduling_type_stage - else - created_processables - end + created_processables.scheduling_type_stage end def created_processables diff --git a/app/views/layouts/header/_default.html.haml b/app/views/layouts/header/_default.html.haml index 5636df7d5e0..f6255dac7cf 100644 --- a/app/views/layouts/header/_default.html.haml +++ b/app/views/layouts/header/_default.html.haml @@ -65,7 +65,7 @@ .dropdown-menu.dropdown-menu-right = render 'layouts/header/help_dropdown' - if header_link?(:user_dropdown) - %li.nav-item.header-user.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown", track_value: "", qa_selector: 'user_menu' }, class: ('mr-0' if has_impersonation_link) } + %li.nav-item.header-user.js-nav-user-dropdown.dropdown{ data: { track_label: "profile_dropdown", track_event: "click_dropdown", track_value: "", qa_selector: 'user_menu' }, class: ('mr-0' if has_impersonation_link) } = link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do = image_tag avatar_icon_for_user(current_user, 23), width: 23, height: 23, class: "header-user-avatar qa-user-avatar" = render_if_exists 'layouts/header/user_notification_dot', project: project, namespace: group diff --git a/app/views/projects/static_site_editor/show.html.haml b/app/views/projects/static_site_editor/show.html.haml index 574cdd0bf88..9ccc54e6d51 100644 --- a/app/views/projects/static_site_editor/show.html.haml +++ b/app/views/projects/static_site_editor/show.html.haml @@ -1 +1 @@ -#static-site-editor{ data: {} } +#static-site-editor{ data: { project_id: '8', path: 'README.md' } } diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 5178fabb2d8..ddf112e648c 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -77,12 +77,8 @@ class PostReceive # rubocop:disable Scalability/IdempotentWorker return false unless user - # At the moment, we only expires the repository caches. - # In the future we might need to call ProjectCacheWorker - # (or the custom class we create) to update the snippet - # repository size or any other key. - # We might also need to update the repository statistics. expire_caches(post_received, snippet.repository) + snippet.repository.expire_statistics_caches end # Expire the repository status, branch, and tag cache once per push. |