Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-12-20 16:37:47 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-20 16:37:47 +0300
commitaee0a117a889461ce8ced6fcf73207fe017f1d99 (patch)
tree891d9ef189227a8445d83f35c1b0fc99573f4380 /app/assets/javascripts/pipelines
parent8d46af3258650d305f53b819eabf7ab18d22f59e (diff)
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'app/assets/javascripts/pipelines')
-rw-r--r--app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue39
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/graph/job_item.vue8
-rw-r--r--app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue8
-rw-r--r--app/assets/javascripts/pipelines/components/jobs/jobs_app.vue121
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue8
-rw-r--r--app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql5
-rw-r--r--app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql2
-rw-r--r--app/assets/javascripts/pipelines/graphql/queries/get_pipeline_jobs.query.graphql70
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_bundle.js12
-rw-r--r--app/assets/javascripts/pipelines/pipeline_details_jobs.js34
14 files changed, 287 insertions, 28 deletions
diff --git a/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue b/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue
index 3c78b655dc7..1920fed84ec 100644
--- a/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue
+++ b/app/assets/javascripts/pipelines/components/graph/graph_view_selector.vue
@@ -1,5 +1,5 @@
<script>
-import { GlAlert, GlLoadingIcon, GlSegmentedControl, GlToggle } from '@gitlab/ui';
+import { GlAlert, GlButton, GlButtonGroup, GlLoadingIcon, GlToggle } from '@gitlab/ui';
import { __, s__ } from '~/locale';
import { STAGE_VIEW, LAYER_VIEW } from './constants';
@@ -7,8 +7,9 @@ export default {
name: 'GraphViewSelector',
components: {
GlAlert,
+ GlButton,
+ GlButtonGroup,
GlLoadingIcon,
- GlSegmentedControl,
GlToggle,
},
props: {
@@ -96,6 +97,9 @@ export default {
this.hoverTipDismissed = true;
this.$emit('dismissHoverTip');
},
+ isCurrentType(type) {
+ return this.segmentSelectedType === type;
+ },
/*
In both toggle methods, we use setTimeout so that the loading indicator displays,
then the work is done to update the DOM. The process is:
@@ -110,11 +114,14 @@ export default {
See https://www.hesselinkwebdesign.nl/2019/nexttick-vs-settimeout-in-vue/ for more details.
*/
- toggleView(type) {
- this.isSwitcherLoading = true;
- setTimeout(() => {
- this.$emit('updateViewType', type);
- });
+ setViewType(type) {
+ if (!this.isCurrentType(type)) {
+ this.isSwitcherLoading = true;
+ this.segmentSelectedType = type;
+ setTimeout(() => {
+ this.$emit('updateViewType', type);
+ });
+ }
},
toggleShowLinksActive(val) {
this.isToggleLoading = true;
@@ -136,14 +143,16 @@ export default {
size="lg"
/>
<span class="gl-font-weight-bold">{{ $options.i18n.viewLabelText }}</span>
- <gl-segmented-control
- v-model="segmentSelectedType"
- :options="viewTypesList"
- :disabled="isSwitcherLoading"
- data-testid="pipeline-view-selector"
- class="gl-mx-4"
- @input="toggleView"
- />
+ <gl-button-group class="gl-mx-4">
+ <gl-button
+ v-for="viewType in viewTypesList"
+ :key="viewType.value"
+ :selected="isCurrentType(viewType.value)"
+ @click="setViewType(viewType.value)"
+ >
+ {{ viewType.text }}
+ </gl-button>
+ </gl-button-group>
<div v-if="showLinksToggle" class="gl-display-flex gl-align-items-center">
<gl-toggle
diff --git a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
index 6f4360649ff..12c3f9a7f40 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_group_dropdown.vue
@@ -67,7 +67,7 @@ export default {
:class="cssClassJobName"
class="dropdown-menu-toggle gl-pipeline-job-width! gl-pr-4!"
>
- <div class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
+ <div class="gl-display-flex gl-align-items-stretch gl-justify-content-space-between">
<job-item
:type="$options.jobItemTypes.jobDropdown"
:group-tooltip="tooltipText"
diff --git a/app/assets/javascripts/pipelines/components/graph/job_item.vue b/app/assets/javascripts/pipelines/components/graph/job_item.vue
index 0216b2717ed..ee58dcc4882 100644
--- a/app/assets/javascripts/pipelines/components/graph/job_item.vue
+++ b/app/assets/javascripts/pipelines/components/graph/job_item.vue
@@ -203,7 +203,7 @@ export default {
<template>
<div
:id="computedJobId"
- class="ci-job-component gl-display-flex gl-align-items-center gl-justify-content-space-between gl-w-full"
+ class="ci-job-component gl-display-flex gl-justify-content-space-between gl-pipeline-job-width"
data-qa-selector="job_item_container"
>
<component
@@ -223,12 +223,12 @@ export default {
>
<div class="ci-job-name-component gl-display-flex gl-align-items-center">
<ci-icon :size="24" :status="job.status" class="gl-line-height-0" />
- <div class="gl-pl-3 gl-display-flex gl-flex-direction-column gl-w-full">
- <div class="gl-text-truncate gl-w-70p gl-line-height-normal">{{ job.name }}</div>
+ <div class="gl-pl-3 gl-pr-3 gl-display-flex gl-flex-direction-column gl-pipeline-job-width">
+ <div class="gl-text-truncate gl-pr-9 gl-line-height-normal">{{ job.name }}</div>
<div
v-if="showStageName"
data-testid="stage-name-in-job"
- class="gl-text-truncate gl-w-70p gl-font-sm gl-text-gray-500 gl-line-height-normal"
+ class="gl-text-truncate gl-pr-9 gl-font-sm gl-text-gray-500 gl-line-height-normal"
>
{{ stageName }}
</div>
diff --git a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
index be47799868b..e0c1dcc5be5 100644
--- a/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
+++ b/app/assets/javascripts/pipelines/components/graph/linked_pipeline.vue
@@ -124,7 +124,7 @@ export default {
<div
ref="linkedPipeline"
v-gl-tooltip
- class="gl-pipeline-job-width"
+ class="gl-downstream-pipeline-job-width"
:title="tooltipText"
data-qa-selector="child_pipeline"
@mouseover="onDownstreamHovered"
@@ -134,7 +134,7 @@ export default {
class="gl-relative gl-bg-white gl-p-3 gl-border-solid gl-border-gray-100 gl-border-1"
:class="{ 'gl-pl-9': isUpstream }"
>
- <div class="gl-display-flex">
+ <div class="gl-display-flex gl-pr-7 gl-pipeline-job-width">
<ci-status
v-if="!pipelineIsLoading"
:status="pipelineStatus"
@@ -142,7 +142,9 @@ export default {
css-classes="gl-top-0 gl-pr-2"
/>
<div v-else class="gl-pr-2"><gl-loading-icon size="sm" inline /></div>
- <div class="gl-display-flex gl-flex-direction-column gl-w-13">
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-pipeline-job-width gl-text-truncate"
+ >
<span class="gl-text-truncate" data-testid="downstream-title">
{{ downstreamTitle }}
</span>
diff --git a/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
new file mode 100644
index 00000000000..ffac8206b58
--- /dev/null
+++ b/app/assets/javascripts/pipelines/components/jobs/jobs_app.vue
@@ -0,0 +1,121 @@
+<script>
+import { GlIntersectionObserver, GlLoadingIcon, GlSkeletonLoader } from '@gitlab/ui';
+import produce from 'immer';
+import createFlash from '~/flash';
+import { __ } from '~/locale';
+import eventHub from '~/jobs/components/table/event_hub';
+import JobsTable from '~/jobs/components/table/jobs_table.vue';
+import { JOBS_TAB_FIELDS } from '~/jobs/components/table/constants';
+import getPipelineJobs from '../../graphql/queries/get_pipeline_jobs.query.graphql';
+
+export default {
+ fields: JOBS_TAB_FIELDS,
+ components: {
+ GlIntersectionObserver,
+ GlLoadingIcon,
+ GlSkeletonLoader,
+ JobsTable,
+ },
+ inject: {
+ fullPath: {
+ default: '',
+ },
+ pipelineIid: {
+ default: '',
+ },
+ },
+ apollo: {
+ jobs: {
+ query: getPipelineJobs,
+ variables() {
+ return {
+ ...this.queryVariables,
+ };
+ },
+ update(data) {
+ return data.project?.pipeline?.jobs?.nodes || [];
+ },
+ result({ data }) {
+ this.jobsPageInfo = data.project?.pipeline?.jobs?.pageInfo || {};
+ },
+ error() {
+ createFlash({ message: __('An error occured while fetching the pipelines jobs.') });
+ },
+ },
+ },
+ data() {
+ return {
+ jobs: [],
+ jobsPageInfo: {},
+ firstLoad: true,
+ };
+ },
+ computed: {
+ queryVariables() {
+ return {
+ fullPath: this.fullPath,
+ iid: this.pipelineIid,
+ };
+ },
+ },
+ mounted() {
+ eventHub.$on('jobActionPerformed', this.handleJobAction);
+ },
+ beforeDestroy() {
+ eventHub.$off('jobActionPerformed', this.handleJobAction);
+ },
+ methods: {
+ handleJobAction() {
+ this.firstLoad = true;
+
+ this.$apollo.queries.jobs.refetch();
+ },
+ fetchMoreJobs() {
+ this.firstLoad = false;
+
+ this.$apollo.queries.jobs.fetchMore({
+ variables: {
+ ...this.queryVariables,
+ after: this.jobsPageInfo.endCursor,
+ },
+ updateQuery: (previousResult, { fetchMoreResult }) => {
+ const results = produce(fetchMoreResult, (draftData) => {
+ draftData.project.pipeline.jobs.nodes = [
+ ...previousResult.project.pipeline.jobs.nodes,
+ ...draftData.project.pipeline.jobs.nodes,
+ ];
+ });
+ return results;
+ },
+ });
+ },
+ },
+};
+</script>
+
+<template>
+ <div>
+ <div v-if="$apollo.loading && firstLoad" class="gl-mt-5">
+ <gl-skeleton-loader :width="1248" :height="73">
+ <circle cx="748.031" cy="37.7193" r="15.0307" />
+ <circle cx="787.241" cy="37.7193" r="15.0307" />
+ <circle cx="827.759" cy="37.7193" r="15.0307" />
+ <circle cx="866.969" cy="37.7193" r="15.0307" />
+ <circle cx="380" cy="37" r="18" />
+ <rect x="432" y="19" width="126.587" height="15" />
+ <rect x="432" y="41" width="247" height="15" />
+ <rect x="158" y="19" width="86.1" height="15" />
+ <rect x="158" y="41" width="168" height="15" />
+ <rect x="22" y="19" width="96" height="36" />
+ <rect x="924" y="30" width="96" height="15" />
+ <rect x="1057" y="20" width="166" height="35" />
+ </gl-skeleton-loader>
+ </div>
+
+ <jobs-table v-else :jobs="jobs" :table-fields="$options.fields" />
+
+ <gl-intersection-observer v-if="jobsPageInfo.hasNextPage" @appear="fetchMoreJobs">
+ <gl-loading-icon v-if="$apollo.loading" size="md" />
+ </gl-intersection-observer>
+ </div>
+</template>
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 836333c8bde..793e343a02a 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_graph/job_pill.vue
@@ -1,5 +1,5 @@
<script>
-import tooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import tooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
export default {
components: {
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 78771b6a072..64210576b29 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_graph/pipeline_graph.vue
@@ -25,7 +25,7 @@ export default {
// The max width and the width make sure the ellipsis to work and the min width
// is for when there is less text than the stage column width (which the width 100% does not fix)
jobWrapperClasses:
- 'gl-display-flex gl-flex-direction-column gl-align-items-center gl-w-full gl-px-8 gl-min-w-full gl-max-w-15',
+ 'gl-display-flex gl-flex-direction-column gl-align-items-stretch gl-w-full gl-px-8 gl-min-w-full gl-max-w-15',
props: {
pipelineData: {
required: true,
diff --git a/app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue b/app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue
index 367a18af248..e485b38ce11 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_graph/stage_name.vue
@@ -1,6 +1,6 @@
<script>
import { capitalize, escape } from 'lodash';
-import tooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import tooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
export default {
components: {
diff --git a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue
index 7552ddb61dc..afcb04cd7eb 100644
--- a/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue
+++ b/app/assets/javascripts/pipelines/components/pipelines_list/pipeline_stage.vue
@@ -15,7 +15,7 @@
import { GlDropdown, GlLoadingIcon, GlTooltipDirective, GlIcon } from '@gitlab/ui';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
-import { __ } from '~/locale';
+import { __, sprintf } from '~/locale';
import eventHub from '../../event_hub';
import JobItem from './job_item.vue';
@@ -98,6 +98,9 @@ export default {
// warn the pipelines table to update
this.$emit('pipelineActionRequestComplete');
},
+ stageAriaLabel(title) {
+ return sprintf(__('View Stage: %{title}'), { title });
+ },
},
};
</script>
@@ -106,9 +109,10 @@ export default {
<gl-dropdown
ref="dropdown"
v-gl-tooltip.hover.ds0
+ v-gl-tooltip="stage.title"
data-testid="mini-pipeline-graph-dropdown"
- :title="stage.title"
variant="link"
+ :aria-label="stageAriaLabel(stage.title)"
:lazy="true"
:popper-opts="{ placement: 'bottom' }"
:toggle-class="['mini-pipeline-graph-dropdown-toggle', triggerButtonClass]"
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql
index 887c217da41..2a0b13dd0cc 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql
+++ b/app/assets/javascripts/pipelines/graphql/queries/get_dag_vis_data.query.graphql
@@ -1,19 +1,24 @@
query getDagVisData($projectPath: ID!, $iid: ID!) {
project(fullPath: $projectPath) {
+ id
pipeline(iid: $iid) {
id
stages {
nodes {
+ id
name
groups {
nodes {
+ id
name
size
jobs {
nodes {
+ id
name
needs {
nodes {
+ id
name
}
}
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
index 8fcae9dbad8..47bc167ca52 100644
--- a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
+++ b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_header_data.query.graphql
@@ -1,5 +1,6 @@
query getPipelineHeaderData($fullPath: ID!, $iid: ID!) {
project(fullPath: $fullPath) {
+ id
pipeline(iid: $iid) {
id
iid
@@ -11,6 +12,7 @@ query getPipelineHeaderData($fullPath: ID!, $iid: ID!) {
updatePipeline
}
detailedStatus {
+ id
detailsPath
icon
group
diff --git a/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_jobs.query.graphql b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_jobs.query.graphql
new file mode 100644
index 00000000000..5fe47e09d9c
--- /dev/null
+++ b/app/assets/javascripts/pipelines/graphql/queries/get_pipeline_jobs.query.graphql
@@ -0,0 +1,70 @@
+#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
+
+query getPipelineJobs($fullPath: ID!, $iid: ID!, $after: String) {
+ project(fullPath: $fullPath) {
+ id
+ pipeline(iid: $iid) {
+ id
+ jobs(after: $after, first: 20) {
+ pageInfo {
+ ...PageInfo
+ }
+ nodes {
+ artifacts {
+ nodes {
+ downloadPath
+ fileType
+ }
+ }
+ allowFailure
+ status
+ scheduledAt
+ manualJob
+ triggered
+ createdByTag
+ detailedStatus {
+ id
+ detailsPath
+ group
+ icon
+ label
+ text
+ tooltip
+ action {
+ id
+ buttonTitle
+ icon
+ method
+ path
+ title
+ }
+ }
+ id
+ refName
+ refPath
+ tags
+ shortSha
+ commitPath
+ stage {
+ id
+ name
+ }
+ name
+ duration
+ finishedAt
+ coverage
+ retryable
+ playable
+ cancelable
+ active
+ stuck
+ userPermissions {
+ readBuild
+ readJobArtifacts
+ updateBuild
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/pipelines/pipeline_details_bundle.js b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
index ee9560e36c4..ae8b2503c79 100644
--- a/app/assets/javascripts/pipelines/pipeline_details_bundle.js
+++ b/app/assets/javascripts/pipelines/pipeline_details_bundle.js
@@ -3,6 +3,7 @@ import { __ } from '~/locale';
import createDagApp from './pipeline_details_dag';
import { createPipelinesDetailApp } from './pipeline_details_graph';
import { createPipelineHeaderApp } from './pipeline_details_header';
+import { createPipelineJobsApp } from './pipeline_details_jobs';
import { apolloProvider } from './pipeline_shared_client';
import { createTestDetails } from './pipeline_test_details';
@@ -11,6 +12,7 @@ const SELECTORS = {
PIPELINE_GRAPH: '#js-pipeline-graph-vue',
PIPELINE_HEADER: '#js-pipeline-header-vue',
PIPELINE_TESTS: '#js-pipeline-tests-detail',
+ PIPELINE_JOBS: '#js-pipeline-jobs-vue',
};
export default async function initPipelineDetailsBundle() {
@@ -55,4 +57,14 @@ export default async function initPipelineDetailsBundle() {
message: __('An error occurred while loading the Test Reports tab.'),
});
}
+
+ try {
+ if (gon.features?.jobsTabVue) {
+ createPipelineJobsApp(SELECTORS.PIPELINE_JOBS);
+ }
+ } catch {
+ createFlash({
+ message: __('An error occurred while loading the Jobs tab.'),
+ });
+ }
}
diff --git a/app/assets/javascripts/pipelines/pipeline_details_jobs.js b/app/assets/javascripts/pipelines/pipeline_details_jobs.js
new file mode 100644
index 00000000000..a1294a484f0
--- /dev/null
+++ b/app/assets/javascripts/pipelines/pipeline_details_jobs.js
@@ -0,0 +1,34 @@
+import { GlToast } from '@gitlab/ui';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createDefaultClient from '~/lib/graphql';
+import JobsApp from './components/jobs/jobs_app.vue';
+
+Vue.use(VueApollo);
+Vue.use(GlToast);
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient(),
+});
+
+export const createPipelineJobsApp = (selector) => {
+ const containerEl = document.querySelector(selector);
+
+ if (!containerEl) {
+ return false;
+ }
+
+ const { fullPath, pipelineIid } = containerEl.dataset;
+
+ return new Vue({
+ el: containerEl,
+ apolloProvider,
+ provide: {
+ fullPath,
+ pipelineIid,
+ },
+ render(createElement) {
+ return createElement(JobsApp);
+ },
+ });
+};