diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 12:16:11 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-01-20 12:16:11 +0300 |
commit | edaa33dee2ff2f7ea3fac488d41558eb5f86d68c (patch) | |
tree | 11f143effbfeba52329fb7afbd05e6e2a3790241 /app/assets/javascripts/pipelines | |
parent | d8a5691316400a0f7ec4f83832698f1988eb27c1 (diff) |
Add latest changes from gitlab-org/gitlab@14-7-stable-eev14.7.0-rc42
Diffstat (limited to 'app/assets/javascripts/pipelines')
9 files changed, 45 insertions, 17 deletions
diff --git a/app/assets/javascripts/pipelines/components/header_component.vue b/app/assets/javascripts/pipelines/components/header_component.vue index 4db6a3c9fd8..8088858f381 100644 --- a/app/assets/javascripts/pipelines/components/header_component.vue +++ b/app/assets/javascripts/pipelines/components/header_component.vue @@ -212,7 +212,9 @@ export default { </script> <template> <div class="js-pipeline-header-container"> - <gl-alert v-if="hasError" :variant="failure.variant">{{ failure.text }}</gl-alert> + <gl-alert v-if="hasError" :variant="failure.variant" :dismissible="false">{{ + failure.text + }}</gl-alert> <ci-header v-if="shouldRenderContent" :status="pipeline.detailedStatus" diff --git a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue index ffac8206b58..e11073aee33 100644 --- a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue +++ b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue @@ -112,7 +112,7 @@ export default { </gl-skeleton-loader> </div> - <jobs-table v-else :jobs="jobs" :table-fields="$options.fields" /> + <jobs-table v-else :jobs="jobs" :table-fields="$options.fields" data-testid="jobs-tab-table" /> <gl-intersection-observer v-if="jobsPageInfo.hasNextPage" @appear="fetchMoreJobs"> <gl-loading-icon v-if="$apollo.loading" size="md" /> diff --git a/app/assets/javascripts/pipelines/components/parsing_utils.js b/app/assets/javascripts/pipelines/components/parsing_utils.js index fa7330ce890..cae4e11c13f 100644 --- a/app/assets/javascripts/pipelines/components/parsing_utils.js +++ b/app/assets/javascripts/pipelines/components/parsing_utils.js @@ -1,5 +1,6 @@ import { memoize } from 'lodash'; import { createNodeDict } from '../utils'; +import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants'; import { createSankey } from './dag/drawing_utils'; /* @@ -15,12 +16,14 @@ const deduplicate = (item, itemIndex, arr) => { return foundIdx === itemIndex; }; -export const makeLinksFromNodes = (nodes, nodeDict) => { +export const makeLinksFromNodes = (nodes, nodeDict, { needsKey = NEEDS_PROPERTY } = {}) => { const constantLinkValue = 10; // all links are the same weight return nodes .map(({ jobs, name: groupName }) => - jobs.map(({ needs = [] }) => - needs.reduce((acc, needed) => { + jobs.map((job) => { + const needs = job[needsKey] || []; + + return needs.reduce((acc, needed) => { // It's possible that we have an optional job, which // is being needed by another job. In that scenario, // the needed job doesn't exist, so we don't want to @@ -34,8 +37,8 @@ export const makeLinksFromNodes = (nodes, nodeDict) => { } return acc; - }, []), - ), + }, []); + }), ) .flat(2); }; @@ -76,9 +79,9 @@ export const filterByAncestors = (links, nodeDict) => return !allAncestors.includes(source); }); -export const parseData = (nodes) => { - const nodeDict = createNodeDict(nodes); - const allLinks = makeLinksFromNodes(nodes, nodeDict); +export const parseData = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => { + const nodeDict = createNodeDict(nodes, { needsKey }); + const allLinks = makeLinksFromNodes(nodes, nodeDict, { needsKey }); const filteredLinks = allLinks.filter(deduplicate); const links = filterByAncestors(filteredLinks, nodeDict); @@ -123,7 +126,8 @@ export const removeOrphanNodes = (sankeyfiedNodes) => { export const listByLayers = ({ stages }) => { const arrayOfJobs = stages.flatMap(({ groups }) => groups); const parsedData = parseData(arrayOfJobs); - const dataWithLayers = createSankey()(parsedData); + const explicitParsedData = parseData(arrayOfJobs, { needsKey: EXPLICIT_NEEDS_PROPERTY }); + const dataWithLayers = createSankey()(explicitParsedData); const pipelineLayers = dataWithLayers.nodes.reduce((acc, { layer, name }) => { /* sort groups by layer */ 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 64210576b29..8daf85e2b2e 100644 --- a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue +++ b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue @@ -132,6 +132,7 @@ export default { :ref="$options.CONTAINER_REF" class="gl-bg-gray-10 gl-overflow-auto" data-testid="graph-container" + data-qa-selector="pipeline_graph_container" > <links-layer :pipeline-data="pipelineStages" @@ -147,7 +148,10 @@ export default { :key="`${stage.name}-${index}`" class="gl-flex-direction-column" > - <div class="gl-display-flex gl-align-items-center gl-w-full gl-px-9 gl-py-4 gl-mb-5"> + <div + class="gl-display-flex gl-align-items-center gl-w-full gl-px-9 gl-py-4 gl-mb-5" + data-qa-selector="stage_container" + > <stage-name :stage-name="stage.name" /> </div> <div :class="$options.jobWrapperClasses"> @@ -158,6 +162,7 @@ export default { :pipeline-id="$options.PIPELINE_ID" :is-hovered="highlightedJob === group.name" :is-faded-out="isFadedOut(group.name)" + data-qa-selector="job_container" @on-mouse-enter="setHoveredJob" @on-mouse-leave="removeHoveredJob" /> diff --git a/app/assets/javascripts/pipelines/components/unwrapping_utils.js b/app/assets/javascripts/pipelines/components/unwrapping_utils.js index 2d24beb8323..d42a11c3aba 100644 --- a/app/assets/javascripts/pipelines/components/unwrapping_utils.js +++ b/app/assets/javascripts/pipelines/components/unwrapping_utils.js @@ -1,4 +1,5 @@ import { reportToSentry } from '../utils'; +import { EXPLICIT_NEEDS_PROPERTY, NEEDS_PROPERTY } from '../constants'; const unwrapGroups = (stages) => { return stages.map((stage, idx) => { @@ -27,12 +28,16 @@ const unwrapNodesWithName = (jobArray, prop, field = 'name') => { } return jobArray.map((job) => { - return { ...job, [prop]: job[prop].nodes.map((item) => item[field] || '') }; + if (job[prop]) { + return { ...job, [prop]: job[prop].nodes.map((item) => item[field] || '') }; + } + return job; }); }; const unwrapJobWithNeeds = (denodedJobArray) => { - return unwrapNodesWithName(denodedJobArray, 'needs'); + const explicitNeedsUnwrapped = unwrapNodesWithName(denodedJobArray, EXPLICIT_NEEDS_PROPERTY); + return unwrapNodesWithName(explicitNeedsUnwrapped, NEEDS_PROPERTY); }; const unwrapStagesWithNeedsAndLookup = (denodedStages) => { diff --git a/app/assets/javascripts/pipelines/constants.js b/app/assets/javascripts/pipelines/constants.js index d123f7a203c..410fc7b82cd 100644 --- a/app/assets/javascripts/pipelines/constants.js +++ b/app/assets/javascripts/pipelines/constants.js @@ -7,6 +7,8 @@ export const ANY_TRIGGER_AUTHOR = 'Any'; export const SUPPORTED_FILTER_PARAMETERS = ['username', 'ref', 'status', 'source']; export const FILTER_TAG_IDENTIFIER = 'tag'; export const SCHEDULE_ORIGIN = 'schedule'; +export const NEEDS_PROPERTY = 'needs'; +export const EXPLICIT_NEEDS_PROPERTY = 'previousStageJobsOrNeeds'; export const TestStatus = { FAILED: 'failed', diff --git a/app/assets/javascripts/pipelines/graphql/fragmentTypes.json b/app/assets/javascripts/pipelines/graphql/fragmentTypes.json new file mode 100644 index 00000000000..4601b74b5c1 --- /dev/null +++ b/app/assets/javascripts/pipelines/graphql/fragmentTypes.json @@ -0,0 +1 @@ +{"__schema":{"types":[{"kind":"UNION","name":"JobNeedUnion","possibleTypes":[{"name":"CiBuildNeed"},{"name":"CiJob"}]}]}}
\ No newline at end of file diff --git a/app/assets/javascripts/pipelines/pipeline_shared_client.js b/app/assets/javascripts/pipelines/pipeline_shared_client.js index c3be487caae..84276588d6a 100644 --- a/app/assets/javascripts/pipelines/pipeline_shared_client.js +++ b/app/assets/javascripts/pipelines/pipeline_shared_client.js @@ -1,10 +1,19 @@ import VueApollo from 'vue-apollo'; +import { IntrospectionFragmentMatcher } from 'apollo-cache-inmemory'; import createDefaultClient from '~/lib/graphql'; +import introspectionQueryResultData from './graphql/fragmentTypes.json'; + +export const fragmentMatcher = new IntrospectionFragmentMatcher({ + introspectionQueryResultData, +}); export const apolloProvider = new VueApollo({ defaultClient: createDefaultClient( {}, { + cacheConfig: { + fragmentMatcher, + }, useGet: true, }, ), diff --git a/app/assets/javascripts/pipelines/utils.js b/app/assets/javascripts/pipelines/utils.js index e28eb74fb1b..f6e1c8b7412 100644 --- a/app/assets/javascripts/pipelines/utils.js +++ b/app/assets/javascripts/pipelines/utils.js @@ -1,6 +1,6 @@ import * as Sentry from '@sentry/browser'; import { pickBy } from 'lodash'; -import { SUPPORTED_FILTER_PARAMETERS } from './constants'; +import { SUPPORTED_FILTER_PARAMETERS, NEEDS_PROPERTY } from './constants'; /* The following functions are the main engine in transforming the data as @@ -35,11 +35,11 @@ import { SUPPORTED_FILTER_PARAMETERS } from './constants'; 10 -> value (constant) */ -export const createNodeDict = (nodes) => { +export const createNodeDict = (nodes, { needsKey = NEEDS_PROPERTY } = {}) => { return nodes.reduce((acc, node) => { const newNode = { ...node, - needs: node.jobs.map((job) => job.needs || []).flat(), + needs: node.jobs.map((job) => job[needsKey] || []).flat(), }; if (node.size > 1) { |