From b4b6bff01d33ddf1ebd78001f16027b3ccd6443e Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 13 Oct 2020 18:08:58 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- Gemfile | 2 +- Gemfile.lock | 6 +- app/assets/javascripts/behaviors/gl_emoji.js | 4 +- .../diffs/components/diff_file_header.vue | 13 +- app/assets/javascripts/diffs/i18n.js | 5 + .../pipeline_graph/drawing_utils.js | 15 +- .../components/pipeline_graph/job_pill.vue | 41 +- .../pipeline_graph/pipeline_graph.vue | 81 +++- app/assets/javascripts/pipelines/utils.js | 44 ++- .../snippets/components/snippet_blob_edit.vue | 6 +- app/assets/javascripts/tracking.js | 2 +- .../page_bundles/_pipeline_mixins.scss | 207 ++++++++++ .../stylesheets/page_bundles/pipeline.scss | 38 +- .../stylesheets/page_bundles/pipelines.scss | 141 ++++++- app/assets/stylesheets/pages/pipelines.scss | 370 ------------------ .../projects/static_site_editor_controller.rb | 2 + .../concerns/resolves_merge_requests.rb | 1 + app/graphql/types/merge_request_type.rb | 6 + app/services/jira/requests/base.rb | 7 +- .../composer/composer_json_service.rb | 6 +- app/views/projects/commit/show.html.haml | 1 + .../232503-editor-lite-to-snippet.yml | 5 + .../unreleased/233994_sse_usage_ping.yml | 5 + .../239090-fix-throughput-chart.yml | 6 + .../260323-handle-malformed-composer-json.yml | 5 + .../fix-gl-emoji-race-condition.yml | 5 + .../ci_bridge_pipeline_details.yml | 7 - config/initializers/sprockets.rb | 2 - danger/documentation/Dangerfile | 3 +- doc/administration/pages/index.md | 10 +- doc/ci/yaml/README.md | 5 +- lib/api/composer_packages.rb | 4 + lib/gitlab/ci/status/bridge/common.rb | 1 - lib/gitlab/database/reindexing.rb | 6 +- .../database/reindexing/concurrent_reindex.rb | 13 +- lib/gitlab/database/reindexing/coordinator.rb | 41 ++ lib/gitlab/usage_data.rb | 3 +- .../static_site_editor_counter.rb | 16 + lib/tasks/gitlab/db.rake | 2 +- .../static_site_editor_controller_spec.rb | 5 + .../pipelines/pipeline_graph/mock_data.js | 21 +- .../pipelines/pipeline_graph/utils_spec.js | 324 ++++++++------- .../snippet_blob_edit_spec.js.snap | 3 +- .../components/snippet_blob_edit_spec.js | 16 +- spec/frontend/tracking_spec.js | 2 +- spec/graphql/types/merge_request_type_spec.rb | 36 ++ .../gitlab/ci/status/bridge/common_spec.rb | 9 - .../reindexing/concurrent_reindex_spec.rb | 6 +- .../database/reindexing/coordinator_spec.rb | 68 ++++ spec/lib/gitlab/database/reindexing_spec.rb | 52 +-- .../static_site_editor_counter_spec.rb | 10 + spec/lib/gitlab/usage_data_spec.rb | 1 + spec/requests/api/composer_packages_spec.rb | 28 ++ .../requests/projects/list_service_spec.rb | 4 + .../composer/composer_json_service_spec.rb | 4 +- spec/tasks/gitlab/db_rake_spec.rb | 2 +- 56 files changed, 1072 insertions(+), 656 deletions(-) create mode 100644 app/assets/javascripts/diffs/i18n.js create mode 100644 changelogs/unreleased/232503-editor-lite-to-snippet.yml create mode 100644 changelogs/unreleased/233994_sse_usage_ping.yml create mode 100644 changelogs/unreleased/239090-fix-throughput-chart.yml create mode 100644 changelogs/unreleased/260323-handle-malformed-composer-json.yml create mode 100644 changelogs/unreleased/fix-gl-emoji-race-condition.yml delete mode 100644 config/feature_flags/development/ci_bridge_pipeline_details.yml create mode 100644 lib/gitlab/database/reindexing/coordinator.rb create mode 100644 lib/gitlab/usage_data_counters/static_site_editor_counter.rb create mode 100644 spec/lib/gitlab/database/reindexing/coordinator_spec.rb create mode 100644 spec/lib/gitlab/usage_data_counters/static_site_editor_counter_spec.rb diff --git a/Gemfile b/Gemfile index 3110bee4979..a5ab8de90e0 100644 --- a/Gemfile +++ b/Gemfile @@ -290,7 +290,7 @@ gem 'gitlab_chronic_duration', '~> 0.10.6.2' gem 'rack-proxy', '~> 0.6.0' gem 'sassc-rails', '~> 2.1.0' -gem 'gitlab-terser', '1.0.1.1' +gem 'terser', '1.0.2' gem 'addressable', '~> 2.7' gem 'font-awesome-rails', '~> 4.7' diff --git a/Gemfile.lock b/Gemfile.lock index 0a6b37ab9ee..3c4c55c6142 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -452,8 +452,6 @@ GEM rubocop-performance (~> 1.5.2) rubocop-rails (~> 2.5) rubocop-rspec (~> 1.36) - gitlab-terser (1.0.1.1) - execjs (>= 0.3.0, < 3) gitlab_chronic_duration (0.10.6.2) numerizer (~> 0.2) gitlab_omniauth-ldap (2.1.1) @@ -1132,6 +1130,8 @@ GEM temple (0.8.2) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) + terser (1.0.2) + execjs (>= 0.3.0, < 3) test-prof (0.12.0) text (1.3.1) thin (1.7.2) @@ -1333,7 +1333,6 @@ DEPENDENCIES gitlab-puma_worker_killer (~> 0.1.1.gitlab.1) gitlab-sidekiq-fetcher (= 0.5.2) gitlab-styles (~> 4.3.0) - gitlab-terser (= 1.0.1.1) gitlab_chronic_duration (~> 0.10.6.2) gitlab_omniauth-ldap (~> 2.1.1) gon (~> 6.2) @@ -1483,6 +1482,7 @@ DEPENDENCIES stackprof (~> 0.2.15) state_machines-activerecord (~> 0.6.0) sys-filesystem (~> 1.1.6) + terser (= 1.0.2) test-prof (~> 0.12.0) thin (~> 1.7.0) timecop (~> 0.9.1) diff --git a/app/assets/javascripts/behaviors/gl_emoji.js b/app/assets/javascripts/behaviors/gl_emoji.js index bcf732e9522..16373b523b2 100644 --- a/app/assets/javascripts/behaviors/gl_emoji.js +++ b/app/assets/javascripts/behaviors/gl_emoji.js @@ -3,9 +3,7 @@ import isEmojiUnicodeSupported from '../emoji/support'; import { initEmojiMap, getEmojiInfo, emojiFallbackImageSrc, emojiImageTag } from '../emoji'; class GlEmoji extends HTMLElement { - constructor() { - super(); - + connectedCallback() { this.initialize(); } initialize() { diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue index 480c73fda0d..b08b9df13a4 100644 --- a/app/assets/javascripts/diffs/components/diff_file_header.vue +++ b/app/assets/javascripts/diffs/components/diff_file_header.vue @@ -9,7 +9,6 @@ import { GlButtonGroup, GlDropdown, GlDropdownItem, - GlDropdownSectionHeader, GlDropdownDivider, } from '@gitlab/ui'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; @@ -19,6 +18,7 @@ import { __, s__, sprintf } from '~/locale'; import { diffViewerModes } from '~/ide/constants'; import DiffStats from './diff_stats.vue'; import { scrollToElement } from '~/lib/utils/common_utils'; +import { DIFF_FILE_HEADER } from '../i18n'; export default { components: { @@ -30,13 +30,15 @@ export default { GlButtonGroup, GlDropdown, GlDropdownItem, - GlDropdownSectionHeader, GlDropdownDivider, }, directives: { GlTooltip: GlTooltipDirective, SafeHtml: GlSafeHtmlDirective, }, + i18n: { + ...DIFF_FILE_HEADER, + }, props: { discussionPath: { type: String, @@ -290,7 +292,7 @@ export default { icon="external-link" /> - - {{ __('More actions') }} - { const containerEl = document.getElementById(containerID); - return links.map(link => { const path = d3.path(); - // We can only have one unique job name per stage, so our selector - // is: ${stageName}-${jobName} - const sourceId = createUniqueJobId(jobs[link.source].stage, link.source); - const targetId = createUniqueJobId(jobs[link.target].stage, link.target); + const sourceId = jobs[link.source].id; + const targetId = jobs[link.target].id; const sourceNodeEl = document.getElementById(sourceId); const targetNodeEl = document.getElementById(targetId); @@ -80,6 +77,12 @@ export const generateLinksData = ({ links }, jobs, containerID) => { targetNodeY, ); - return { ...link, path: path.toString() }; + return { + ...link, + source: sourceId, + target: targetId, + ref: createUniqueJobId(sourceId, targetId), + path: path.toString(), + }; }); }; diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue index d7197cd0585..8eec0110865 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue @@ -14,6 +14,42 @@ export default { type: String, required: true, }, + isHighlighted: { + type: Boolean, + required: false, + default: false, + }, + isFadedOut: { + type: Boolean, + required: false, + default: false, + }, + handleMouseOver: { + type: Function, + required: false, + default: () => {}, + }, + handleMouseLeave: { + type: Function, + required: false, + default: () => {}, + }, + }, + computed: { + jobPillClasses() { + return [ + { 'gl-opacity-3': this.isFadedOut }, + this.isHighlighted ? 'gl-shadow-blue-200-x0-y0-b4-s2' : 'gl-inset-border-2-green-400', + ]; + }, + }, + methods: { + onMouseEnter() { + this.$emit('on-mouse-enter', this.jobId); + }, + onMouseLeave() { + this.$emit('on-mouse-leave'); + }, }, }; @@ -21,7 +57,10 @@ export default {
{{ jobName }}
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue index 816f65c8478..cbde2afbd94 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue @@ -7,7 +7,7 @@ import StagePill from './stage_pill.vue'; import { generateLinksData } from './drawing_utils'; import { parseData } from '../parsing_utils'; import { DRAW_FAILURE, DEFAULT } from '../../constants'; -import { createUniqueJobId } from '../../utils'; +import { generateJobNeedsDict } from '../../utils'; export default { components: { @@ -31,7 +31,9 @@ export default { data() { return { failureType: null, + highlightedJob: null, links: [], + needsObject: null, height: 0, width: 0, }; @@ -43,6 +45,9 @@ export default { hasError() { return this.failureType; }, + hasHighlightedJob() { + return Boolean(this.highlightedJob); + }, failure() { const text = this.$options.errorTexts[this.failureType] || this.$options.errorTexts[DEFAULT]; @@ -51,8 +56,27 @@ export default { viewBox() { return [0, 0, this.width, this.height]; }, - lineStyle() { - return `stroke-width:${this.$options.STROKE_WIDTH}px;`; + highlightedJobs() { + // If you are hovering on a job, then the jobs we want to highlight are: + // The job you are currently hovering + all of its needs. + return this.hasHighlightedJob + ? [this.highlightedJob, ...this.needsObject[this.highlightedJob]] + : []; + }, + highlightedLinks() { + // If you are hovering on a job, then the links we want to highlight are: + // All the links whose `source` and `target` are highlighted jobs. + if (this.hasHighlightedJob) { + const filteredLinks = this.links.filter(link => { + return ( + this.highlightedJobs.includes(link.source) && this.highlightedJobs.includes(link.target) + ); + }); + + return filteredLinks.map(link => link.ref); + } + + return []; }, }, mounted() { @@ -62,9 +86,6 @@ export default { } }, methods: { - createJobId(stageName, jobName) { - return createUniqueJobId(stageName, jobName); - }, drawJobLinks() { const { stages, jobs } = this.pipelineData; const unwrappedGroups = this.unwrapPipelineData(stages); @@ -76,6 +97,18 @@ export default { this.reportFailure(DRAW_FAILURE); } }, + highlightNeeds(uniqueJobId) { + // The first time we hover, we create the object where + // we store all the data to properly highlight the needs. + if (!this.needsObject) { + this.needsObject = generateJobNeedsDict(this.pipelineData) ?? {}; + } + + this.highlightedJob = uniqueJobId; + }, + removeHighlightNeeds() { + this.highlightedJob = null; + }, unwrapPipelineData(stages) { return stages .map(({ name, groups }) => { @@ -95,6 +128,18 @@ export default { resetFailure() { this.failureType = null; }, + isJobHighlighted(jobName) { + return this.highlightedJobs.includes(jobName); + }, + isLinkHighlighted(linkRef) { + return this.highlightedLinks.includes(linkRef); + }, + getLinkClasses(link) { + return [ + this.isLinkHighlighted(link.ref) ? 'gl-stroke-blue-400' : 'gl-stroke-gray-200', + { 'gl-opacity-3': this.hasHighlightedJob && !this.isLinkHighlighted(link.ref) }, + ]; + }, }, }; @@ -113,13 +158,17 @@ export default { class="gl-display-flex gl-bg-gray-50 gl-px-4 gl-overflow-auto gl-relative gl-py-7" > - +
diff --git a/app/assets/javascripts/pipelines/utils.js b/app/assets/javascripts/pipelines/utils.js index c15e5db55a4..7d1a1762e0d 100644 --- a/app/assets/javascripts/pipelines/utils.js +++ b/app/assets/javascripts/pipelines/utils.js @@ -5,6 +5,8 @@ export const validateParams = params => { return pickBy(params, (val, key) => SUPPORTED_FILTER_PARAMETERS.includes(key) && val); }; +export const createUniqueJobId = (stageName, jobName) => `${stageName}-${jobName}`; + /** * This function takes a json payload that comes from a yml * file converted to json through `jsyaml` library. Because we @@ -21,7 +23,10 @@ export const preparePipelineGraphData = jsonData => { // Creates an object with only the valid jobs const jobs = jsonKeys.reduce((acc, val) => { if (jobNames.includes(val)) { - return { ...acc, [val]: { ...jsonData[val] } }; + return { + ...acc, + [val]: { ...jsonData[val], id: createUniqueJobId(jsonData[val].stage, val) }, + }; } return { ...acc }; }, {}); @@ -47,7 +52,11 @@ export const preparePipelineGraphData = jsonData => { return { name: stage, groups: stageJobs.map(job => { - return { name: job, jobs: [{ ...jsonData[job] }] }; + return { + name: job, + jobs: [{ ...jsonData[job] }], + id: createUniqueJobId(stage, job), + }; }), }; }); @@ -55,4 +64,33 @@ export const preparePipelineGraphData = jsonData => { return { stages: pipelineData, jobs }; }; -export const createUniqueJobId = (stageName, jobName) => `${stageName}-${jobName}`; +export const generateJobNeedsDict = ({ jobs }) => { + const arrOfJobNames = Object.keys(jobs); + + return arrOfJobNames.reduce((acc, value) => { + const recursiveNeeds = jobName => { + if (!jobs[jobName]?.needs) { + return []; + } + + return jobs[jobName].needs + .map(job => { + const { id } = jobs[job]; + // If we already have the needs of a job in the accumulator, + // then we use the memoized data instead of the recursive call + // to save some performance. + const newNeeds = acc[id] ?? recursiveNeeds(job); + + return [id, ...newNeeds]; + }) + .flat(Infinity); + }; + + // To ensure we don't have duplicates job relationship when 2 jobs + // needed by another both depends on the same jobs, we remove any + // duplicates from the array. + const uniqueValues = Array.from(new Set(recursiveNeeds(value))); + + return { ...acc, [jobs[value].id]: uniqueValues }; + }, {}); +}; diff --git a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue index f21456789ac..6a10dc38f2c 100644 --- a/app/assets/javascripts/snippets/components/snippet_blob_edit.vue +++ b/app/assets/javascripts/snippets/components/snippet_blob_edit.vue @@ -1,7 +1,7 @@