diff options
Diffstat (limited to 'app/assets/javascripts/jobs/components/job')
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> |