Commit f120ef9e authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '298973-refactor-job-pills' into 'master'

JobItem Refactor

See merge request gitlab-org/gitlab!57394
parents 4400cf8d 4c69af59
<script> <script>
import { reportToSentry } from '../../utils';
import LinkedGraphWrapper from '../graph_shared/linked_graph_wrapper.vue'; import LinkedGraphWrapper from '../graph_shared/linked_graph_wrapper.vue';
import LinksLayer from '../graph_shared/links_layer.vue'; import LinksLayer from '../graph_shared/links_layer.vue';
import { DOWNSTREAM, MAIN, UPSTREAM, ONE_COL_WIDTH } from './constants'; import { DOWNSTREAM, MAIN, UPSTREAM, ONE_COL_WIDTH } from './constants';
import LinkedPipelinesColumn from './linked_pipelines_column.vue'; import LinkedPipelinesColumn from './linked_pipelines_column.vue';
import StageColumnComponent from './stage_column_component.vue'; import StageColumnComponent from './stage_column_component.vue';
import { reportToSentry, validateConfigPaths } from './utils'; import { validateConfigPaths } from './utils';
export default { export default {
name: 'PipelineGraph', name: 'PipelineGraph',
......
...@@ -2,10 +2,10 @@ ...@@ -2,10 +2,10 @@
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { escape, capitalize } from 'lodash'; import { escape, capitalize } from 'lodash';
import GraphBundleMixin from '../../mixins/graph_pipeline_bundle_mixin'; import GraphBundleMixin from '../../mixins/graph_pipeline_bundle_mixin';
import { reportToSentry } from '../../utils';
import { UPSTREAM, DOWNSTREAM, MAIN } from './constants'; import { UPSTREAM, DOWNSTREAM, MAIN } from './constants';
import LinkedPipelinesColumnLegacy from './linked_pipelines_column_legacy.vue'; import LinkedPipelinesColumnLegacy from './linked_pipelines_column_legacy.vue';
import StageColumnComponentLegacy from './stage_column_component_legacy.vue'; import StageColumnComponentLegacy from './stage_column_component_legacy.vue';
import { reportToSentry } from './utils';
export default { export default {
name: 'PipelineGraphLegacy', name: 'PipelineGraphLegacy',
......
...@@ -4,12 +4,12 @@ import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.qu ...@@ -4,12 +4,12 @@ import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.qu
import { __ } from '~/locale'; import { __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants'; import { DEFAULT, DRAW_FAILURE, LOAD_FAILURE } from '../../constants';
import { reportToSentry } from '../../utils';
import { IID_FAILURE, STAGE_VIEW } from './constants'; import { IID_FAILURE, STAGE_VIEW } from './constants';
import PipelineGraph from './graph_component.vue'; import PipelineGraph from './graph_component.vue';
import GraphViewSelector from './graph_view_selector.vue'; import GraphViewSelector from './graph_view_selector.vue';
import { import {
getQueryHeaders, getQueryHeaders,
reportToSentry,
serializeLoadErrors, serializeLoadErrors,
toggleQueryPollingByVisibility, toggleQueryPollingByVisibility,
unwrapPipelineData, unwrapPipelineData,
......
<script> <script>
import { GlTooltipDirective } from '@gitlab/ui'; import { GlTooltipDirective } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue'; import CiIcon from '~/vue_shared/components/ci_icon.vue';
import { reportToSentry } from '../../utils';
import JobItem from './job_item.vue'; import JobItem from './job_item.vue';
import { reportToSentry } from './utils';
/** /**
* Renders the dropdown for the pipeline graph. * Renders the dropdown for the pipeline graph.
......
...@@ -3,11 +3,11 @@ import { GlTooltipDirective, GlLink } from '@gitlab/ui'; ...@@ -3,11 +3,11 @@ import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin'; import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { sprintf } from '~/locale'; import { sprintf } from '~/locale';
import { reportToSentry } from '../../utils';
import ActionComponent from '../jobs_shared/action_component.vue';
import JobNameComponent from '../jobs_shared/job_name_component.vue';
import { accessValue } from './accessors'; import { accessValue } from './accessors';
import ActionComponent from './action_component.vue';
import { REST } from './constants'; import { REST } from './constants';
import JobNameComponent from './job_name_component.vue';
import { reportToSentry } from './utils';
/** /**
* Renders the badge for the pipeline graph and the job's dropdown. * Renders the badge for the pipeline graph and the job's dropdown.
......
...@@ -3,9 +3,9 @@ import { GlTooltipDirective, GlButton, GlLink, GlLoadingIcon, GlBadge } from '@g ...@@ -3,9 +3,9 @@ import { GlTooltipDirective, GlButton, GlLink, GlLoadingIcon, GlBadge } from '@g
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
import CiStatus from '~/vue_shared/components/ci_icon.vue'; import CiStatus from '~/vue_shared/components/ci_icon.vue';
import { reportToSentry } from '../../utils';
import { accessValue } from './accessors'; import { accessValue } from './accessors';
import { DOWNSTREAM, REST, UPSTREAM } from './constants'; import { DOWNSTREAM, REST, UPSTREAM } from './constants';
import { reportToSentry } from './utils';
export default { export default {
directives: { directives: {
......
<script> <script>
import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql'; import getPipelineDetails from 'shared_queries/pipelines/get_pipeline_details.query.graphql';
import { LOAD_FAILURE } from '../../constants'; import { LOAD_FAILURE } from '../../constants';
import { reportToSentry } from '../../utils';
import { ONE_COL_WIDTH, UPSTREAM } from './constants'; import { ONE_COL_WIDTH, UPSTREAM } from './constants';
import LinkedPipeline from './linked_pipeline.vue'; import LinkedPipeline from './linked_pipeline.vue';
import { import {
getQueryHeaders, getQueryHeaders,
reportToSentry,
serializeLoadErrors, serializeLoadErrors,
toggleQueryPollingByVisibility, toggleQueryPollingByVisibility,
unwrapPipelineData, unwrapPipelineData,
......
<script> <script>
import { reportToSentry } from '../../utils';
import { UPSTREAM } from './constants'; import { UPSTREAM } from './constants';
import LinkedPipeline from './linked_pipeline.vue'; import LinkedPipeline from './linked_pipeline.vue';
import { reportToSentry } from './utils';
export default { export default {
components: { components: {
......
<script> <script>
import { capitalize, escape, isEmpty } from 'lodash'; import { capitalize, escape, isEmpty } from 'lodash';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { reportToSentry } from '../../utils';
import MainGraphWrapper from '../graph_shared/main_graph_wrapper.vue'; import MainGraphWrapper from '../graph_shared/main_graph_wrapper.vue';
import ActionComponent from '../jobs_shared/action_component.vue';
import { accessValue } from './accessors'; import { accessValue } from './accessors';
import ActionComponent from './action_component.vue';
import { GRAPHQL } from './constants'; import { GRAPHQL } from './constants';
import JobGroupDropdown from './job_group_dropdown.vue'; import JobGroupDropdown from './job_group_dropdown.vue';
import JobItem from './job_item.vue'; import JobItem from './job_item.vue';
import { reportToSentry } from './utils';
export default { export default {
components: { components: {
......
<script> <script>
import { isEmpty, escape } from 'lodash'; import { isEmpty, escape } from 'lodash';
import stageColumnMixin from '../../mixins/stage_column_mixin'; import stageColumnMixin from '../../mixins/stage_column_mixin';
import ActionComponent from './action_component.vue'; import { reportToSentry } from '../../utils';
import ActionComponent from '../jobs_shared/action_component.vue';
import JobGroupDropdown from './job_group_dropdown.vue'; import JobGroupDropdown from './job_group_dropdown.vue';
import JobItem from './job_item.vue'; import JobItem from './job_item.vue';
import { reportToSentry } from './utils';
export default { export default {
components: { components: {
......
import * as Sentry from '@sentry/browser';
import Visibility from 'visibilityjs'; import Visibility from 'visibilityjs';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { unwrapStagesWithNeeds } from '../unwrapping_utils'; import { unwrapStagesWithNeeds } from '../unwrapping_utils';
...@@ -24,13 +23,6 @@ const getQueryHeaders = (etagResource) => { ...@@ -24,13 +23,6 @@ const getQueryHeaders = (etagResource) => {
}; };
}; };
const reportToSentry = (component, failureType) => {
Sentry.withScope((scope) => {
scope.setTag('component', component);
Sentry.captureException(failureType);
});
};
const serializeGqlErr = (gqlError) => { const serializeGqlErr = (gqlError) => {
const { locations = [], message = '', path = [] } = gqlError; const { locations = [], message = '', path = [] } = gqlError;
...@@ -113,7 +105,6 @@ const validateConfigPaths = (value) => value.graphqlResourceEtag?.length > 0; ...@@ -113,7 +105,6 @@ const validateConfigPaths = (value) => value.graphqlResourceEtag?.length > 0;
export { export {
getQueryHeaders, getQueryHeaders,
reportToSentry,
serializeGqlErr, serializeGqlErr,
serializeLoadErrors, serializeLoadErrors,
toggleQueryPollingByVisibility, toggleQueryPollingByVisibility,
......
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { reportToSentry } from '../graph/utils'; import { reportToSentry } from '../../utils';
export const reportPerformance = (path, stats) => { export const reportPerformance = (path, stats) => {
axios.post(path, stats).catch((err) => { axios.post(path, stats).catch((err) => {
......
...@@ -10,8 +10,7 @@ import { ...@@ -10,8 +10,7 @@ import {
} from '~/performance/constants'; } from '~/performance/constants';
import { performanceMarkAndMeasure } from '~/performance/utils'; import { performanceMarkAndMeasure } from '~/performance/utils';
import { DRAW_FAILURE } from '../../constants'; import { DRAW_FAILURE } from '../../constants';
import { createJobsHash, generateJobNeedsDict } from '../../utils'; import { createJobsHash, generateJobNeedsDict, reportToSentry } from '../../utils';
import { reportToSentry } from '../graph/utils';
import { parseData } from '../parsing_utils'; import { parseData } from '../parsing_utils';
import { reportPerformance } from './api'; import { reportPerformance } from './api';
import { generateLinksData } from './drawing_utils'; import { generateLinksData } from './drawing_utils';
......
...@@ -11,7 +11,7 @@ import { ...@@ -11,7 +11,7 @@ import {
PIPELINES_DETAIL_LINKS_JOB_RATIO, PIPELINES_DETAIL_LINKS_JOB_RATIO,
} from '~/performance/constants'; } from '~/performance/constants';
import { performanceMarkAndMeasure } from '~/performance/utils'; import { performanceMarkAndMeasure } from '~/performance/utils';
import { reportToSentry } from '../graph/utils'; import { reportToSentry } from '../../utils';
import { parseData } from '../parsing_utils'; import { parseData } from '../parsing_utils';
import { reportPerformance } from './api'; import { reportPerformance } from './api';
import LinksInner from './links_inner.vue'; import LinksInner from './links_inner.vue';
......
...@@ -5,7 +5,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -5,7 +5,7 @@ import axios from '~/lib/utils/axios_utils';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { dasherize } from '~/lib/utils/text_utility'; import { dasherize } from '~/lib/utils/text_utility';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { reportToSentry } from './utils'; import { reportToSentry } from '../../utils';
/** /**
* Renders either a cancel, retry or play icon button and handles the post request * Renders either a cancel, retry or play icon button and handles the post request
......
<script>
import { GlTooltipDirective, GlLink } from '@gitlab/ui';
import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { sprintf } from '~/locale';
import { reportToSentry } from '../../utils';
import ActionComponent from '../jobs_shared/action_component.vue';
import JobNameComponent from '../jobs_shared/job_name_component.vue';
/**
* Renders the badge for the pipeline graph and the job's dropdown.
*
* The following object should be provided as `job`:
*
* {
* "id": 4256,
* "name": "test",
* "status": {
* "icon": "status_success",
* "text": "passed",
* "label": "passed",
* "group": "success",
* "tooltip": "passed",
* "details_path": "/root/ci-mock/builds/4256",
* "action": {
* "icon": "retry",
* "title": "Retry",
* "path": "/root/ci-mock/builds/4256/retry",
* "method": "post"
* }
* }
* }
*/
export default {
hoverClass: 'gl-shadow-x0-y0-b3-s1-blue-500',
components: {
ActionComponent,
JobNameComponent,
GlLink,
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [delayedJobMixin],
props: {
job: {
type: Object,
required: true,
},
cssClassJobName: {
type: String,
required: false,
default: '',
},
dropdownLength: {
type: Number,
required: false,
default: Infinity,
},
jobHovered: {
type: String,
required: false,
default: '',
},
pipelineExpanded: {
type: Object,
required: false,
default: () => ({}),
},
pipelineId: {
type: Number,
required: false,
default: -1,
},
},
computed: {
boundary() {
return this.dropdownLength === 1 ? 'viewport' : 'scrollParent';
},
detailsPath() {
return this.status.details_path;
},
hasDetails() {
return this.status.has_details;
},
status() {
return this.job && this.job.status ? this.job.status : {};
},
tooltipText() {
const textBuilder = [];
const { name: jobName } = this.job;
if (jobName) {
textBuilder.push(jobName);
}
const { tooltip: statusTooltip } = this.status;
if (jobName && statusTooltip) {
textBuilder.push('-');
}
if (statusTooltip) {
if (this.isDelayedJob) {
textBuilder.push(sprintf(statusTooltip, { remainingTime: this.remainingTime }));
} else {
textBuilder.push(statusTooltip);
}
}
return textBuilder.join(' ');
},
/**
* Verifies if the provided job has an action path
*
* @return {Boolean}
*/
hasAction() {
return this.job.status && this.job.status.action && this.job.status.action.path;
},
relatedDownstreamHovered() {
return this.job.name === this.jobHovered;
},
relatedDownstreamExpanded() {
return this.job.name === this.pipelineExpanded.jobName && this.pipelineExpanded.expanded;
},
jobClasses() {
return this.relatedDownstreamHovered || this.relatedDownstreamExpanded
? `${this.$options.hoverClass} ${this.cssClassJobName}`
: this.cssClassJobName;
},
},
errorCaptured(err, _vm, info) {
reportToSentry('pipelines_job_item', `pipelines_job_item error: ${err}, info: ${info}`);
},
methods: {
hideTooltips() {
this.$root.$emit(BV_HIDE_TOOLTIP);
},
pipelineActionRequestComplete() {
this.$emit('pipelineActionRequestComplete');
},
},
};
</script>
<template>
<div
class="ci-job-component gl-display-flex gl-align-items-center gl-justify-content-space-between"
data-qa-selector="job_item_container"
>
<gl-link
v-if="hasDetails"
v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }"
:href="detailsPath"
:title="tooltipText"
:class="jobClasses"
class="js-pipeline-graph-job-link qa-job-link menu-item gl-text-gray-900 gl-active-text-decoration-none gl-focus-text-decoration-none gl-hover-text-decoration-none"
data-testid="job-with-link"
@click.stop="hideTooltips"
@mouseout="hideTooltips"
>
<job-name-component :name="job.name" :status="job.status" :icon-size="24" />
</gl-link>
<div
v-else
v-gl-tooltip="{ boundary, placement: 'bottom', customClass: 'gl-pointer-events-none' }"
:title="tooltipText"
:class="jobClasses"
class="js-job-component-tooltip non-details-job-component menu-item"
data-testid="job-without-link"
@mouseout="hideTooltips"
>
<job-name-component :name="job.name" :status="job.status" :icon-size="24" />
</div>
<action-component
v-if="hasAction"
:tooltip-text="status.action.title"
:link="status.action.path"
:action-icon="status.action.icon"
data-qa-selector="action_button"
@pipelineActionRequestComplete="pipelineActionRequestComplete"
/>
</div>
</template>
...@@ -17,7 +17,7 @@ import { deprecatedCreateFlash as Flash } from '~/flash'; ...@@ -17,7 +17,7 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import eventHub from '../../event_hub'; import eventHub from '../../event_hub';
import JobItem from '../graph/job_item.vue'; import JobItem from './job_item.vue';
export default { export default {
components: { components: {
......
...@@ -3,12 +3,12 @@ import { deprecatedCreateFlash as Flash } from '~/flash'; ...@@ -3,12 +3,12 @@ import { deprecatedCreateFlash as Flash } from '~/flash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import Translate from '~/vue_shared/translate'; import Translate from '~/vue_shared/translate';
import PipelineGraphLegacy from './components/graph/graph_component_legacy.vue'; import PipelineGraphLegacy from './components/graph/graph_component_legacy.vue';
import { reportToSentry } from './components/graph/utils';
import TestReports from './components/test_reports/test_reports.vue'; import TestReports from './components/test_reports/test_reports.vue';
import GraphBundleMixin from './mixins/graph_pipeline_bundle_mixin'; import GraphBundleMixin from './mixins/graph_pipeline_bundle_mixin';
import createDagApp from './pipeline_details_dag'; import createDagApp from './pipeline_details_dag';
import { apolloProvider } from './pipeline_shared_client'; import { apolloProvider } from './pipeline_shared_client';
import createTestReportsStore from './stores/test_reports'; import createTestReportsStore from './stores/test_reports';
import { reportToSentry } from './utils';
Vue.use(Translate); Vue.use(Translate);
......
...@@ -2,7 +2,7 @@ import Vue from 'vue'; ...@@ -2,7 +2,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import { GRAPHQL } from './components/graph/constants'; import { GRAPHQL } from './components/graph/constants';
import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue'; import PipelineGraphWrapper from './components/graph/graph_component_wrapper.vue';
import { reportToSentry } from './components/graph/utils'; import { reportToSentry } from './utils';
Vue.use(VueApollo); Vue.use(VueApollo);
......
import * as Sentry from '@sentry/browser';
import { pickBy } from 'lodash'; import { pickBy } from 'lodash';
import { createNodeDict } from './components/parsing_utils'; import { createNodeDict } from './components/parsing_utils';
import { SUPPORTED_FILTER_PARAMETERS } from './constants'; import { SUPPORTED_FILTER_PARAMETERS } from './constants';
...@@ -65,3 +66,10 @@ export const generateJobNeedsDict = (jobs = {}) => { ...@@ -65,3 +66,10 @@ export const generateJobNeedsDict = (jobs = {}) => {
return { ...acc, [value]: uniqueValues }; return { ...acc, [value]: uniqueValues };
}, {}); }, {});
}; };
export const reportToSentry = (component, failureType) => {
Sentry.withScope((scope) => {
scope.setTag('component', component);
Sentry.captureException(failureType);
});
};
...@@ -3,7 +3,7 @@ import { mount } from '@vue/test-utils'; ...@@ -3,7 +3,7 @@ import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import ActionComponent from '~/pipelines/components/graph/action_component.vue'; import ActionComponent from '~/pipelines/components/jobs_shared/action_component.vue';
describe('pipeline graph action component', () => { describe('pipeline graph action component', () => {
let wrapper; let wrapper;
......
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import jobNameComponent from '~/pipelines/components/graph/job_name_component.vue'; import jobNameComponent from '~/pipelines/components/jobs_shared/job_name_component.vue';
import ciIcon from '~/vue_shared/components/ci_icon.vue'; import ciIcon from '~/vue_shared/components/ci_icon.vue';
describe('job name component', () => { describe('job name component', () => {
......
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import ActionComponent from '~/pipelines/components/graph/action_component.vue';
import JobItem from '~/pipelines/components/graph/job_item.vue'; import JobItem from '~/pipelines/components/graph/job_item.vue';
import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue'; import StageColumnComponent from '~/pipelines/components/graph/stage_column_component.vue';
import ActionComponent from '~/pipelines/components/jobs_shared/action_component.vue';
const mockJob = { const mockJob = {
id: 4250, id: 4250,
......
...@@ -8,9 +8,9 @@ import { ...@@ -8,9 +8,9 @@ import {
PIPELINES_DETAIL_LINKS_JOB_RATIO, PIPELINES_DETAIL_LINKS_JOB_RATIO,
} from '~/performance/constants'; } from '~/performance/constants';
import * as perfUtils from '~/performance/utils'; import * as perfUtils from '~/performance/utils';
import * as sentryUtils from '~/pipelines/components/graph/utils';
import * as Api from '~/pipelines/components/graph_shared/api'; import * as Api from '~/pipelines/components/graph_shared/api';
import LinksInner from '~/pipelines/components/graph_shared/links_inner.vue'; import LinksInner from '~/pipelines/components/graph_shared/links_inner.vue';
import * as sentryUtils from '~/pipelines/utils';
import { createJobsHash } from '~/pipelines/utils'; import { createJobsHash } from '~/pipelines/utils';
import { import {
jobRect, jobRect,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment