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:
Diffstat (limited to 'app/assets/javascripts/jobs/components/job')
-rw-r--r--app/assets/javascripts/jobs/components/job/empty_state.vue100
-rw-r--r--app/assets/javascripts/jobs/components/job/environments_block.vue214
-rw-r--r--app/assets/javascripts/jobs/components/job/erased_block.vue49
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql11
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql6
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql11
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql11
-rw-r--r--app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql12
-rw-r--r--app/assets/javascripts/jobs/components/job/job_app.vue350
-rw-r--r--app/assets/javascripts/jobs/components/job/job_log_controllers.vue269
-rw-r--r--app/assets/javascripts/jobs/components/job/manual_variables_form.vue305
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue121
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue47
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue77
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue64
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue81
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue35
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue154
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue59
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue146
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue124
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue171
-rw-r--r--app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue94
-rw-r--r--app/assets/javascripts/jobs/components/job/stuck_block.vue90
-rw-r--r--app/assets/javascripts/jobs/components/job/unmet_prerequisites_block.vue33
25 files changed, 0 insertions, 2634 deletions
diff --git a/app/assets/javascripts/jobs/components/job/empty_state.vue b/app/assets/javascripts/jobs/components/job/empty_state.vue
deleted file mode 100644
index d0a39025807..00000000000
--- a/app/assets/javascripts/jobs/components/job/empty_state.vue
+++ /dev/null
@@ -1,100 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import ManualVariablesForm from '~/jobs/components/job/manual_variables_form.vue';
-
-export default {
- components: {
- GlLink,
- ManualVariablesForm,
- },
- props: {
- illustrationPath: {
- type: String,
- required: true,
- },
- illustrationSizeClass: {
- type: String,
- required: true,
- },
- isRetryable: {
- type: Boolean,
- required: true,
- },
- jobId: {
- type: Number,
- required: true,
- },
- title: {
- type: String,
- required: true,
- },
- content: {
- type: String,
- required: false,
- default: null,
- },
- playable: {
- type: Boolean,
- required: true,
- default: false,
- },
- scheduled: {
- type: Boolean,
- required: false,
- default: false,
- },
- action: {
- type: Object,
- required: false,
- default: null,
- validator(value) {
- return (
- value === null ||
- (Object.prototype.hasOwnProperty.call(value, 'path') &&
- Object.prototype.hasOwnProperty.call(value, 'method') &&
- Object.prototype.hasOwnProperty.call(value, 'button_title'))
- );
- },
- },
- },
- computed: {
- shouldRenderManualVariables() {
- return this.playable && !this.scheduled;
- },
- },
-};
-</script>
-<template>
- <div class="row empty-state">
- <div class="col-12">
- <div :class="illustrationSizeClass" class="svg-content">
- <img :src="illustrationPath" />
- </div>
- </div>
-
- <div class="col-12">
- <div class="text-content">
- <h4 class="text-center" data-testid="job-empty-state-title">{{ title }}</h4>
-
- <p v-if="content" data-testid="job-empty-state-content">{{ content }}</p>
- </div>
- <manual-variables-form
- v-if="shouldRenderManualVariables"
- :is-retryable="isRetryable"
- :job-id="jobId"
- @hideManualVariablesForm="$emit('hideManualVariablesForm')"
- />
- <div v-if="action && !shouldRenderManualVariables" class="text-content">
- <div class="text-center">
- <gl-link
- :href="action.path"
- :data-method="action.method"
- class="btn gl-button btn-confirm gl-text-decoration-none!"
- data-testid="job-empty-state-action"
- >{{ action.button_title }}</gl-link
- >
- </div>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/environments_block.vue b/app/assets/javascripts/jobs/components/job/environments_block.vue
deleted file mode 100644
index 4046e1ade82..00000000000
--- a/app/assets/javascripts/jobs/components/job/environments_block.vue
+++ /dev/null
@@ -1,214 +0,0 @@
-<script>
-import { GlSprintf, GlLink } from '@gitlab/ui';
-import { isEmpty } from 'lodash';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import { __ } from '~/locale';
-
-export default {
- creatingEnvironment: 'creating',
- components: {
- CiIcon,
- GlSprintf,
- GlLink,
- },
- props: {
- deploymentStatus: {
- type: Object,
- required: true,
- },
- deploymentCluster: {
- type: Object,
- required: false,
- default: null,
- },
- iconStatus: {
- type: Object,
- required: true,
- },
- },
- computed: {
- environment() {
- switch (this.deploymentStatus.status) {
- case 'last':
- return this.lastEnvironmentMessage();
- case 'out_of_date':
- return this.outOfDateEnvironmentMessage();
- case 'failed':
- return this.failedEnvironmentMessage();
- case this.$options.creatingEnvironment:
- return this.creatingEnvironmentMessage();
- default:
- return '';
- }
- },
- environmentLink() {
- if (this.hasEnvironment) {
- return {
- link: this.deploymentStatus.environment.environment_path,
- name: this.deploymentStatus.environment.name,
- };
- }
- return {};
- },
- hasLastDeployment() {
- return this.hasEnvironment && this.deploymentStatus.environment.last_deployment;
- },
- lastDeployment() {
- return this.hasLastDeployment ? this.deploymentStatus.environment.last_deployment : {};
- },
- hasEnvironment() {
- return !isEmpty(this.deploymentStatus.environment);
- },
- lastDeploymentPath() {
- return !isEmpty(this.lastDeployment.deployable)
- ? this.lastDeployment.deployable.build_path
- : '';
- },
- hasCluster() {
- return Boolean(this.deploymentCluster) && Boolean(this.deploymentCluster.name);
- },
- clusterNameOrLink() {
- if (!this.hasCluster) {
- return '';
- }
-
- const { name, path } = this.deploymentCluster;
-
- return {
- path,
- name,
- };
- },
- kubernetesNamespace() {
- return this.hasCluster ? this.deploymentCluster.kubernetes_namespace : null;
- },
- deploymentLink() {
- return {
- path: this.lastDeploymentPath,
- name:
- this.deploymentStatus.status === this.$options.creatingEnvironment
- ? __('latest deployment')
- : __('most recent deployment'),
- };
- },
- },
- methods: {
- failedEnvironmentMessage() {
- return __('The deployment of this job to %{environmentLink} did not succeed.');
- },
- lastEnvironmentMessage() {
- if (this.hasCluster) {
- if (this.kubernetesNamespace) {
- return __(
- 'This job is deployed to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}.',
- );
- }
- // we know the cluster but not the namespace
- return __('This job is deployed to %{environmentLink} using cluster %{clusterNameOrLink}.');
- }
- // not a cluster deployment
- return __('This job is deployed to %{environmentLink}.');
- },
- outOfDateEnvironmentMessage() {
- if (this.hasLastDeployment) {
- if (this.hasCluster) {
- if (this.kubernetesNamespace) {
- return __(
- 'This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}. View the %{deploymentLink}.',
- );
- }
- // we know the cluster but not the namespace
- return __(
- 'This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink}. View the %{deploymentLink}.',
- );
- }
- // not a cluster deployment
- return __(
- 'This job is an out-of-date deployment to %{environmentLink}. View the %{deploymentLink}.',
- );
- }
- // no last deployment, i.e. this is the first deployment
- if (this.hasCluster) {
- if (this.kubernetesNamespace) {
- return __(
- 'This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}.',
- );
- }
- // we know the cluster but not the namespace
- return __(
- 'This job is an out-of-date deployment to %{environmentLink} using cluster %{clusterNameOrLink}.',
- );
- }
- // not a cluster deployment
- return __('This job is an out-of-date deployment to %{environmentLink}.');
- },
- creatingEnvironmentMessage() {
- if (this.hasLastDeployment) {
- if (this.hasCluster) {
- if (this.kubernetesNamespace) {
- return __(
- 'This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}. This will overwrite the %{deploymentLink}.',
- );
- }
- // we know the cluster but not the namespace
- return __(
- 'This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink}. This will overwrite the %{deploymentLink}.',
- );
- }
- // not a cluster deployment
- return __(
- 'This job is creating a deployment to %{environmentLink}. This will overwrite the %{deploymentLink}.',
- );
- }
- // no last deployment, i.e. this is the first deployment
- if (this.hasCluster) {
- if (this.kubernetesNamespace) {
- return __(
- 'This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink} and namespace %{kubernetesNamespace}.',
- );
- }
- // we know the cluster but not the namespace
- return __(
- 'This job is creating a deployment to %{environmentLink} using cluster %{clusterNameOrLink}.',
- );
- }
- // not a cluster deployment
- return __('This job is creating a deployment to %{environmentLink}.');
- },
- },
-};
-</script>
-<template>
- <div class="gl-mt-3 gl-mb-3 js-environment-container">
- <div class="environment-information">
- <ci-icon :status="iconStatus" />
- <p class="inline gl-mb-0">
- <gl-sprintf :message="environment">
- <template #environmentLink>
- <gl-link
- v-if="hasEnvironment"
- :href="environmentLink.link"
- data-testid="job-environment-link"
- >{{ environmentLink.name }}</gl-link
- >
- </template>
- <template #clusterNameOrLink>
- <gl-link
- v-if="clusterNameOrLink.path"
- :href="clusterNameOrLink.path"
- data-testid="job-cluster-link"
- >{{ clusterNameOrLink.name }}</gl-link
- >
- <template v-else>{{ clusterNameOrLink.name }}</template>
- </template>
- <template #kubernetesNamespace>{{ kubernetesNamespace }}</template>
- <template #deploymentLink>
- <gl-link :href="deploymentLink.path" data-testid="job-deployment-link">{{
- deploymentLink.name
- }}</gl-link>
- </template>
- </gl-sprintf>
- </p>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/erased_block.vue b/app/assets/javascripts/jobs/components/job/erased_block.vue
deleted file mode 100644
index a815689659e..00000000000
--- a/app/assets/javascripts/jobs/components/job/erased_block.vue
+++ /dev/null
@@ -1,49 +0,0 @@
-<script>
-import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui';
-import { isEmpty } from 'lodash';
-import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-
-export default {
- components: {
- GlAlert,
- GlLink,
- GlSprintf,
- TimeagoTooltip,
- },
- props: {
- user: {
- type: Object,
- required: false,
- default: () => ({}),
- },
- erasedAt: {
- type: String,
- required: true,
- },
- },
- computed: {
- isErasedByUser() {
- return !isEmpty(this.user);
- },
- },
-};
-</script>
-<template>
- <div class="gl-mt-3">
- <gl-alert variant="warning" :dismissible="false">
- <template v-if="isErasedByUser">
- <gl-sprintf :message="s__('Job|Job has been erased by %{userLink}')">
- <template #userLink>
- <gl-link :href="user.web_url" target="_blank">{{ user.username }}</gl-link>
- </template>
- </gl-sprintf>
- </template>
-
- <template v-else>
- {{ s__('Job|Job has been erased') }}
- </template>
-
- <timeago-tooltip :time="erasedAt" />
- </gl-alert>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql b/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql
deleted file mode 100644
index f4a0b10672e..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_job.fragment.graphql
+++ /dev/null
@@ -1,11 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql"
-
-fragment BaseCiJob on CiJob {
- id
- manualVariables {
- nodes {
- ...ManualCiVariable
- }
- }
- __typename
-}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql b/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql
deleted file mode 100644
index 0479df7bc4c..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/fragments/ci_variable.fragment.graphql
+++ /dev/null
@@ -1,6 +0,0 @@
-fragment ManualCiVariable on CiVariable {
- __typename
- id
- key
- value
-}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql b/app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql
deleted file mode 100644
index 520deef5136..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_play_with_variables.mutation.graphql
+++ /dev/null
@@ -1,11 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
-
-mutation playJobWithVariables($id: CiBuildID!, $variables: [CiVariableInput!]) {
- jobPlay(input: { id: $id, variables: $variables }) {
- job {
- ...BaseCiJob
- webPath
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql b/app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql
deleted file mode 100644
index e35d603ea71..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/mutations/job_retry_with_variables.mutation.graphql
+++ /dev/null
@@ -1,11 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
-
-mutation retryJobWithVariables($id: CiBuildID!, $variables: [CiVariableInput!]) {
- jobRetry(input: { id: $id, variables: $variables }) {
- job {
- ...BaseCiJob
- webPath
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql b/app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql
deleted file mode 100644
index 95e3521091d..00000000000
--- a/app/assets/javascripts/jobs/components/job/graphql/queries/get_job.query.graphql
+++ /dev/null
@@ -1,12 +0,0 @@
-#import "~/jobs/components/job/graphql/fragments/ci_job.fragment.graphql"
-
-query getJob($fullPath: ID!, $id: JobID!) {
- project(fullPath: $fullPath) {
- id
- job(id: $id) {
- ...BaseCiJob
- manualJob
- name
- }
- }
-}
diff --git a/app/assets/javascripts/jobs/components/job/job_app.vue b/app/assets/javascripts/jobs/components/job/job_app.vue
deleted file mode 100644
index 52030a0f830..00000000000
--- a/app/assets/javascripts/jobs/components/job/job_app.vue
+++ /dev/null
@@ -1,350 +0,0 @@
-<script>
-import { GlLoadingIcon, GlIcon, GlAlert } from '@gitlab/ui';
-import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
-import { throttle, isEmpty } from 'lodash';
-// eslint-disable-next-line no-restricted-imports
-import { mapGetters, mapState, mapActions } from 'vuex';
-import LogTopBar from 'ee_else_ce/jobs/components/job/job_log_controllers.vue';
-import SafeHtml from '~/vue_shared/directives/safe_html';
-import { isScrolledToBottom } from '~/lib/utils/scroll_utils';
-import { __, sprintf } from '~/locale';
-import CiHeader from '~/vue_shared/components/header_ci_component.vue';
-import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
-import Log from '~/jobs/components/log/log.vue';
-import { MANUAL_STATUS } from '~/jobs/constants';
-import EmptyState from './empty_state.vue';
-import EnvironmentsBlock from './environments_block.vue';
-import ErasedBlock from './erased_block.vue';
-import StuckBlock from './stuck_block.vue';
-import UnmetPrerequisitesBlock from './unmet_prerequisites_block.vue';
-import Sidebar from './sidebar/sidebar.vue';
-
-export default {
- name: 'JobPageApp',
- components: {
- CiHeader,
- EmptyState,
- EnvironmentsBlock,
- ErasedBlock,
- GlIcon,
- Log,
- LogTopBar,
- StuckBlock,
- UnmetPrerequisitesBlock,
- Sidebar,
- GlLoadingIcon,
- SharedRunner: () => import('ee_component/jobs/components/shared_runner_limit_block.vue'),
- GlAlert,
- },
- directives: {
- SafeHtml,
- },
- mixins: [delayedJobMixin],
- props: {
- artifactHelpUrl: {
- type: String,
- required: false,
- default: '',
- },
- runnerSettingsUrl: {
- type: String,
- required: false,
- default: null,
- },
- deploymentHelpUrl: {
- type: String,
- required: false,
- default: null,
- },
- terminalPath: {
- type: String,
- required: false,
- default: null,
- },
- projectPath: {
- type: String,
- required: true,
- },
- subscriptionsMoreMinutesUrl: {
- type: String,
- required: false,
- default: null,
- },
- },
- data() {
- return {
- searchResults: [],
- showUpdateVariablesState: false,
- };
- },
- computed: {
- ...mapState([
- 'isLoading',
- 'job',
- 'isSidebarOpen',
- 'jobLog',
- 'isJobLogComplete',
- 'jobLogSize',
- 'isJobLogSizeVisible',
- 'isScrollBottomDisabled',
- 'isScrollTopDisabled',
- 'isScrolledToBottomBeforeReceivingJobLog',
- 'hasError',
- 'selectedStage',
- ]),
- ...mapGetters([
- 'headerTime',
- 'hasUnmetPrerequisitesFailure',
- 'shouldRenderCalloutMessage',
- 'shouldRenderTriggeredLabel',
- 'hasEnvironment',
- 'shouldRenderSharedRunnerLimitWarning',
- 'hasJobLog',
- 'emptyStateIllustration',
- 'isScrollingDown',
- 'emptyStateAction',
- 'hasOfflineRunnersForProject',
- ]),
-
- shouldRenderContent() {
- return !this.isLoading && !this.hasError;
- },
-
- emptyStateTitle() {
- const { emptyStateIllustration, remainingTime } = this;
- const { title } = emptyStateIllustration;
-
- if (this.isDelayedJob) {
- return sprintf(title, { remainingTime });
- }
-
- return title;
- },
-
- shouldRenderHeaderCallout() {
- return this.shouldRenderCalloutMessage && !this.hasUnmetPrerequisitesFailure;
- },
-
- isJobRetryable() {
- return Boolean(this.job.retry_path);
- },
-
- itemName() {
- return sprintf(__('Job %{jobName}'), { jobName: this.job.name });
- },
- },
- watch: {
- // Once the job log is loaded,
- // fetch the stages for the dropdown on the sidebar
- job(newVal, oldVal) {
- if (isEmpty(oldVal) && !isEmpty(newVal.pipeline)) {
- const stages = this.job.pipeline.details.stages || [];
-
- const defaultStage = stages.find((stage) => stage && stage.name === this.selectedStage);
-
- if (defaultStage) {
- this.fetchJobsForStage(defaultStage);
- }
- }
-
- // Only poll for job log if we are not in the manual variables form empty state.
- // This will be handled more elegantly in the future with GraphQL in https://gitlab.com/gitlab-org/gitlab/-/issues/389597
- if (newVal?.status?.group !== MANUAL_STATUS && !this.showUpdateVariablesState) {
- this.fetchJobLog();
- }
- },
- },
- created() {
- this.throttled = throttle(this.toggleScrollButtons, 100);
-
- window.addEventListener('resize', this.onResize);
- window.addEventListener('scroll', this.updateScroll);
- },
- mounted() {
- this.updateSidebar();
- },
- beforeDestroy() {
- this.stopPollingJobLog();
- this.stopPolling();
- window.removeEventListener('resize', this.onResize);
- window.removeEventListener('scroll', this.updateScroll);
- },
- methods: {
- ...mapActions([
- 'fetchJobLog',
- 'fetchJobsForStage',
- 'hideSidebar',
- 'showSidebar',
- 'toggleSidebar',
- 'scrollBottom',
- 'scrollTop',
- 'stopPollingJobLog',
- 'stopPolling',
- 'toggleScrollButtons',
- 'toggleScrollAnimation',
- ]),
- onHideManualVariablesForm() {
- this.showUpdateVariablesState = false;
- },
- onResize() {
- this.updateSidebar();
- this.updateScroll();
- },
- onUpdateVariables() {
- this.showUpdateVariablesState = true;
- },
- updateSidebar() {
- const breakpoint = bp.getBreakpointSize();
- if (breakpoint === 'xs' || breakpoint === 'sm') {
- this.hideSidebar();
- } else if (!this.isSidebarOpen) {
- this.showSidebar();
- }
- },
- updateScroll() {
- if (!isScrolledToBottom()) {
- this.toggleScrollAnimation(false);
- } else if (this.isScrollingDown) {
- this.toggleScrollAnimation(true);
- }
-
- this.throttled();
- },
- setSearchResults(searchResults) {
- this.searchResults = searchResults;
- },
- },
-};
-</script>
-<template>
- <div>
- <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-6" />
-
- <template v-else-if="shouldRenderContent">
- <div class="build-page" data-testid="job-content">
- <!-- Header Section -->
- <header>
- <div class="build-header top-area">
- <ci-header
- :status="job.status"
- :time="headerTime"
- :user="job.user"
- :has-sidebar-button="true"
- :should-render-triggered-label="shouldRenderTriggeredLabel"
- :item-name="itemName"
- @clickedSidebarButton="toggleSidebar"
- />
- </div>
- <gl-alert
- v-if="shouldRenderHeaderCallout"
- variant="danger"
- class="gl-mt-3"
- :dismissible="false"
- >
- <div v-safe-html="job.callout_message"></div>
- </gl-alert>
- </header>
- <!-- EO Header Section -->
-
- <!-- Body Section -->
- <stuck-block
- v-if="job.stuck"
- :has-offline-runners-for-project="hasOfflineRunnersForProject"
- :tags="job.tags"
- :runners-path="runnerSettingsUrl"
- />
-
- <unmet-prerequisites-block
- v-if="hasUnmetPrerequisitesFailure"
- :help-path="deploymentHelpUrl"
- />
-
- <shared-runner
- v-if="shouldRenderSharedRunnerLimitWarning"
- :quota-used="job.runners.quota.used"
- :quota-limit="job.runners.quota.limit"
- :project-path="projectPath"
- :subscriptions-more-minutes-url="subscriptionsMoreMinutesUrl"
- />
-
- <environments-block
- v-if="hasEnvironment"
- :deployment-status="job.deployment_status"
- :deployment-cluster="job.deployment_cluster"
- :icon-status="job.status"
- />
-
- <erased-block
- v-if="job.erased_at"
- data-testid="job-erased-block"
- :user="job.erased_by"
- :erased-at="job.erased_at"
- />
-
- <div
- v-if="job.archived"
- class="gl-mt-3 gl-py-2 gl-px-3 gl-align-items-center gl-z-index-1 gl-m-auto archived-job"
- :class="{ 'sticky-top gl-border-bottom-0': hasJobLog }"
- data-testid="archived-job"
- >
- <gl-icon name="lock" class="gl-vertical-align-bottom" />
- {{ __('This job is archived. Only the complete pipeline can be retried.') }}
- </div>
- <!-- job log -->
- <div
- v-if="hasJobLog && !showUpdateVariablesState"
- class="build-log-container gl-relative"
- :class="{ 'gl-mt-3': !job.archived }"
- >
- <log-top-bar
- :class="{
- 'has-archived-block': job.archived,
- }"
- :size="jobLogSize"
- :raw-path="job.raw_path"
- :is-scroll-bottom-disabled="isScrollBottomDisabled"
- :is-scroll-top-disabled="isScrollTopDisabled"
- :is-job-log-size-visible="isJobLogSizeVisible"
- :is-scrolling-down="isScrollingDown"
- :is-complete="isJobLogComplete"
- :job-log="jobLog"
- @scrollJobLogTop="scrollTop"
- @scrollJobLogBottom="scrollBottom"
- @searchResults="setSearchResults"
- />
- <log :job-log="jobLog" :is-complete="isJobLogComplete" :search-results="searchResults" />
- </div>
- <!-- EO job log -->
-
- <!-- empty state -->
- <empty-state
- v-if="!hasJobLog || showUpdateVariablesState"
- :illustration-path="emptyStateIllustration.image"
- :illustration-size-class="emptyStateIllustration.size"
- :is-retryable="isJobRetryable"
- :job-id="job.id"
- :title="emptyStateTitle"
- :content="emptyStateIllustration.content"
- :action="emptyStateAction"
- :playable="job.playable"
- :scheduled="job.scheduled"
- @hideManualVariablesForm="onHideManualVariablesForm()"
- />
- <!-- EO empty state -->
-
- <!-- EO Body Section -->
- </div>
- </template>
-
- <sidebar
- v-if="shouldRenderContent"
- :class="{
- 'right-sidebar-expanded': isSidebarOpen,
- 'right-sidebar-collapsed': !isSidebarOpen,
- }"
- :artifact-help-url="artifactHelpUrl"
- data-testid="job-sidebar"
- @updateVariables="onUpdateVariables()"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job/job_log_controllers.vue
deleted file mode 100644
index efd4eed2a9f..00000000000
--- a/app/assets/javascripts/jobs/components/job/job_log_controllers.vue
+++ /dev/null
@@ -1,269 +0,0 @@
-<script>
-import { GlTooltipDirective, GlLink, GlButton, GlSearchBoxByClick } from '@gitlab/ui';
-import { scrollToElement, backOff } from '~/lib/utils/common_utils';
-import { numberToHumanSize } from '~/lib/utils/number_utils';
-import { __, s__, sprintf } from '~/locale';
-import HelpPopover from '~/vue_shared/components/help_popover.vue';
-import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
-
-export default {
- i18n: {
- scrollToBottomButtonLabel: s__('Job|Scroll to bottom'),
- scrollToTopButtonLabel: s__('Job|Scroll to top'),
- scrollToNextFailureButtonLabel: s__('Job|Scroll to next failure'),
- showRawButtonLabel: s__('Job|Show complete raw'),
- searchPlaceholder: s__('Job|Search job log'),
- noResults: s__('Job|No search results found'),
- searchPopoverTitle: s__('Job|Job log search'),
- searchPopoverDescription: s__(
- 'Job|Search for substrings in your job log output. Currently search is only supported for the visible job log output, not for any log output that is truncated due to size.',
- ),
- logLineNumberNotFound: s__('Job|We could not find this element'),
- },
- components: {
- GlLink,
- GlButton,
- GlSearchBoxByClick,
- HelpPopover,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [glFeatureFlagMixin()],
- props: {
- size: {
- type: Number,
- required: true,
- },
- rawPath: {
- type: String,
- required: false,
- default: null,
- },
- isScrollTopDisabled: {
- type: Boolean,
- required: true,
- },
- isScrollBottomDisabled: {
- type: Boolean,
- required: true,
- },
- isScrollingDown: {
- type: Boolean,
- required: true,
- },
- isJobLogSizeVisible: {
- type: Boolean,
- required: true,
- },
- isComplete: {
- type: Boolean,
- required: true,
- },
- jobLog: {
- type: Array,
- required: true,
- },
- },
- data() {
- return {
- searchTerm: '',
- searchResults: [],
- failureCount: null,
- failureIndex: 0,
- };
- },
- computed: {
- jobLogSize() {
- return sprintf(__('Showing last %{size} of log -'), {
- size: numberToHumanSize(this.size),
- });
- },
- showJumpToFailures() {
- return this.glFeatures.jobLogJumpToFailures;
- },
- hasFailures() {
- return this.failureCount > 0;
- },
- shouldDisableJumpToFailures() {
- return !this.hasFailures;
- },
- },
- mounted() {
- this.checkFailureCount();
- },
- methods: {
- checkFailureCount() {
- if (this.glFeatures.jobLogJumpToFailures) {
- backOff((next, stop) => {
- this.failureCount = document.querySelectorAll('.term-fg-l-red').length;
-
- if (this.hasFailures || (this.isComplete && !this.hasFailures)) {
- stop();
- } else {
- next();
- }
- }).catch(() => {
- this.failureCount = null;
- });
- }
- },
- handleScrollToNextFailure() {
- const failures = document.querySelectorAll('.term-fg-l-red');
- const nextFailure = failures[this.failureIndex];
-
- if (nextFailure) {
- nextFailure.scrollIntoView({ block: 'center' });
- this.failureIndex = (this.failureIndex + 1) % failures.length;
- }
- },
- handleScrollToTop() {
- this.$emit('scrollJobLogTop');
- this.failureIndex = 0;
- },
- handleScrollToBottom() {
- this.$emit('scrollJobLogBottom');
- this.failureIndex = 0;
- },
- searchJobLog() {
- this.searchResults = [];
-
- if (!this.searchTerm) return;
-
- const compactedLog = [];
-
- this.jobLog.forEach((obj) => {
- if (obj.lines && obj.lines.length > 0) {
- compactedLog.push(...obj.lines);
- }
-
- if (!obj.lines && obj.content.length > 0) {
- compactedLog.push(obj);
- }
- });
-
- compactedLog.forEach((line) => {
- const lineText = line.content[0].text;
-
- if (lineText.toLocaleLowerCase().includes(this.searchTerm.toLocaleLowerCase())) {
- this.searchResults.push(line);
- }
- });
-
- if (this.searchResults.length > 0) {
- this.$emit('searchResults', this.searchResults);
-
- // BE returns zero based index, we need to add one to match the line numbers in the DOM
- const firstSearchResult = `#L${this.searchResults[0].lineNumber + 1}`;
- const logLine = document.querySelector(`.js-line ${firstSearchResult}`);
-
- if (logLine) {
- setTimeout(() => scrollToElement(logLine));
-
- const message = sprintf(s__('Job|%{searchLength} results found for %{searchTerm}'), {
- searchLength: this.searchResults.length,
- searchTerm: this.searchTerm,
- });
-
- this.$toast.show(message);
- } else {
- this.$toast.show(this.$options.i18n.logLineNumberNotFound);
- }
- } else {
- this.$toast.show(this.$options.i18n.noResults);
- }
- },
- },
-};
-</script>
-<template>
- <div class="top-bar gl-display-flex gl-justify-content-space-between">
- <slot name="drawers"></slot>
- <!-- truncate information -->
- <div
- class="truncated-info gl-display-none gl-sm-display-flex gl-flex-wrap gl-align-items-center"
- data-testid="log-truncated-info"
- >
- <template v-if="isJobLogSizeVisible">
- {{ jobLogSize }}
- <gl-link
- v-if="rawPath"
- :href="rawPath"
- class="text-plain text-underline gl-ml-2"
- data-testid="raw-link"
- >{{ s__('Job|Complete Raw') }}</gl-link
- >
- </template>
- </div>
- <!-- eo truncate information -->
-
- <div class="controllers">
- <slot name="controllers"> </slot>
- <gl-search-box-by-click
- v-model="searchTerm"
- class="gl-mr-3"
- :placeholder="$options.i18n.searchPlaceholder"
- data-testid="job-log-search-box"
- @clear="$emit('searchResults', [])"
- @submit="searchJobLog"
- />
-
- <help-popover class="gl-mr-3">
- <template #title>{{ $options.i18n.searchPopoverTitle }}</template>
-
- <p class="gl-mb-0">
- {{ $options.i18n.searchPopoverDescription }}
- </p>
- </help-popover>
-
- <!-- links -->
- <gl-button
- v-if="rawPath"
- v-gl-tooltip.body
- :title="$options.i18n.showRawButtonLabel"
- :aria-label="$options.i18n.showRawButtonLabel"
- :href="rawPath"
- data-testid="job-raw-link-controller"
- icon="doc-text"
- />
- <!-- eo links -->
-
- <!-- scroll buttons -->
- <gl-button
- v-if="showJumpToFailures"
- v-gl-tooltip
- :title="$options.i18n.scrollToNextFailureButtonLabel"
- :aria-label="$options.i18n.scrollToNextFailureButtonLabel"
- :disabled="shouldDisableJumpToFailures"
- class="btn-scroll gl-ml-3"
- data-testid="job-controller-scroll-to-failure"
- icon="soft-wrap"
- @click="handleScrollToNextFailure"
- />
-
- <div v-gl-tooltip :title="$options.i18n.scrollToTopButtonLabel" class="gl-ml-3">
- <gl-button
- :disabled="isScrollTopDisabled"
- class="btn-scroll"
- data-testid="job-controller-scroll-top"
- icon="scroll_up"
- :aria-label="$options.i18n.scrollToTopButtonLabel"
- @click="handleScrollToTop"
- />
- </div>
-
- <div v-gl-tooltip :title="$options.i18n.scrollToBottomButtonLabel" class="gl-ml-3">
- <gl-button
- :disabled="isScrollBottomDisabled"
- class="js-scroll-bottom btn-scroll"
- data-testid="job-controller-scroll-bottom"
- icon="scroll_down"
- :class="{ animate: isScrollingDown }"
- :aria-label="$options.i18n.scrollToBottomButtonLabel"
- @click="handleScrollToBottom"
- />
- </div>
- <!-- eo scroll buttons -->
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/manual_variables_form.vue b/app/assets/javascripts/jobs/components/job/manual_variables_form.vue
deleted file mode 100644
index 356d65e1d14..00000000000
--- a/app/assets/javascripts/jobs/components/job/manual_variables_form.vue
+++ /dev/null
@@ -1,305 +0,0 @@
-<script>
-import {
- GlFormInputGroup,
- GlInputGroupText,
- GlFormInput,
- GlButton,
- GlLink,
- GlLoadingIcon,
- GlSprintf,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import { cloneDeep, uniqueId } from 'lodash';
-import { fetchPolicies } from '~/lib/graphql';
-import { createAlert } from '~/alert';
-import { TYPENAME_CI_BUILD, TYPENAME_COMMIT_STATUS } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import { JOB_GRAPHQL_ERRORS } from '~/jobs/constants';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import { s__ } from '~/locale';
-import { reportMessageToSentry } from '~/jobs/utils';
-import GetJob from './graphql/queries/get_job.query.graphql';
-import playJobWithVariablesMutation from './graphql/mutations/job_play_with_variables.mutation.graphql';
-import retryJobWithVariablesMutation from './graphql/mutations/job_retry_with_variables.mutation.graphql';
-
-// This component is a port of ~/jobs/components/job/legacy_manual_variables_form.vue
-// It is meant to fetch/update the job information via GraphQL instead of REST API.
-
-export default {
- name: 'ManualVariablesForm',
- components: {
- GlFormInputGroup,
- GlInputGroupText,
- GlFormInput,
- GlButton,
- GlLink,
- GlLoadingIcon,
- GlSprintf,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- inject: ['projectPath'],
- apollo: {
- variables: {
- query: GetJob,
- variables() {
- return {
- fullPath: this.projectPath,
- id: convertToGraphQLId(TYPENAME_COMMIT_STATUS, this.jobId),
- };
- },
- fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
- update(data) {
- const jobVariables = cloneDeep(data?.project?.job?.manualVariables?.nodes);
- return [...jobVariables.reverse(), ...this.variables];
- },
- error(error) {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText });
- reportMessageToSentry(this.$options.name, error, {});
- },
- },
- },
- props: {
- isRetryable: {
- type: Boolean,
- required: true,
- },
- jobId: {
- type: Number,
- required: true,
- },
- },
- clearBtnSharedClasses: ['gl-flex-grow-0 gl-flex-basis-0 gl-m-0! gl-ml-3!'],
- inputTypes: {
- key: 'key',
- value: 'value',
- },
- i18n: {
- cancel: s__('CiVariables|Cancel'),
- removeInputs: s__('CiVariables|Remove inputs'),
- formHelpText: s__(
- 'CiVariables|Specify variable values to be used in this run. The variables specified in the configuration file and %{linkStart}CI/CD settings%{linkEnd} are used by default.',
- ),
- overrideNoteText: s__(
- 'CiVariables|Variables specified here are %{boldStart}expanded%{boldEnd} and not %{boldStart}masked.%{boldEnd}',
- ),
- header: s__('CiVariables|Variables'),
- keyLabel: s__('CiVariables|Key'),
- keyPlaceholder: s__('CiVariables|Input variable key'),
- runAgainButtonText: s__('CiVariables|Run job again'),
- runButtonText: s__('CiVariables|Run job'),
- valueLabel: s__('CiVariables|Value'),
- valuePlaceholder: s__('CiVariables|Input variable value'),
- },
- data() {
- return {
- job: {},
- variables: [
- {
- id: uniqueId(),
- key: '',
- value: '',
- },
- ],
- runBtnDisabled: false,
- };
- },
- computed: {
- mutationVariables() {
- return {
- id: convertToGraphQLId(TYPENAME_CI_BUILD, this.jobId),
- variables: this.preparedVariables,
- };
- },
- preparedVariables() {
- return this.variables
- .filter((variable) => variable.key !== '')
- .map(({ key, value }) => ({ key, value }));
- },
- runBtnText() {
- return this.isRetryable
- ? this.$options.i18n.runAgainButtonText
- : this.$options.i18n.runButtonText;
- },
- variableSettings() {
- return helpPagePath('ci/variables/index', { anchor: 'add-a-cicd-variable-to-a-project' });
- },
- },
- methods: {
- async playJob() {
- try {
- const { data } = await this.$apollo.mutate({
- mutation: playJobWithVariablesMutation,
- variables: this.mutationVariables,
- });
- if (data.jobPlay?.errors?.length) {
- createAlert({ message: data.jobPlay.errors[0] });
- } else {
- this.navigateToJob(data.jobPlay?.job?.webPath);
- }
- } catch (error) {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText });
- reportMessageToSentry(this.$options.name, error, {});
- }
- },
- async retryJob() {
- try {
- const { data } = await this.$apollo.mutate({
- mutation: retryJobWithVariablesMutation,
- variables: this.mutationVariables,
- });
- if (data.jobRetry?.errors?.length) {
- createAlert({ message: data.jobRetry.errors[0] });
- } else {
- this.navigateToJob(data.jobRetry?.job?.webPath);
- }
- } catch (error) {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobMutationErrorText });
- reportMessageToSentry(this.$options.name, error, {});
- }
- },
- addEmptyVariable() {
- const lastVar = this.variables[this.variables.length - 1];
-
- if (lastVar.key === '') {
- return;
- }
-
- this.variables.push({
- id: uniqueId(),
- key: '',
- value: '',
- });
- },
- canRemove(index) {
- return index < this.variables.length - 1;
- },
- deleteVariable(id) {
- this.variables.splice(
- this.variables.findIndex((el) => el.id === id),
- 1,
- );
- },
- inputRef(type, id) {
- return `${this.$options.inputTypes[type]}-${id}`;
- },
- navigateToJob(path) {
- redirectTo(path); // eslint-disable-line import/no-deprecated
- },
- runJob() {
- this.runBtnDisabled = true;
-
- if (this.isRetryable) {
- this.retryJob();
- } else {
- this.playJob();
- }
- },
- },
-};
-</script>
-<template>
- <gl-loading-icon v-if="$apollo.queries.variables.loading" class="gl-mt-9" size="lg" />
- <div v-else class="row gl-justify-content-center">
- <div class="col-10">
- <label>{{ $options.i18n.header }}</label>
-
- <div
- v-for="(variable, index) in variables"
- :key="variable.id"
- class="gl-display-flex gl-align-items-center gl-mb-5"
- data-testid="ci-variable-row"
- >
- <gl-form-input-group class="gl-mr-4 gl-flex-grow-1">
- <template #prepend>
- <gl-input-group-text>
- {{ $options.i18n.keyLabel }}
- </gl-input-group-text>
- </template>
- <gl-form-input
- :ref="inputRef('key', variable.id)"
- v-model="variable.key"
- :placeholder="$options.i18n.keyPlaceholder"
- data-testid="ci-variable-key"
- @change="addEmptyVariable"
- />
- </gl-form-input-group>
-
- <gl-form-input-group class="gl-flex-grow-2">
- <template #prepend>
- <gl-input-group-text>
- {{ $options.i18n.valueLabel }}
- </gl-input-group-text>
- </template>
- <gl-form-input
- :ref="inputRef('value', variable.id)"
- v-model="variable.value"
- :placeholder="$options.i18n.valuePlaceholder"
- data-testid="ci-variable-value"
- />
- </gl-form-input-group>
-
- <gl-button
- v-if="canRemove(index)"
- v-gl-tooltip
- :aria-label="$options.i18n.removeInputs"
- :title="$options.i18n.removeInputs"
- :class="$options.clearBtnSharedClasses"
- category="tertiary"
- icon="remove"
- data-testid="delete-variable-btn"
- @click="deleteVariable(variable.id)"
- />
- <!-- Placeholder button to keep the layout fixed -->
- <gl-button
- v-else
- class="gl-opacity-0 gl-pointer-events-none"
- :class="$options.clearBtnSharedClasses"
- data-testid="delete-variable-btn-placeholder"
- category="tertiary"
- icon="remove"
- />
- </div>
-
- <div class="gl-text-center gl-mt-5">
- <gl-sprintf :message="$options.i18n.formHelpText">
- <template #link="{ content }">
- <gl-link :href="variableSettings" target="_blank">
- {{ content }}
- </gl-link>
- </template>
- </gl-sprintf>
- </div>
- <div class="gl-text-center gl-mt-3">
- <gl-sprintf :message="$options.i18n.overrideNoteText">
- <template #bold="{ content }">
- <strong>
- {{ content }}
- </strong>
- </template>
- </gl-sprintf>
- </div>
- <div class="gl-display-flex gl-justify-content-center gl-mt-5">
- <gl-button
- v-if="isRetryable"
- class="gl-mt-5"
- data-testid="cancel-btn"
- @click="$emit('hideManualVariablesForm')"
- >{{ $options.i18n.cancel }}</gl-button
- >
- <gl-button
- class="gl-mt-5"
- variant="confirm"
- category="primary"
- :disabled="runBtnDisabled"
- data-testid="run-manual-job-btn"
- @click="runJob"
- >
- {{ runBtnText }}
- </gl-button>
- </div>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue
deleted file mode 100644
index a78cacf110f..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/artifacts_block.vue
+++ /dev/null
@@ -1,121 +0,0 @@
-<script>
-import { GlButton, GlButtonGroup, GlIcon, GlLink, GlPopover } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-
-export default {
- i18n: {
- jobArtifacts: s__('Job|Job artifacts'),
- artifactsHelpText: s__(
- 'Job|Job artifacts are files that are configured to be uploaded when a job finishes execution. Artifacts could be compiled files, unit tests or scanning reports, or any other files generated by a job.',
- ),
- expiredText: s__('Job|The artifacts were removed'),
- willExpireText: s__('Job|The artifacts will be removed'),
- lockedText: s__(
- 'Job|These artifacts are the latest. They will not be deleted (even if expired) until newer artifacts are available.',
- ),
- keepText: s__('Job|Keep'),
- downloadText: s__('Job|Download'),
- browseText: s__('Job|Browse'),
- },
- artifactsHelpPath: helpPagePath('ci/jobs/job_artifacts'),
- components: {
- GlButton,
- GlButtonGroup,
- GlIcon,
- GlLink,
- GlPopover,
- TimeagoTooltip,
- },
- mixins: [timeagoMixin],
- props: {
- artifact: {
- type: Object,
- required: true,
- },
- helpUrl: {
- type: String,
- required: true,
- },
- },
- computed: {
- isExpired() {
- return this.artifact?.expired && !this.isLocked;
- },
- isLocked() {
- return this.artifact?.locked;
- },
- // Only when the key is `false` we can render this block
- willExpire() {
- return this.artifact?.expired === false && !this.isLocked;
- },
- },
-};
-</script>
-<template>
- <div>
- <div class="title gl-font-weight-bold">
- <span class="gl-mr-2">{{ $options.i18n.jobArtifacts }}</span>
- <gl-link :href="$options.artifactsHelpPath" data-testid="artifacts-help-link">
- <gl-icon id="artifacts-help" name="question-o" />
- </gl-link>
- <gl-popover
- target="artifacts-help"
- :title="$options.i18n.jobArtifacts"
- triggers="hover focus"
- >
- {{ $options.i18n.artifactsHelpText }}
- </gl-popover>
- </div>
- <p
- v-if="isExpired || willExpire"
- class="build-detail-row"
- data-testid="artifacts-remove-timeline"
- >
- <span v-if="isExpired">{{ $options.i18n.expiredText }}</span>
- <span v-if="willExpire" data-qa-selector="artifacts_unlocked_message_content">
- {{ $options.i18n.willExpireText }}
- </span>
- <timeago-tooltip v-if="artifact.expire_at" :time="artifact.expire_at" />
- <gl-link
- :href="helpUrl"
- target="_blank"
- rel="noopener noreferrer nofollow"
- data-testid="artifact-expired-help-link"
- >
- <gl-icon name="question-o" />
- </gl-link>
- </p>
- <p v-else-if="isLocked" class="build-detail-row">
- <span data-testid="job-locked-message" data-qa-selector="artifacts_locked_message_content">
- {{ $options.i18n.lockedText }}
- </span>
- </p>
- <gl-button-group class="gl-display-flex gl-mt-3">
- <gl-button
- v-if="artifact.keep_path"
- :href="artifact.keep_path"
- data-method="post"
- data-testid="keep-artifacts"
- >{{ $options.i18n.keepText }}</gl-button
- >
- <gl-button
- v-if="artifact.download_path"
- :href="artifact.download_path"
- rel="nofollow"
- data-testid="download-artifacts"
- download
- >{{ $options.i18n.downloadText }}</gl-button
- >
- <gl-button
- v-if="artifact.browse_path"
- :href="artifact.browse_path"
- data-testid="browse-artifacts"
- data-qa-selector="browse_artifacts_button"
- >{{ $options.i18n.browseText }}</gl-button
- >
- </gl-button-group>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue
deleted file mode 100644
index 7f25ca8a94d..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/commit_block.vue
+++ /dev/null
@@ -1,47 +0,0 @@
-<script>
-import { GlLink } from '@gitlab/ui';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-
-export default {
- components: {
- ClipboardButton,
- GlLink,
- },
- props: {
- commit: {
- type: Object,
- required: true,
- },
- mergeRequest: {
- type: Object,
- required: false,
- default: null,
- },
- },
-};
-</script>
-<template>
- <div>
- <span class="gl-font-weight-bold">{{ __('Commit') }}</span>
-
- <gl-link :href="commit.commit_path" class="gl-text-blue-600!" data-testid="commit-sha">
- {{ commit.short_id }}
- </gl-link>
-
- <clipboard-button
- :text="commit.id"
- :title="__('Copy commit SHA')"
- category="tertiary"
- size="small"
- />
-
- <span v-if="mergeRequest">
- {{ __('in') }}
- <gl-link :href="mergeRequest.path" class="gl-text-blue-600!" data-testid="link-commit"
- >!{{ mergeRequest.iid }}</gl-link
- >
- </span>
-
- <p class="gl-mb-0">{{ commit.title }}</p>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue b/app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue
deleted file mode 100644
index 097ab3b4cf6..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/job_container_item.vue
+++ /dev/null
@@ -1,77 +0,0 @@
-<script>
-import { GlLink, GlIcon, GlTooltipDirective } from '@gitlab/ui';
-import delayedJobMixin from '~/jobs/mixins/delayed_job_mixin';
-import { sprintf } from '~/locale';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-
-export default {
- components: {
- CiIcon,
- GlIcon,
- GlLink,
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- mixins: [delayedJobMixin],
- props: {
- job: {
- type: Object,
- required: true,
- },
- isActive: {
- type: Boolean,
- required: true,
- },
- },
- computed: {
- tooltipText() {
- const { name, status } = this.job;
- const text = `${name} - ${status.tooltip}`;
-
- if (this.isDelayedJob) {
- return sprintf(text, { remainingTime: this.remainingTime });
- }
-
- return text;
- },
- jobName() {
- return this.job.name ? this.job.name : this.job.id;
- },
- classes() {
- return {
- retried: this.job.retried,
- 'gl-font-weight-bold': this.isActive,
- };
- },
- dataTestId() {
- return this.isActive ? 'active-job' : null;
- },
- },
-};
-</script>
-
-<template>
- <div class="build-job gl-relative" :class="classes">
- <gl-link
- v-gl-tooltip.left.viewport
- :href="job.status.details_path"
- :title="tooltipText"
- class="gl-display-flex gl-align-items-center"
- :data-testid="dataTestId"
- >
- <gl-icon
- v-if="isActive"
- name="arrow-right"
- class="icon-arrow-right gl-absolute gl-display-block"
- :size="14"
- />
-
- <ci-icon :status="job.status" class="gl-mr-2" :size="14" />
-
- <span class="gl-text-truncate gl-w-full">{{ jobName }}</span>
-
- <gl-icon v-if="job.retried" name="retry" />
- </gl-link>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue b/app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue
deleted file mode 100644
index a3f1a2c4be8..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/job_retry_forward_deployment_modal.vue
+++ /dev/null
@@ -1,64 +0,0 @@
-<script>
-import { GlLink, GlModal } from '@gitlab/ui';
-import { JOB_RETRY_FORWARD_DEPLOYMENT_MODAL } from '~/jobs/constants';
-
-export default {
- name: 'JobRetryForwardDeploymentModal',
- components: {
- GlLink,
- GlModal,
- },
- i18n: {
- ...JOB_RETRY_FORWARD_DEPLOYMENT_MODAL,
- },
- inject: {
- retryOutdatedJobDocsUrl: {
- default: '',
- },
- },
- props: {
- modalId: {
- type: String,
- required: true,
- },
- href: {
- type: String,
- required: true,
- },
- },
- data() {
- return {
- primaryProps: {
- text: this.$options.i18n.primaryText,
- attributes: {
- 'data-method': 'post',
- 'data-testid': 'retry-button-modal',
- href: this.href,
- variant: 'danger',
- },
- },
- cancelProps: {
- text: this.$options.i18n.cancel,
- attributes: { category: 'secondary', variant: 'default' },
- },
- };
- },
-};
-</script>
-
-<template>
- <gl-modal
- :action-cancel="cancelProps"
- :action-primary="primaryProps"
- :modal-id="modalId"
- :title="$options.i18n.title"
- >
- <p>
- {{ $options.i18n.info }}
- <gl-link v-if="retryOutdatedJobDocsUrl" :href="retryOutdatedJobDocsUrl" target="_blank">
- {{ $options.i18n.moreInfo }}
- </gl-link>
- </p>
- <p>{{ $options.i18n.areYouSure }}</p>
- </gl-modal>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue b/app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue
deleted file mode 100644
index 87c47f592aa..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/job_sidebar_retry_button.vue
+++ /dev/null
@@ -1,81 +0,0 @@
-<script>
-import { GlButton, GlDisclosureDropdown, GlModalDirective } from '@gitlab/ui';
-// eslint-disable-next-line no-restricted-imports
-import { mapGetters } from 'vuex';
-import { JOB_SIDEBAR_COPY } from '~/jobs/constants';
-
-export default {
- name: 'JobSidebarRetryButton',
- i18n: {
- ...JOB_SIDEBAR_COPY,
- },
- components: {
- GlButton,
- GlDisclosureDropdown,
- },
- directives: {
- GlModal: GlModalDirective,
- },
- props: {
- modalId: {
- type: String,
- required: true,
- },
- href: {
- type: String,
- required: true,
- },
- isManualJob: {
- type: Boolean,
- required: true,
- },
- },
- computed: {
- ...mapGetters(['hasForwardDeploymentFailure']),
- dropdownItems() {
- return [
- {
- text: this.$options.i18n.runAgainJobButtonLabel,
- href: this.href,
- extraAttrs: {
- 'data-method': 'post',
- },
- },
- {
- text: this.$options.i18n.updateVariables,
- action: () => this.$emit('updateVariablesClicked'),
- },
- ];
- },
- },
-};
-</script>
-<template>
- <gl-button
- v-if="hasForwardDeploymentFailure"
- v-gl-modal="modalId"
- :aria-label="$options.i18n.retryJobLabel"
- category="primary"
- variant="confirm"
- icon="retry"
- data-testid="retry-job-button"
- />
- <gl-disclosure-dropdown
- v-else-if="isManualJob"
- icon="retry"
- category="primary"
- placement="right"
- variant="confirm"
- :items="dropdownItems"
- />
- <gl-button
- v-else
- :href="href"
- :aria-label="$options.i18n.retryJobLabel"
- category="primary"
- variant="confirm"
- icon="retry"
- data-method="post"
- data-testid="retry-job-link"
- />
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue b/app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue
deleted file mode 100644
index df64b6422c7..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/jobs_container.vue
+++ /dev/null
@@ -1,35 +0,0 @@
-<script>
-import JobContainerItem from './job_container_item.vue';
-
-export default {
- components: {
- JobContainerItem,
- },
-
- props: {
- jobs: {
- type: Array,
- required: true,
- },
- jobId: {
- type: Number,
- required: true,
- },
- },
- methods: {
- isJobActive(currentJobId) {
- return this.jobId === currentJobId;
- },
- },
-};
-</script>
-<template>
- <div class="builds-container">
- <job-container-item
- v-for="job in jobs"
- :key="job.id"
- :job="job"
- :is-active="isJobActive(job.id)"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue
deleted file mode 100644
index 92e1557ada2..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar.vue
+++ /dev/null
@@ -1,154 +0,0 @@
-<script>
-import { GlButton, GlIcon } from '@gitlab/ui';
-import { isEmpty } from 'lodash';
-// eslint-disable-next-line no-restricted-imports
-import { mapActions, mapGetters, mapState } from 'vuex';
-import { JOB_SIDEBAR_COPY, forwardDeploymentFailureModalId } from '~/jobs/constants';
-import ArtifactsBlock from './artifacts_block.vue';
-import CommitBlock from './commit_block.vue';
-import JobsContainer from './jobs_container.vue';
-import JobRetryForwardDeploymentModal from './job_retry_forward_deployment_modal.vue';
-import JobSidebarDetailsContainer from './sidebar_job_details_container.vue';
-import SidebarHeader from './sidebar_header.vue';
-import StagesDropdown from './stages_dropdown.vue';
-import TriggerBlock from './trigger_block.vue';
-
-export default {
- name: 'JobSidebar',
- i18n: {
- ...JOB_SIDEBAR_COPY,
- },
- borderTopClass: ['gl-border-t-solid', 'gl-border-t-1', 'gl-border-t-gray-100'],
- forwardDeploymentFailureModalId,
- components: {
- ArtifactsBlock,
- CommitBlock,
- GlButton,
- GlIcon,
- JobsContainer,
- JobRetryForwardDeploymentModal,
- JobSidebarDetailsContainer,
- SidebarHeader,
- StagesDropdown,
- TriggerBlock,
- },
- props: {
- artifactHelpUrl: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- ...mapGetters(['hasForwardDeploymentFailure']),
- ...mapState(['job', 'stages', 'jobs', 'selectedStage']),
- hasArtifact() {
- // the artifact object will always have a locked property
- return Object.keys(this.job.artifact).length > 1;
- },
- hasTriggers() {
- return !isEmpty(this.job.trigger);
- },
- commit() {
- return this.job?.pipeline?.commit || {};
- },
- selectedStageData() {
- return this.stages.find((val) => val.name === this.selectedStage);
- },
- shouldShowJobRetryForwardDeploymentModal() {
- return this.job.retry_path && this.hasForwardDeploymentFailure;
- },
- },
- watch: {
- job(value, oldValue) {
- const hasNewStatus = value.status.text !== oldValue.status.text;
- const isCurrentStage = value?.stage === this.selectedStage;
-
- if (hasNewStatus && isCurrentStage) {
- this.fetchJobsForStage(this.selectedStageData);
- }
- },
- },
- methods: {
- ...mapActions(['fetchJobsForStage']),
- },
-};
-</script>
-<template>
- <aside class="right-sidebar build-sidebar" data-offset-top="101" data-spy="affix">
- <div class="sidebar-container">
- <div class="blocks-container">
- <sidebar-header
- :rest-job="job"
- :job-id="job.id"
- @updateVariables="$emit('updateVariables')"
- />
- <div
- v-if="job.terminal_path || job.new_issue_path"
- class="gl-py-5"
- :class="$options.borderTopClass"
- >
- <gl-button
- v-if="job.new_issue_path"
- :href="job.new_issue_path"
- category="secondary"
- variant="confirm"
- data-testid="job-new-issue"
- >
- {{ $options.i18n.newIssue }}
- </gl-button>
- <gl-button
- v-if="job.terminal_path"
- :href="job.terminal_path"
- target="_blank"
- data-testid="terminal-link"
- >
- {{ $options.i18n.debug }}
- <gl-icon name="external-link" />
- </gl-button>
- </div>
-
- <job-sidebar-details-container class="gl-py-5" :class="$options.borderTopClass" />
-
- <artifacts-block
- v-if="hasArtifact"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :artifact="job.artifact"
- :help-url="artifactHelpUrl"
- />
-
- <trigger-block
- v-if="hasTriggers"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :trigger="job.trigger"
- />
-
- <commit-block
- :commit="commit"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :merge-request="job.merge_request"
- />
-
- <stages-dropdown
- v-if="job.pipeline"
- class="gl-py-5"
- :class="$options.borderTopClass"
- :pipeline="job.pipeline"
- :selected-stage="selectedStage"
- :stages="stages"
- @requestSidebarStageDropdown="fetchJobsForStage"
- />
- </div>
-
- <jobs-container v-if="jobs.length" :job-id="job.id" :jobs="jobs" />
- </div>
- <job-retry-forward-deployment-modal
- v-if="shouldShowJobRetryForwardDeploymentModal"
- :modal-id="$options.forwardDeploymentFailureModalId"
- :href="job.retry_path"
- />
- </aside>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue
deleted file mode 100644
index 0ba34eafa58..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_detail_row.vue
+++ /dev/null
@@ -1,59 +0,0 @@
-<script>
-import { GlIcon, GlLink } from '@gitlab/ui';
-
-export default {
- name: 'SidebarDetailRow',
- components: {
- GlIcon,
- GlLink,
- },
- props: {
- title: {
- type: String,
- required: false,
- default: '',
- },
- value: {
- type: String,
- required: true,
- },
- helpUrl: {
- type: String,
- required: false,
- default: '',
- },
- path: {
- type: String,
- required: false,
- default: '',
- },
- },
- computed: {
- hasTitle() {
- return this.title.length > 0;
- },
- hasHelpURL() {
- return this.helpUrl.length > 0;
- },
- },
-};
-</script>
-<template>
- <p class="gl-display-flex gl-justify-content-space-between gl-mb-2">
- <span v-if="hasTitle">
- <b>{{ title }}:</b>
- <gl-link
- v-if="path"
- :href="path"
- class="gl-text-blue-600!"
- data-testid="job-sidebar-value-link"
- >
- {{ value }}
- </gl-link>
- <span v-else>{{ value }}</span>
- </span>
- <gl-link v-if="hasHelpURL" :href="helpUrl" target="_blank" data-testid="job-sidebar-help-link">
- <gl-icon name="question-o" />
- </gl-link>
- </p>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue
deleted file mode 100644
index 56fcd8738d7..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_header.vue
+++ /dev/null
@@ -1,146 +0,0 @@
-<script>
-import { GlButton, GlTooltipDirective } from '@gitlab/ui';
-// eslint-disable-next-line no-restricted-imports
-import { mapActions } from 'vuex';
-import { createAlert } from '~/alert';
-import { TYPENAME_COMMIT_STATUS } from '~/graphql_shared/constants';
-import { convertToGraphQLId } from '~/graphql_shared/utils';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
-import {
- JOB_GRAPHQL_ERRORS,
- JOB_SIDEBAR_COPY,
- forwardDeploymentFailureModalId,
- PASSED_STATUS,
-} from '~/jobs/constants';
-import GetJob from '../graphql/queries/get_job.query.graphql';
-import JobSidebarRetryButton from './job_sidebar_retry_button.vue';
-
-export default {
- name: 'SidebarHeader',
- i18n: {
- ...JOB_SIDEBAR_COPY,
- },
- forwardDeploymentFailureModalId,
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlButton,
- JobSidebarRetryButton,
- TooltipOnTruncate,
- },
- inject: ['projectPath'],
- apollo: {
- job: {
- query: GetJob,
- variables() {
- return {
- fullPath: this.projectPath,
- id: convertToGraphQLId(TYPENAME_COMMIT_STATUS, this.jobId),
- };
- },
- update(data) {
- const { name, manualJob } = data?.project?.job || {};
- return {
- name,
- manualJob,
- };
- },
- error() {
- createAlert({ message: JOB_GRAPHQL_ERRORS.jobQueryErrorText });
- },
- },
- },
- props: {
- jobId: {
- type: Number,
- required: true,
- },
- restJob: {
- type: Object,
- required: true,
- default: () => ({}),
- },
- },
- data() {
- return {
- job: {},
- };
- },
- computed: {
- buttonTitle() {
- return this.restJob.status?.text === PASSED_STATUS
- ? this.$options.i18n.runAgainJobButtonLabel
- : this.$options.i18n.retryJobLabel;
- },
- canShowJobRetryButton() {
- return this.restJob.retry_path && !this.$apollo.queries.job.loading;
- },
- isManualJob() {
- return this.job?.manualJob;
- },
- retryButtonCategory() {
- return this.restJob.status && this.restJob.recoverable ? 'primary' : 'secondary';
- },
- },
- methods: {
- ...mapActions(['toggleSidebar']),
- },
-};
-</script>
-
-<template>
- <div class="gl-py-5 gl-display-flex gl-align-items-center">
- <tooltip-on-truncate :title="job.name" truncate-target="child"
- ><h4 class="gl-my-0 gl-mr-3 gl-text-truncate" data-testid="job-name">{{ job.name }}</h4>
- </tooltip-on-truncate>
- <div class="gl-flex-grow-1 gl-flex-shrink-0 gl-text-right">
- <gl-button
- v-if="restJob.erase_path"
- v-gl-tooltip.left
- :title="$options.i18n.eraseLogButtonLabel"
- :aria-label="$options.i18n.eraseLogButtonLabel"
- :href="restJob.erase_path"
- :data-confirm="$options.i18n.eraseLogConfirmText"
- class="gl-mr-2"
- data-testid="job-log-erase-link"
- data-confirm-btn-variant="danger"
- data-method="post"
- icon="remove"
- />
- <job-sidebar-retry-button
- v-if="canShowJobRetryButton"
- v-gl-tooltip.left
- :title="buttonTitle"
- :aria-label="buttonTitle"
- :is-manual-job="isManualJob"
- :category="retryButtonCategory"
- :href="restJob.retry_path"
- :modal-id="$options.forwardDeploymentFailureModalId"
- variant="confirm"
- data-qa-selector="retry_button"
- data-testid="retry-button"
- @updateVariablesClicked="$emit('updateVariables')"
- />
- <gl-button
- v-if="restJob.cancel_path"
- v-gl-tooltip.left
- :title="$options.i18n.cancelJobButtonLabel"
- :aria-label="$options.i18n.cancelJobButtonLabel"
- :href="restJob.cancel_path"
- variant="danger"
- icon="cancel"
- data-method="post"
- data-testid="cancel-button"
- rel="nofollow"
- />
- <gl-button
- :aria-label="$options.i18n.toggleSidebar"
- category="tertiary"
- class="gl-md-display-none gl-ml-2"
- icon="chevron-double-lg-right"
- @click="toggleSidebar"
- />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue b/app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue
deleted file mode 100644
index 09335476008..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/sidebar_job_details_container.vue
+++ /dev/null
@@ -1,124 +0,0 @@
-<script>
-// eslint-disable-next-line no-restricted-imports
-import { mapState } from 'vuex';
-import { GlBadge } from '@gitlab/ui';
-import { helpPagePath } from '~/helpers/help_page_helper';
-import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
-import { __, sprintf } from '~/locale';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-import DetailRow from './sidebar_detail_row.vue';
-
-export default {
- name: 'JobSidebarDetailsContainer',
- components: {
- DetailRow,
- GlBadge,
- },
- mixins: [timeagoMixin],
- computed: {
- ...mapState(['job']),
- coverage() {
- return `${this.job.coverage}%`;
- },
- duration() {
- return timeIntervalInWords(this.job.duration);
- },
- durationTitle() {
- return this.job.finished_at ? __('Duration') : __('Elapsed time');
- },
- erasedAt() {
- return this.timeFormatted(this.job.erased_at);
- },
- finishedAt() {
- return this.timeFormatted(this.job.finished_at);
- },
- hasTags() {
- return this.job?.tags?.length;
- },
- hasTimeout() {
- return this.job?.metadata?.timeout_human_readable ?? false;
- },
- hasAnyDetail() {
- return Boolean(
- this.job.duration ||
- this.job.finished_at ||
- this.job.erased_at ||
- this.job.queued_duration ||
- this.job.runner ||
- this.job.coverage,
- );
- },
- runnerId() {
- const { id, short_sha: token, description } = this.job.runner;
-
- return `#${id} (${token}) ${description}`;
- },
- queuedDuration() {
- return timeIntervalInWords(this.job.queued_duration);
- },
- shouldRenderBlock() {
- return Boolean(this.hasAnyDetail || this.hasTimeout || this.hasTags);
- },
- timeout() {
- return `${this.job?.metadata?.timeout_human_readable}${this.timeoutSource}`;
- },
- timeoutSource() {
- if (!this.job?.metadata?.timeout_source) {
- return '';
- }
-
- return sprintf(__(' (from %{timeoutSource})'), {
- timeoutSource: this.job.metadata.timeout_source,
- });
- },
- runnerAdminPath() {
- return this.job?.runner?.admin_path || '';
- },
- },
- i18n: {
- COVERAGE: __('Coverage'),
- FINISHED: __('Finished'),
- ERASED: __('Erased'),
- QUEUED: __('Queued'),
- RUNNER: __('Runner'),
- TAGS: __('Tags:'),
- TIMEOUT: __('Timeout'),
- },
- TIMEOUT_HELP_URL: helpPagePath('/ci/pipelines/settings.md', {
- anchor: 'set-a-limit-for-how-long-jobs-can-run',
- }),
-};
-</script>
-
-<template>
- <div v-if="shouldRenderBlock">
- <detail-row v-if="job.duration" :value="duration" :title="durationTitle" />
- <detail-row
- v-if="job.finished_at"
- :value="finishedAt"
- data-testid="job-finished"
- :title="$options.i18n.FINISHED"
- />
- <detail-row v-if="job.erased_at" :value="erasedAt" :title="$options.i18n.ERASED" />
- <detail-row v-if="job.queued_duration" :value="queuedDuration" :title="$options.i18n.QUEUED" />
- <detail-row
- v-if="hasTimeout"
- :help-url="$options.TIMEOUT_HELP_URL"
- :value="timeout"
- data-testid="job-timeout"
- :title="$options.i18n.TIMEOUT"
- />
- <detail-row
- v-if="job.runner"
- :value="runnerId"
- :title="$options.i18n.RUNNER"
- :path="runnerAdminPath"
- />
- <detail-row v-if="job.coverage" :value="coverage" :title="$options.i18n.COVERAGE" />
-
- <p v-if="hasTags" class="build-detail-row" data-testid="job-tags">
- <span class="font-weight-bold">{{ $options.i18n.TAGS }}</span>
- <gl-badge v-for="(tag, i) in job.tags" :key="i" variant="info">{{ tag }}</gl-badge>
- </p>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue b/app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue
deleted file mode 100644
index c1f84adf664..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/stages_dropdown.vue
+++ /dev/null
@@ -1,171 +0,0 @@
-<script>
-import { GlLink, GlDisclosureDropdown, GlSprintf } from '@gitlab/ui';
-import { isEmpty } from 'lodash';
-import { Mousetrap } from '~/lib/mousetrap';
-import { s__ } from '~/locale';
-import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import { clickCopyToClipboardButton } from '~/behaviors/copy_to_clipboard';
-import { keysFor, MR_COPY_SOURCE_BRANCH_NAME } from '~/behaviors/shortcuts/keybindings';
-
-export default {
- components: {
- CiIcon,
- ClipboardButton,
- GlDisclosureDropdown,
- GlLink,
- GlSprintf,
- },
- props: {
- pipeline: {
- type: Object,
- required: true,
- },
- stages: {
- type: Array,
- required: true,
- },
- selectedStage: {
- type: String,
- required: true,
- },
- },
- computed: {
- dropdownItems() {
- return this.stages.map((stage) => ({
- text: stage.name,
- action: () => {
- this.onStageClick(stage);
- },
- }));
- },
-
- hasRef() {
- return !isEmpty(this.pipeline.ref);
- },
- isTriggeredByMergeRequest() {
- return Boolean(this.pipeline.merge_request);
- },
- isMergeRequestPipeline() {
- return Boolean(this.pipeline.flags && this.pipeline.flags.merge_request_pipeline);
- },
- pipelineInfo() {
- if (!this.hasRef) {
- return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id}');
- } else if (!this.isTriggeredByMergeRequest) {
- return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{ref}');
- } else if (!this.isMergeRequestPipeline) {
- return s__('Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source}');
- }
-
- return s__(
- 'Job|%{boldStart}Pipeline%{boldEnd} %{id} for %{mrId} with %{source} into %{target}',
- );
- },
- },
- mounted() {
- Mousetrap.bind(keysFor(MR_COPY_SOURCE_BRANCH_NAME), this.handleKeyboardCopy);
- },
- beforeDestroy() {
- Mousetrap.unbind(keysFor(MR_COPY_SOURCE_BRANCH_NAME));
- },
- methods: {
- onStageClick(stage) {
- this.$emit('requestSidebarStageDropdown', stage);
- },
- handleKeyboardCopy() {
- let button;
-
- if (!this.hasRef) {
- return;
- } else if (!this.isTriggeredByMergeRequest) {
- button = this.$refs['copy-source-ref-link'];
- } else {
- button = this.$refs['copy-source-branch-link'];
- }
-
- clickCopyToClipboardButton(button.$el);
- },
- },
-};
-</script>
-<template>
- <div class="dropdown">
- <div class="js-pipeline-info" data-testid="pipeline-info">
- <ci-icon :status="pipeline.details.status" />
- <gl-sprintf :message="pipelineInfo">
- <template #bold="{ content }">
- <span class="font-weight-bold">{{ content }}</span>
- </template>
- <template #id>
- <gl-link
- :href="pipeline.path"
- class="js-pipeline-path link-commit"
- data-testid="pipeline-path"
- data-qa-selector="pipeline_path"
- >#{{ pipeline.id }}</gl-link
- >
- </template>
- <template #mrId>
- <gl-link
- :href="pipeline.merge_request.path"
- class="link-commit ref-name"
- data-testid="mr-link"
- >!{{ pipeline.merge_request.iid }}</gl-link
- >
- </template>
- <template #ref>
- <gl-link
- :href="pipeline.ref.path"
- class="link-commit ref-name"
- data-testid="source-ref-link"
- >{{ pipeline.ref.name }}</gl-link
- ><clipboard-button
- ref="copy-source-ref-link"
- :text="pipeline.ref.name"
- :title="__('Copy reference')"
- category="tertiary"
- size="small"
- data-testid="copy-source-ref-link"
- />
- </template>
- <template #source>
- <gl-link
- :href="pipeline.merge_request.source_branch_path"
- class="link-commit ref-name"
- data-testid="source-branch-link"
- >{{ pipeline.merge_request.source_branch }}</gl-link
- ><clipboard-button
- ref="copy-source-branch-link"
- :text="pipeline.merge_request.source_branch"
- :title="__('Copy branch name')"
- category="tertiary"
- size="small"
- data-testid="copy-source-branch-link"
- />
- </template>
- <template #target>
- <gl-link
- :href="pipeline.merge_request.target_branch_path"
- class="link-commit ref-name"
- data-testid="target-branch-link"
- >{{ pipeline.merge_request.target_branch }}</gl-link
- ><clipboard-button
- :text="pipeline.merge_request.target_branch"
- :title="__('Copy branch name')"
- category="tertiary"
- size="small"
- data-testid="copy-target-branch-link"
- />
- </template>
- </gl-sprintf>
- </div>
-
- <gl-disclosure-dropdown
- :toggle-text="selectedStage"
- :items="dropdownItems"
- block
- class="gl-mt-3"
- />
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue b/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue
deleted file mode 100644
index c9172fe0322..00000000000
--- a/app/assets/javascripts/jobs/components/job/sidebar/trigger_block.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-<script>
-import { GlButton, GlTableLite } from '@gitlab/ui';
-import { __ } from '~/locale';
-
-const DEFAULT_TD_CLASSES = 'gl-font-sm!';
-
-export default {
- fields: [
- {
- key: 'key',
- label: __('Key'),
- tdAttr: { 'data-testid': 'trigger-build-key' },
- tdClass: DEFAULT_TD_CLASSES,
- },
- {
- key: 'value',
- label: __('Value'),
- tdAttr: { 'data-testid': 'trigger-build-value' },
- tdClass: DEFAULT_TD_CLASSES,
- },
- ],
- components: {
- GlButton,
- GlTableLite,
- },
- props: {
- trigger: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- showVariableValues: false,
- };
- },
- computed: {
- hasVariables() {
- return this.trigger.variables.length > 0;
- },
- getToggleButtonText() {
- return this.showVariableValues ? __('Hide values') : __('Reveal values');
- },
- hasValues() {
- return this.trigger.variables.some((v) => v.value);
- },
- },
- methods: {
- toggleValues() {
- this.showVariableValues = !this.showVariableValues;
- },
- getDisplayValue(value) {
- return this.showVariableValues ? value : '••••••';
- },
- },
-};
-</script>
-
-<template>
- <div>
- <p
- v-if="trigger.short_token"
- :class="{ 'gl-mb-2': hasVariables, 'gl-mb-0': !hasVariables }"
- data-testid="trigger-short-token"
- >
- <span class="gl-font-weight-bold">{{ __('Trigger token:') }}</span> {{ trigger.short_token }}
- </p>
-
- <template v-if="hasVariables">
- <p class="gl-display-flex gl-justify-content-space-between gl-align-items-center">
- <span class="gl-font-weight-bold">{{ __('Trigger variables:') }}</span>
-
- <gl-button
- v-if="hasValues"
- class="gl-mt-2"
- size="small"
- data-testid="trigger-reveal-values-button"
- @click="toggleValues"
- >{{ getToggleButtonText }}</gl-button
- >
- </p>
-
- <gl-table-lite :items="trigger.variables" :fields="$options.fields" small bordered fixed>
- <template #cell(key)="{ item }">
- <span class="gl-overflow-break-word">{{ item.key }}</span>
- </template>
-
- <template #cell(value)="data">
- <span class="gl-overflow-break-word">{{ getDisplayValue(data.value) }}</span>
- </template>
- </gl-table-lite>
- </template>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/stuck_block.vue b/app/assets/javascripts/jobs/components/job/stuck_block.vue
deleted file mode 100644
index 1a678ce69a8..00000000000
--- a/app/assets/javascripts/jobs/components/job/stuck_block.vue
+++ /dev/null
@@ -1,90 +0,0 @@
-<script>
-import { GlAlert, GlBadge, GlLink, GlSprintf } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import { DOCS_URL } from 'jh_else_ce/lib/utils/url_utility';
-/**
- * Renders Stuck Runners block for job's view.
- */
-export default {
- components: {
- GlAlert,
- GlBadge,
- GlLink,
- GlSprintf,
- },
- props: {
- hasOfflineRunnersForProject: {
- type: Boolean,
- required: true,
- },
- tags: {
- type: Array,
- required: false,
- default: () => [],
- },
- runnersPath: {
- type: String,
- required: true,
- },
- },
- computed: {
- hasNoRunnersWithCorrespondingTags() {
- return this.tags.length > 0;
- },
- protectedBranchSettingsDocsLink() {
- return `${DOCS_URL}/runner/security/index.html#reduce-the-security-risk-of-using-privileged-containers`;
- },
- stuckData() {
- if (this.hasNoRunnersWithCorrespondingTags) {
- return {
- text: s__(
- `Job|This job is stuck because of one of the following problems. There are no active runners online, no runners for the %{linkStart}protected branch%{linkEnd}, or no runners that match all of the job's tags:`,
- ),
- dataTestId: 'job-stuck-with-tags',
- showTags: true,
- };
- } else if (this.hasOfflineRunnersForProject) {
- return {
- text: s__(`Job|This job is stuck because the project
- doesn't have any runners online assigned to it.`),
- dataTestId: 'job-stuck-no-runners',
- showTags: false,
- };
- }
-
- return {
- text: s__(`Job|This job is stuck because you don't
- have any active runners that can run this job.`),
- dataTestId: 'job-stuck-no-active-runners',
- showTags: false,
- };
- },
- },
-};
-</script>
-<template>
- <gl-alert variant="warning" :dismissible="false">
- <p class="gl-mb-0" :data-testid="stuckData.dataTestId">
- <gl-sprintf :message="stuckData.text">
- <template #link="{ content }">
- <a
- class="gl-display-inline-block"
- :href="protectedBranchSettingsDocsLink"
- target="_blank"
- >
- {{ content }}
- </a>
- </template>
- </gl-sprintf>
- <template v-if="stuckData.showTags">
- <gl-badge v-for="tag in tags" :key="tag" variant="info">
- {{ tag }}
- </gl-badge>
- </template>
- </p>
- {{ __('Go to project') }}
- <gl-link v-if="runnersPath" :href="runnersPath">
- {{ __('CI settings') }}
- </gl-link>
- </gl-alert>
-</template>
diff --git a/app/assets/javascripts/jobs/components/job/unmet_prerequisites_block.vue b/app/assets/javascripts/jobs/components/job/unmet_prerequisites_block.vue
deleted file mode 100644
index c9747ca9f02..00000000000
--- a/app/assets/javascripts/jobs/components/job/unmet_prerequisites_block.vue
+++ /dev/null
@@ -1,33 +0,0 @@
-<script>
-import { GlLink, GlAlert } from '@gitlab/ui';
-import { __, s__ } from '~/locale';
-/**
- * Renders Unmet Prerequisites block for job's view.
- */
-export default {
- i18n: {
- failMessage: s__(
- 'Job|This job failed because the necessary resources were not successfully created.',
- ),
- moreInformation: __('More information'),
- },
- components: {
- GlLink,
- GlAlert,
- },
- props: {
- helpPath: {
- type: String,
- required: true,
- },
- },
-};
-</script>
-<template>
- <gl-alert variant="danger" class="gl-mt-3" :dismissible="false">
- {{ $options.i18n.failMessage }}
- <gl-link :href="helpPath">
- {{ $options.i18n.moreInformation }}
- </gl-link>
- </gl-alert>
-</template>