summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/jobs/components
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/jobs/components')
-rw-r--r--app/assets/javascripts/jobs/components/job_log_controllers.vue2
-rw-r--r--app/assets/javascripts/jobs/components/sidebar.vue2
-rw-r--r--app/assets/javascripts/jobs/components/sidebar_job_details_container.vue5
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/actions_cell.vue16
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue10
-rw-r--r--app/assets/javascripts/jobs/components/table/constants.js67
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql7
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table.vue69
8 files changed, 107 insertions, 71 deletions
diff --git a/app/assets/javascripts/jobs/components/job_log_controllers.vue b/app/assets/javascripts/jobs/components/job_log_controllers.vue
index 6105299e15c..97141a27a5e 100644
--- a/app/assets/javascripts/jobs/components/job_log_controllers.vue
+++ b/app/assets/javascripts/jobs/components/job_log_controllers.vue
@@ -5,7 +5,7 @@ import { __, s__, sprintf } from '~/locale';
export default {
i18n: {
- eraseLogButtonLabel: s__('Job|Erase job log'),
+ eraseLogButtonLabel: s__('Job|Erase job log and artifacts'),
scrollToBottomButtonLabel: s__('Job|Scroll to bottom'),
scrollToTopButtonLabel: s__('Job|Scroll to top'),
showRawButtonLabel: s__('Job|Show complete raw'),
diff --git a/app/assets/javascripts/jobs/components/sidebar.vue b/app/assets/javascripts/jobs/components/sidebar.vue
index 1b50006239c..9aa1503c7c3 100644
--- a/app/assets/javascripts/jobs/components/sidebar.vue
+++ b/app/assets/javascripts/jobs/components/sidebar.vue
@@ -2,7 +2,7 @@
import { GlButton, GlIcon } from '@gitlab/ui';
import { isEmpty } from 'lodash';
import { mapActions, mapGetters, mapState } from 'vuex';
-import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate.vue';
+import TooltipOnTruncate from '~/vue_shared/components/tooltip_on_truncate/tooltip_on_truncate.vue';
import { JOB_SIDEBAR } from '../constants';
import ArtifactsBlock from './artifacts_block.vue';
import CommitBlock from './commit_block.vue';
diff --git a/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue b/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
index d90377029c5..5451cd21c14 100644
--- a/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
+++ b/app/assets/javascripts/jobs/components/sidebar_job_details_container.vue
@@ -20,6 +20,9 @@ export default {
duration() {
return timeIntervalInWords(this.job.duration);
},
+ durationTitle() {
+ return this.job.finished_at ? __('Duration') : __('Elapsed time');
+ },
erasedAt() {
return this.timeFormatted(this.job.erased_at);
},
@@ -76,7 +79,7 @@ export default {
<template>
<div v-if="shouldRenderBlock">
- <detail-row v-if="job.duration" :value="duration" title="Duration" />
+ <detail-row v-if="job.duration" :value="duration" :title="durationTitle" />
<detail-row
v-if="job.finished_at"
:value="finishedAt"
diff --git a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
index 51251c0cacc..7dfa963a857 100644
--- a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
+++ b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
@@ -12,6 +12,7 @@ import {
JOB_SCHEDULED,
PLAY_JOB_CONFIRMATION_MESSAGE,
RUN_JOB_NOW_HEADER_TITLE,
+ FILE_TYPE_ARCHIVE,
} from '../constants';
import eventHub from '../event_hub';
import cancelJobMutation from '../graphql/mutations/job_cancel.mutation.graphql';
@@ -58,12 +59,21 @@ export default {
},
},
computed: {
+ hasArtifacts() {
+ return this.job.artifacts.nodes.find((artifact) => artifact.fileType === FILE_TYPE_ARCHIVE);
+ },
artifactDownloadPath() {
- return this.job.artifacts?.nodes[0]?.downloadPath;
+ return this.hasArtifacts.downloadPath;
},
canReadJob() {
return this.job.userPermissions?.readBuild;
},
+ canUpdateJob() {
+ return this.job.userPermissions?.updateBuild;
+ },
+ canReadArtifacts() {
+ return this.job.userPermissions?.readJobArtifacts;
+ },
isActive() {
return this.job.active;
},
@@ -86,7 +96,7 @@ export default {
return this.job.detailedStatus?.action?.method;
},
shouldDisplayArtifacts() {
- return this.job.userPermissions?.readJobArtifacts && this.job.artifacts?.nodes.length > 0;
+ return this.canReadArtifacts && this.hasArtifacts;
},
},
methods: {
@@ -139,7 +149,7 @@ export default {
<template>
<gl-button-group>
- <template v-if="canReadJob">
+ <template v-if="canReadJob && canUpdateJob">
<gl-button
v-if="isActive"
data-testid="cancel-button"
diff --git a/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue b/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue
index 71f9397f5f5..1a6d1a341b0 100644
--- a/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue
+++ b/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue
@@ -35,10 +35,12 @@ export default {
</script>
<template>
- <div class="gl-text-truncate">
- <gl-link class="gl-text-gray-500!" :href="pipelinePath" data-testid="pipeline-id">
- {{ pipelineId }}
- </gl-link>
+ <div>
+ <div class="gl-text-truncate">
+ <gl-link class="gl-text-gray-500!" :href="pipelinePath" data-testid="pipeline-id">
+ {{ pipelineId }}
+ </gl-link>
+ </div>
<div>
<span>{{ __('created by') }}</span>
<gl-link v-if="showAvatar" :href="userPath" data-testid="pipeline-user-link">
diff --git a/app/assets/javascripts/jobs/components/table/constants.js b/app/assets/javascripts/jobs/components/table/constants.js
index e5d1bc01cbf..962979ba573 100644
--- a/app/assets/javascripts/jobs/components/table/constants.js
+++ b/app/assets/javascripts/jobs/components/table/constants.js
@@ -1,4 +1,5 @@
import { s__, __ } from '~/locale';
+import { DEFAULT_TH_CLASSES } from '~/lib/utils/constants';
export const GRAPHQL_PAGE_SIZE = 30;
@@ -17,6 +18,9 @@ export const DEFAULT = 'default';
/* Job Status Constants */
export const JOB_SCHEDULED = 'SCHEDULED';
+/* Artifact file types */
+export const FILE_TYPE_ARCHIVE = 'ARCHIVE';
+
/* i18n */
export const ACTIONS_DOWNLOAD_ARTIFACTS = __('Download artifacts');
export const ACTIONS_START_NOW = s__('DelayedJobs|Start now');
@@ -30,3 +34,66 @@ export const PLAY_JOB_CONFIRMATION_MESSAGE = s__(
`DelayedJobs|Are you sure you want to run %{job_name} immediately? This job will run automatically after its timer finishes.`,
);
export const RUN_JOB_NOW_HEADER_TITLE = s__('DelayedJobs|Run the delayed job now?');
+
+/* Table constants */
+
+const defaultTableClasses = {
+ tdClass: 'gl-p-5!',
+ thClass: DEFAULT_TH_CLASSES,
+};
+// eslint-disable-next-line @gitlab/require-i18n-strings
+const coverageTdClasses = `${defaultTableClasses.tdClass} gl-display-none! gl-lg-display-table-cell!`;
+
+export const DEFAULT_FIELDS = [
+ {
+ key: 'status',
+ label: __('Status'),
+ ...defaultTableClasses,
+ columnClass: 'gl-w-10p',
+ },
+ {
+ key: 'job',
+ label: __('Job'),
+ ...defaultTableClasses,
+ columnClass: 'gl-w-20p',
+ },
+ {
+ key: 'pipeline',
+ label: __('Pipeline'),
+ ...defaultTableClasses,
+ columnClass: 'gl-w-10p',
+ },
+ {
+ key: 'stage',
+ label: __('Stage'),
+ ...defaultTableClasses,
+ columnClass: 'gl-w-10p',
+ },
+ {
+ key: 'name',
+ label: __('Name'),
+ ...defaultTableClasses,
+ columnClass: 'gl-w-15p',
+ },
+ {
+ key: 'duration',
+ label: __('Duration'),
+ ...defaultTableClasses,
+ columnClass: 'gl-w-15p',
+ },
+ {
+ key: 'coverage',
+ label: __('Coverage'),
+ tdClass: coverageTdClasses,
+ thClass: defaultTableClasses.thClass,
+ columnClass: 'gl-w-10p',
+ },
+ {
+ key: 'actions',
+ label: '',
+ ...defaultTableClasses,
+ columnClass: 'gl-w-10p',
+ },
+];
+
+export const JOBS_TAB_FIELDS = DEFAULT_FIELDS.filter((field) => field.key !== 'pipeline');
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
index c8763d4767e..88937185a8c 100644
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
+++ b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
@@ -7,6 +7,7 @@ query getJobs(
$statuses: [CiJobStatus!]
) {
project(fullPath: $fullPath) {
+ id
jobs(after: $after, before: $before, first: $first, last: $last, statuses: $statuses) {
pageInfo {
endCursor
@@ -18,6 +19,7 @@ query getJobs(
artifacts {
nodes {
downloadPath
+ fileType
}
}
allowFailure
@@ -27,6 +29,7 @@ query getJobs(
triggered
createdByTag
detailedStatus {
+ id
detailsPath
group
icon
@@ -34,6 +37,7 @@ query getJobs(
text
tooltip
action {
+ id
buttonTitle
icon
method
@@ -51,11 +55,13 @@ query getJobs(
id
path
user {
+ id
webPath
avatarUrl
}
}
stage {
+ id
name
}
name
@@ -70,6 +76,7 @@ query getJobs(
userPermissions {
readBuild
readJobArtifacts
+ updateBuild
}
}
}
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table.vue b/app/assets/javascripts/jobs/components/table/jobs_table.vue
index 298c99c4162..f513d2090fa 100644
--- a/app/assets/javascripts/jobs/components/table/jobs_table.vue
+++ b/app/assets/javascripts/jobs/components/table/jobs_table.vue
@@ -1,75 +1,17 @@
<script>
import { GlTable } from '@gitlab/ui';
-import { DEFAULT_TH_CLASSES } from '~/lib/utils/constants';
-import { s__, __ } from '~/locale';
+import { s__ } from '~/locale';
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
import ActionsCell from './cells/actions_cell.vue';
import DurationCell from './cells/duration_cell.vue';
import JobCell from './cells/job_cell.vue';
import PipelineCell from './cells/pipeline_cell.vue';
-
-const defaultTableClasses = {
- tdClass: 'gl-p-5!',
- thClass: DEFAULT_TH_CLASSES,
-};
-// eslint-disable-next-line @gitlab/require-i18n-strings
-const coverageTdClasses = `${defaultTableClasses.tdClass} gl-display-none! gl-lg-display-table-cell!`;
+import { DEFAULT_FIELDS } from './constants';
export default {
i18n: {
emptyText: s__('Jobs|No jobs to show'),
},
- fields: [
- {
- key: 'status',
- label: __('Status'),
- ...defaultTableClasses,
- columnClass: 'gl-w-10p',
- },
- {
- key: 'job',
- label: __('Job'),
- ...defaultTableClasses,
- columnClass: 'gl-w-20p',
- },
- {
- key: 'pipeline',
- label: __('Pipeline'),
- ...defaultTableClasses,
- columnClass: 'gl-w-10p',
- },
- {
- key: 'stage',
- label: __('Stage'),
- ...defaultTableClasses,
- columnClass: 'gl-w-10p',
- },
- {
- key: 'name',
- label: __('Name'),
- ...defaultTableClasses,
- columnClass: 'gl-w-15p',
- },
- {
- key: 'duration',
- label: __('Duration'),
- ...defaultTableClasses,
- columnClass: 'gl-w-15p',
- },
- {
- key: 'coverage',
- label: __('Coverage'),
- tdClass: coverageTdClasses,
- thClass: defaultTableClasses.thClass,
- columnClass: 'gl-w-10p',
- },
- {
- key: 'actions',
- label: '',
- ...defaultTableClasses,
- columnClass: 'gl-w-10p',
- },
- ],
components: {
ActionsCell,
CiBadge,
@@ -83,6 +25,11 @@ export default {
type: Array,
required: true,
},
+ tableFields: {
+ type: Array,
+ required: false,
+ default: () => DEFAULT_FIELDS,
+ },
},
methods: {
formatCoverage(coverage) {
@@ -95,7 +42,7 @@ export default {
<template>
<gl-table
:items="jobs"
- :fields="$options.fields"
+ :fields="tableFields"
:tbody-tr-attr="{ 'data-testid': 'jobs-table-row' }"
:empty-text="$options.i18n.emptyText"
show-empty