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/table')
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/actions_cell.vue265
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/duration_cell.vue45
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/job_cell.vue171
-rw-r--r--app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue52
-rw-r--r--app/assets/javascripts/jobs/components/table/constants.js76
-rw-r--r--app/assets/javascripts/jobs/components/table/event_hub.js3
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/cache_config.js60
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql7
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql10
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql78
-rw-r--r--app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql8
-rw-r--r--app/assets/javascripts/jobs/components/table/index.js50
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table.vue112
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_app.vue238
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue35
-rw-r--r--app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue88
19 files changed, 0 insertions, 1328 deletions
diff --git a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue b/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
deleted file mode 100644
index d97f6f6ff8c..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/actions_cell.vue
+++ /dev/null
@@ -1,265 +0,0 @@
-<script>
-import {
- GlButton,
- GlButtonGroup,
- GlModal,
- GlModalDirective,
- GlSprintf,
- GlTooltipDirective,
-} from '@gitlab/ui';
-import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
-import {
- ACTIONS_DOWNLOAD_ARTIFACTS,
- ACTIONS_START_NOW,
- ACTIONS_UNSCHEDULE,
- ACTIONS_PLAY,
- ACTIONS_RETRY,
- ACTIONS_RUN_AGAIN,
- CANCEL,
- GENERIC_ERROR,
- JOB_SCHEDULED,
- JOB_SUCCESS,
- 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';
-import playJobMutation from '../graphql/mutations/job_play.mutation.graphql';
-import retryJobMutation from '../graphql/mutations/job_retry.mutation.graphql';
-import unscheduleJobMutation from '../graphql/mutations/job_unschedule.mutation.graphql';
-import { reportMessageToSentry } from '../../../utils';
-
-export default {
- ACTIONS_DOWNLOAD_ARTIFACTS,
- ACTIONS_START_NOW,
- ACTIONS_UNSCHEDULE,
- ACTIONS_PLAY,
- ACTIONS_RETRY,
- CANCEL,
- GENERIC_ERROR,
- PLAY_JOB_CONFIRMATION_MESSAGE,
- RUN_JOB_NOW_HEADER_TITLE,
- jobRetry: 'jobRetry',
- jobCancel: 'jobCancel',
- jobPlay: 'jobPlay',
- jobUnschedule: 'jobUnschedule',
- playJobModalId: 'play-job-modal',
- name: 'JobActionsCell',
- components: {
- GlButton,
- GlButtonGroup,
- GlCountdown,
- GlModal,
- GlSprintf,
- },
- directives: {
- GlModalDirective,
- GlTooltip: GlTooltipDirective,
- },
- inject: {
- admin: {
- default: false,
- },
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- data() {
- return {
- retryBtnDisabled: false,
- cancelBtnDisabled: false,
- playManualBtnDisabled: false,
- unscheduleBtnDisabled: false,
- };
- },
- computed: {
- hasArtifacts() {
- return this.job.artifacts.nodes.find((artifact) => artifact.fileType === FILE_TYPE_ARCHIVE);
- },
- artifactDownloadPath() {
- 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;
- },
- manualJobPlayable() {
- return this.job.playable && !this.admin && this.job.manualJob;
- },
- isRetryable() {
- return this.job.retryable;
- },
- isScheduled() {
- return this.job.status === JOB_SCHEDULED;
- },
- scheduledAt() {
- return this.job.scheduledAt;
- },
- currentJobActionPath() {
- return this.job.detailedStatus?.action?.path;
- },
- currentJobMethod() {
- return this.job.detailedStatus?.action?.method;
- },
- shouldDisplayArtifacts() {
- return this.canReadArtifacts && this.hasArtifacts;
- },
- retryButtonTitle() {
- return this.job.status === JOB_SUCCESS ? ACTIONS_RUN_AGAIN : ACTIONS_RETRY;
- },
- },
- methods: {
- async postJobAction(name, mutation, redirect = false) {
- try {
- const {
- data: {
- [name]: { errors, job },
- },
- } = await this.$apollo.mutate({
- mutation,
- variables: { id: this.job.id },
- });
- if (errors.length > 0) {
- reportMessageToSentry(this.$options.name, errors.join(', '), {});
- this.showToastMessage();
- } else if (redirect) {
- // Retry and Play actions redirect to job detail view
- // we don't need to refetch with jobActionPerformed event
- redirectTo(job.detailedStatus.detailsPath); // eslint-disable-line import/no-deprecated
- } else {
- eventHub.$emit('jobActionPerformed');
- }
- } catch (failure) {
- reportMessageToSentry(this.$options.name, failure, {});
- this.showToastMessage();
- }
- },
- showToastMessage() {
- const toastProps = {
- text: this.$options.GENERIC_ERROR,
- variant: 'danger',
- };
-
- this.$toast.show(toastProps.text, {
- variant: toastProps.variant,
- });
- },
- cancelJob() {
- this.cancelBtnDisabled = true;
-
- this.postJobAction(this.$options.jobCancel, cancelJobMutation);
- },
- retryJob() {
- this.retryBtnDisabled = true;
-
- this.postJobAction(this.$options.jobRetry, retryJobMutation, true);
- },
- playJob() {
- this.playManualBtnDisabled = true;
-
- this.postJobAction(this.$options.jobPlay, playJobMutation, true);
- },
- unscheduleJob() {
- this.unscheduleBtnDisabled = true;
-
- this.postJobAction(this.$options.jobUnschedule, unscheduleJobMutation);
- },
- },
-};
-</script>
-
-<template>
- <gl-button-group>
- <template v-if="canReadJob && canUpdateJob">
- <gl-button
- v-if="isActive"
- v-gl-tooltip
- icon="cancel"
- :title="$options.CANCEL"
- :aria-label="$options.CANCEL"
- :disabled="cancelBtnDisabled"
- data-testid="cancel-button"
- @click="cancelJob()"
- />
- <template v-else-if="isScheduled">
- <gl-button icon="planning" disabled data-testid="countdown">
- <gl-countdown :end-date-string="scheduledAt" />
- </gl-button>
- <gl-button
- v-gl-modal-directive="$options.playJobModalId"
- v-gl-tooltip
- icon="play"
- :title="$options.ACTIONS_START_NOW"
- :aria-label="$options.ACTIONS_START_NOW"
- data-testid="play-scheduled"
- />
- <gl-modal
- :modal-id="$options.playJobModalId"
- :title="$options.RUN_JOB_NOW_HEADER_TITLE"
- @primary="playJob()"
- >
- <gl-sprintf :message="$options.PLAY_JOB_CONFIRMATION_MESSAGE">
- <template #job_name>{{ job.name }}</template>
- </gl-sprintf>
- </gl-modal>
- <gl-button
- v-gl-tooltip
- icon="time-out"
- :title="$options.ACTIONS_UNSCHEDULE"
- :aria-label="$options.ACTIONS_UNSCHEDULE"
- :disabled="unscheduleBtnDisabled"
- data-testid="unschedule"
- @click="unscheduleJob()"
- />
- </template>
- <template v-else>
- <!--Note: This is the manual job play button -->
- <gl-button
- v-if="manualJobPlayable"
- v-gl-tooltip
- icon="play"
- :title="$options.ACTIONS_PLAY"
- :aria-label="$options.ACTIONS_PLAY"
- :disabled="playManualBtnDisabled"
- data-testid="play"
- @click="playJob()"
- />
- <gl-button
- v-else-if="isRetryable"
- v-gl-tooltip
- icon="retry"
- :title="retryButtonTitle"
- :aria-label="retryButtonTitle"
- :method="currentJobMethod"
- :disabled="retryBtnDisabled"
- data-testid="retry"
- @click="retryJob()"
- />
- </template>
- </template>
- <gl-button
- v-if="shouldDisplayArtifacts"
- v-gl-tooltip
- icon="download"
- :title="$options.ACTIONS_DOWNLOAD_ARTIFACTS"
- :aria-label="$options.ACTIONS_DOWNLOAD_ARTIFACTS"
- :href="artifactDownloadPath"
- rel="nofollow"
- download
- data-testid="download-artifacts"
- />
- </gl-button-group>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue b/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue
deleted file mode 100644
index 11593fa355a..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/duration_cell.vue
+++ /dev/null
@@ -1,45 +0,0 @@
-<script>
-import { GlIcon } from '@gitlab/ui';
-import { formatTime } from '~/lib/utils/datetime_utility';
-import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
-import timeagoMixin from '~/vue_shared/mixins/timeago';
-
-export default {
- iconSize: 12,
- components: {
- GlIcon,
- TimeAgoTooltip,
- },
- mixins: [timeagoMixin],
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- computed: {
- finishedTime() {
- return this.job?.finishedAt;
- },
- duration() {
- return this.job?.duration;
- },
- durationFormatted() {
- return formatTime(this.duration * 1000);
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div v-if="duration" data-testid="job-duration">
- <gl-icon name="timer" :size="$options.iconSize" data-testid="duration-icon" />
- {{ durationFormatted }}
- </div>
- <div v-if="finishedTime" data-testid="job-finished-time">
- <gl-icon name="calendar" :size="$options.iconSize" data-testid="finished-time-icon" />
- <time-ago-tooltip :time="finishedTime" />
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/cells/job_cell.vue b/app/assets/javascripts/jobs/components/table/cells/job_cell.vue
deleted file mode 100644
index 27d286fc766..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/job_cell.vue
+++ /dev/null
@@ -1,171 +0,0 @@
-<script>
-import { GlBadge, GlIcon, GlLink, GlTooltipDirective } from '@gitlab/ui';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-import { s__ } from '~/locale';
-import { SUCCESS_STATUS } from '../../../constants';
-
-export default {
- iconSize: 12,
- badgeSize: 'sm',
- i18n: {
- stuckText: s__('Jobs|Job is stuck. Check runners.'),
- },
- directives: {
- GlTooltip: GlTooltipDirective,
- },
- components: {
- GlBadge,
- GlIcon,
- GlLink,
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- computed: {
- jobId() {
- const id = getIdFromGraphQLId(this.job.id);
- return `#${id}`;
- },
- jobPath() {
- return this.job.detailedStatus?.detailsPath;
- },
- jobRef() {
- return this.job?.refName;
- },
- jobRefPath() {
- return this.job?.refPath;
- },
- jobTags() {
- return this.job.tags;
- },
- createdByTag() {
- return this.job.createdByTag;
- },
- triggered() {
- return this.job.triggered;
- },
- isManualJob() {
- return this.job.manualJob;
- },
- successfulJob() {
- return this.job.status === SUCCESS_STATUS;
- },
- showAllowedToFailBadge() {
- return this.job.allowFailure && !this.successfulJob;
- },
- isScheduledJob() {
- return Boolean(this.job.scheduledAt);
- },
- canReadJob() {
- return this.job?.userPermissions?.readBuild;
- },
- jobStuck() {
- return this.job?.stuck;
- },
- },
-};
-</script>
-
-<template>
- <div>
- <div class="gl-text-truncate gl-mb-2">
- <gl-link
- v-if="canReadJob"
- class="gl-text-blue-600!"
- :href="jobPath"
- data-testid="job-id-link"
- >
- {{ jobId }}
- </gl-link>
-
- <span v-else data-testid="job-id-limited-access">{{ jobId }}</span>
-
- <gl-icon
- v-if="jobStuck"
- v-gl-tooltip="$options.i18n.stuckText"
- name="warning"
- :size="$options.iconSize"
- data-testid="stuck-icon"
- />
-
- <div
- class="gl-display-flex gl-text-gray-700 gl-align-items-center gl-lg-justify-content-start gl-justify-content-end gl-mt-2"
- >
- <div
- v-if="jobRef"
- class="gl-px-2 gl-rounded-base gl-bg-gray-50 gl-max-w-15 gl-text-truncate"
- >
- <gl-icon
- v-if="createdByTag"
- name="label"
- :size="$options.iconSize"
- data-testid="label-icon"
- />
- <gl-icon v-else name="fork" :size="$options.iconSize" data-testid="fork-icon" />
- <gl-link
- class="gl-font-sm gl-font-monospace gl-text-gray-700 gl-hover-text-gray-900"
- :href="job.refPath"
- data-testid="job-ref"
- >{{ job.refName }}</gl-link
- >
- </div>
-
- <span v-else>{{ __('none') }}</span>
- <div class="gl-ml-2 gl-rounded-base gl-px-2 gl-bg-gray-50">
- <gl-icon class="gl-mx-2" name="commit" :size="$options.iconSize" />
- <gl-link
- class="gl-font-sm gl-font-monospace gl-text-gray-700 gl-hover-text-gray-900"
- :href="job.commitPath"
- data-testid="job-sha"
- >{{ job.shortSha }}</gl-link
- >
- </div>
- </div>
- </div>
-
- <div>
- <gl-badge
- v-for="tag in jobTags"
- :key="tag"
- variant="info"
- :size="$options.badgeSize"
- data-testid="job-tag-badge"
- >
- {{ tag }}
- </gl-badge>
-
- <gl-badge
- v-if="triggered"
- variant="info"
- :size="$options.badgeSize"
- data-testid="triggered-job-badge"
- >{{ s__('Job|triggered') }}
- </gl-badge>
- <gl-badge
- v-if="showAllowedToFailBadge"
- variant="warning"
- :size="$options.badgeSize"
- data-testid="fail-job-badge"
- >{{ s__('Job|allowed to fail') }}
- </gl-badge>
- <gl-badge
- v-if="isScheduledJob"
- variant="info"
- :size="$options.badgeSize"
- data-testid="delayed-job-badge"
- >{{ s__('Job|delayed') }}
- </gl-badge>
- <gl-badge
- v-if="isManualJob"
- variant="info"
- :size="$options.badgeSize"
- data-testid="manual-job-badge"
- >
- {{ s__('Job|manual') }}
- </gl-badge>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue b/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue
deleted file mode 100644
index 1a6d1a341b0..00000000000
--- a/app/assets/javascripts/jobs/components/table/cells/pipeline_cell.vue
+++ /dev/null
@@ -1,52 +0,0 @@
-<script>
-import { GlAvatar, GlLink } from '@gitlab/ui';
-import { getIdFromGraphQLId } from '~/graphql_shared/utils';
-
-export default {
- components: {
- GlAvatar,
- GlLink,
- },
- props: {
- job: {
- type: Object,
- required: true,
- },
- },
- computed: {
- pipelineId() {
- const id = getIdFromGraphQLId(this.job.pipeline.id);
- return `#${id}`;
- },
- pipelinePath() {
- return this.job.pipeline?.path;
- },
- pipelineUserAvatar() {
- return this.job.pipeline?.user?.avatarUrl;
- },
- userPath() {
- return this.job.pipeline?.user?.webPath;
- },
- showAvatar() {
- return this.job.pipeline?.user;
- },
- },
-};
-</script>
-
-<template>
- <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">
- <gl-avatar :src="pipelineUserAvatar" :size="16" />
- </gl-link>
- <span v-else>{{ __('API') }}</span>
- </div>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/constants.js b/app/assets/javascripts/jobs/components/table/constants.js
deleted file mode 100644
index 1b572e60c58..00000000000
--- a/app/assets/javascripts/jobs/components/table/constants.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import { s__, __ } from '~/locale';
-
-/* Error constants */
-export const DEFAULT = 'default';
-export const RAW_TEXT_WARNING = s__(
- 'Jobs|Raw text search is not currently supported for the jobs filtered search feature. Please use the available search tokens.',
-);
-
-/* Job Status Constants */
-export const JOB_SCHEDULED = 'SCHEDULED';
-export const JOB_SUCCESS = 'SUCCESS';
-
-/* 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');
-export const ACTIONS_UNSCHEDULE = s__('DelayedJobs|Unschedule');
-export const ACTIONS_PLAY = __('Play');
-export const ACTIONS_RETRY = __('Retry');
-export const ACTIONS_RUN_AGAIN = __('Run again');
-
-export const CANCEL = __('Cancel');
-export const GENERIC_ERROR = __('An error occurred while making the request.');
-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 */
-export const DEFAULT_FIELDS = [
- {
- key: 'status',
- label: __('Status'),
- columnClass: 'gl-w-10p',
- },
- {
- key: 'job',
- label: __('Job'),
- columnClass: 'gl-w-20p',
- },
- {
- key: 'pipeline',
- label: __('Pipeline'),
- columnClass: 'gl-w-10p',
- },
- {
- key: 'stage',
- label: __('Stage'),
- columnClass: 'gl-w-10p',
- },
- {
- key: 'name',
- label: __('Name'),
- columnClass: 'gl-w-15p',
- },
- {
- key: 'duration',
- label: __('Duration'),
- columnClass: 'gl-w-15p',
- },
- {
- key: 'coverage',
- label: __('Coverage'),
- tdClass: 'gl-display-none! gl-lg-display-table-cell!',
- columnClass: 'gl-w-10p',
- },
- {
- key: 'actions',
- label: '',
- 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/event_hub.js b/app/assets/javascripts/jobs/components/table/event_hub.js
deleted file mode 100644
index e31806ad199..00000000000
--- a/app/assets/javascripts/jobs/components/table/event_hub.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import createEventHub from '~/helpers/event_hub_factory';
-
-export default createEventHub();
diff --git a/app/assets/javascripts/jobs/components/table/graphql/cache_config.js b/app/assets/javascripts/jobs/components/table/graphql/cache_config.js
deleted file mode 100644
index 5390c023da4..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/cache_config.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import { isEqual } from 'lodash';
-
-export default {
- typePolicies: {
- Project: {
- fields: {
- jobs: {
- keyArgs: false,
- },
- },
- },
- CiJobConnection: {
- merge(existing = {}, incoming, { args = {} }) {
- if (incoming.nodes) {
- let nodes;
-
- const areNodesEqual = isEqual(existing.nodes, incoming.nodes);
- const statuses = Array.isArray(args.statuses) ? [...args.statuses] : args.statuses;
- const { pageInfo } = incoming;
-
- if (Object.keys(existing).length !== 0 && isEqual(existing?.statuses, args?.statuses)) {
- if (areNodesEqual) {
- if (incoming.pageInfo.hasNextPage) {
- nodes = [...existing.nodes, ...incoming.nodes];
- } else {
- nodes = [...incoming.nodes];
- }
- } else {
- if (!existing.pageInfo?.hasNextPage) {
- nodes = [...incoming.nodes];
-
- return {
- nodes,
- statuses,
- pageInfo,
- };
- }
-
- nodes = [...existing.nodes, ...incoming.nodes];
- }
- } else {
- nodes = [...incoming.nodes];
- }
-
- return {
- nodes,
- statuses,
- pageInfo,
- };
- }
-
- return {
- nodes: existing.nodes,
- pageInfo: existing.pageInfo,
- statuses: args.statuses,
- };
- },
- },
- },
-};
diff --git a/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql b/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql
deleted file mode 100644
index 3038216fdfc..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/fragments/job.fragment.graphql
+++ /dev/null
@@ -1,7 +0,0 @@
-fragment Job on CiJob {
- id
- detailedStatus {
- id
- detailsPath
- }
-}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql
deleted file mode 100644
index 20935514d51..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_cancel.mutation.graphql
+++ /dev/null
@@ -1,10 +0,0 @@
-#import "../fragments/job.fragment.graphql"
-
-mutation cancelJob($id: CiBuildID!) {
- jobCancel(input: { id: $id }) {
- job {
- ...Job
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql
deleted file mode 100644
index c94b045ac40..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_play.mutation.graphql
+++ /dev/null
@@ -1,10 +0,0 @@
-#import "../fragments/job.fragment.graphql"
-
-mutation playJob($id: CiBuildID!) {
- jobPlay(input: { id: $id }) {
- job {
- ...Job
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql
deleted file mode 100644
index 6e51f9a20fa..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_retry.mutation.graphql
+++ /dev/null
@@ -1,10 +0,0 @@
-#import "../fragments/job.fragment.graphql"
-
-mutation retryJob($id: CiBuildID!) {
- jobRetry(input: { id: $id }) {
- job {
- ...Job
- }
- errors
- }
-}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql b/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql
deleted file mode 100644
index 8be8c42f3c3..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/mutations/job_unschedule.mutation.graphql
+++ /dev/null
@@ -1,10 +0,0 @@
-#import "../fragments/job.fragment.graphql"
-
-mutation unscheduleJob($id: CiBuildID!) {
- jobUnschedule(input: { id: $id }) {
- job {
- ...Job
- }
- errors
- }
-}
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
deleted file mode 100644
index 69719011079..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs.query.graphql
+++ /dev/null
@@ -1,78 +0,0 @@
-query getJobs($fullPath: ID!, $after: String, $first: Int = 30, $statuses: [CiJobStatus!]) {
- project(fullPath: $fullPath) {
- id
- jobs(after: $after, first: $first, statuses: $statuses) {
- pageInfo {
- endCursor
- hasNextPage
- hasPreviousPage
- startCursor
- }
- nodes {
- artifacts {
- # eslint-disable-next-line @graphql-eslint/require-id-when-available
- nodes {
- downloadPath
- fileType
- }
- }
- allowFailure
- status
- scheduledAt
- manualJob
- triggered
- createdByTag
- detailedStatus {
- id
- detailsPath
- group
- icon
- label
- text
- tooltip
- action {
- id
- buttonTitle
- icon
- method
- path
- title
- }
- }
- id
- refName
- refPath
- tags
- shortSha
- commitPath
- pipeline {
- id
- path
- user {
- id
- webPath
- avatarUrl
- }
- }
- stage {
- id
- name
- }
- name
- duration
- finishedAt
- coverage
- retryable
- playable
- cancelable
- active
- stuck
- userPermissions {
- readBuild
- readJobArtifacts
- updateBuild
- }
- }
- }
- }
-}
diff --git a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql b/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql
deleted file mode 100644
index a4e02ae721a..00000000000
--- a/app/assets/javascripts/jobs/components/table/graphql/queries/get_jobs_count.query.graphql
+++ /dev/null
@@ -1,8 +0,0 @@
-query getJobsCount($fullPath: ID!, $statuses: [CiJobStatus!]) {
- project(fullPath: $fullPath) {
- id
- jobs(statuses: $statuses) {
- count
- }
- }
-}
diff --git a/app/assets/javascripts/jobs/components/table/index.js b/app/assets/javascripts/jobs/components/table/index.js
deleted file mode 100644
index 88da1169e01..00000000000
--- a/app/assets/javascripts/jobs/components/table/index.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import { GlToast } from '@gitlab/ui';
-import Vue from 'vue';
-import VueApollo from 'vue-apollo';
-import JobsTableApp from '~/jobs/components/table/jobs_table_app.vue';
-import createDefaultClient from '~/lib/graphql';
-import { parseBoolean } from '~/lib/utils/common_utils';
-import cacheConfig from './graphql/cache_config';
-
-Vue.use(VueApollo);
-Vue.use(GlToast);
-
-const apolloProvider = new VueApollo({
- defaultClient: createDefaultClient(
- {},
- {
- cacheConfig,
- },
- ),
-});
-
-export default (containerId = 'js-jobs-table') => {
- const containerEl = document.getElementById(containerId);
-
- if (!containerEl) {
- return false;
- }
-
- const {
- fullPath,
- jobStatuses,
- pipelineEditorPath,
- emptyStateSvgPath,
- admin,
- } = containerEl.dataset;
-
- return new Vue({
- el: containerEl,
- apolloProvider,
- provide: {
- emptyStateSvgPath,
- fullPath,
- pipelineEditorPath,
- jobStatuses: JSON.parse(jobStatuses),
- admin: parseBoolean(admin),
- },
- render(createElement) {
- return createElement(JobsTableApp);
- },
- });
-};
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table.vue b/app/assets/javascripts/jobs/components/table/jobs_table.vue
deleted file mode 100644
index 84479ec421e..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table.vue
+++ /dev/null
@@ -1,112 +0,0 @@
-<script>
-import { GlTable } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-import ProjectCell from '~/pages/admin/jobs/components/table/cell/project_cell.vue';
-import RunnerCell from '~/pages/admin/jobs/components/table/cells/runner_cell.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';
-import { DEFAULT_FIELDS } from './constants';
-
-export default {
- i18n: {
- emptyText: s__('Jobs|No jobs to show'),
- },
- components: {
- ActionsCell,
- CiBadgeLink,
- DurationCell,
- GlTable,
- JobCell,
- PipelineCell,
- ProjectCell,
- RunnerCell,
- },
- props: {
- jobs: {
- type: Array,
- required: true,
- },
- tableFields: {
- type: Array,
- required: false,
- default: () => DEFAULT_FIELDS,
- },
- admin: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- methods: {
- formatCoverage(coverage) {
- return coverage ? `${coverage}%` : '';
- },
- },
-};
-</script>
-
-<template>
- <gl-table
- :items="jobs"
- :fields="tableFields"
- :tbody-tr-attr="{ 'data-testid': 'jobs-table-row' }"
- :empty-text="$options.i18n.emptyText"
- data-testid="jobs-table"
- show-empty
- stacked="lg"
- fixed
- >
- <template #table-colgroup="{ fields }">
- <col v-for="field in fields" :key="field.key" :class="field.columnClass" />
- </template>
-
- <template #cell(status)="{ item }">
- <ci-badge-link :status="item.detailedStatus" />
- </template>
-
- <template #cell(job)="{ item }">
- <job-cell :job="item" />
- </template>
-
- <template #cell(pipeline)="{ item }">
- <pipeline-cell :job="item" />
- </template>
-
- <template v-if="admin" #cell(project)="{ item }">
- <project-cell :job="item" />
- </template>
-
- <template v-if="admin" #cell(runner)="{ item }">
- <runner-cell :job="item" />
- </template>
-
- <template #cell(stage)="{ item }">
- <div class="gl-text-truncate">
- <span data-testid="job-stage-name">{{ item.stage.name }}</span>
- </div>
- </template>
-
- <template #cell(name)="{ item }">
- <div class="gl-text-truncate">
- <span data-testid="job-name">{{ item.name }}</span>
- </div>
- </template>
-
- <template #cell(duration)="{ item }">
- <duration-cell :job="item" />
- </template>
-
- <template #cell(coverage)="{ item }">
- <span v-if="item.coverage" data-testid="job-coverage">{{
- formatCoverage(item.coverage)
- }}</span>
- </template>
-
- <template #cell(actions)="{ item }">
- <actions-cell class="gl-float-right" :job="item" />
- </template>
- </gl-table>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue b/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
deleted file mode 100644
index 09fa006cb88..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table_app.vue
+++ /dev/null
@@ -1,238 +0,0 @@
-<script>
-import { GlAlert, GlIntersectionObserver, GlLoadingIcon } from '@gitlab/ui';
-import { __ } from '~/locale';
-import { createAlert } from '~/alert';
-import { setUrlParams, updateHistory, queryToObject } from '~/lib/utils/url_utility';
-import JobsSkeletonLoader from '~/pages/admin/jobs/components/jobs_skeleton_loader.vue';
-import JobsFilteredSearch from '../filtered_search/jobs_filtered_search.vue';
-import { validateQueryString } from '../filtered_search/utils';
-import GetJobs from './graphql/queries/get_jobs.query.graphql';
-import GetJobsCount from './graphql/queries/get_jobs_count.query.graphql';
-import JobsTable from './jobs_table.vue';
-import JobsTableEmptyState from './jobs_table_empty_state.vue';
-import JobsTableTabs from './jobs_table_tabs.vue';
-import { RAW_TEXT_WARNING } from './constants';
-
-export default {
- i18n: {
- jobsFetchErrorMsg: __('There was an error fetching the jobs for your project.'),
- jobsCountErrorMsg: __('There was an error fetching the number of jobs for your project.'),
- loadingAriaLabel: __('Loading'),
- },
- filterSearchBoxStyles:
- 'gl-my-0 gl-p-5 gl-bg-gray-10 gl-text-gray-900 gl-border-b gl-border-gray-100',
- components: {
- GlAlert,
- JobsFilteredSearch,
- JobsTable,
- JobsTableEmptyState,
- JobsTableTabs,
- GlIntersectionObserver,
- GlLoadingIcon,
- JobsSkeletonLoader,
- },
- inject: {
- fullPath: {
- default: '',
- },
- },
- apollo: {
- jobs: {
- query: GetJobs,
- variables() {
- return {
- fullPath: this.fullPath,
- ...this.validatedQueryString,
- };
- },
- update(data) {
- const { jobs: { nodes: list = [], pageInfo = {} } = {} } = data.project || {};
- return {
- list,
- pageInfo,
- };
- },
- error() {
- this.error = this.$options.i18n.jobsFetchErrorMsg;
- },
- },
- jobsCount: {
- query: GetJobsCount,
- context: {
- isSingleRequest: true,
- },
- variables() {
- return {
- fullPath: this.fullPath,
- ...this.validatedQueryString,
- };
- },
- update({ project }) {
- return project?.jobs?.count || 0;
- },
- error() {
- this.error = this.$options.i18n.jobsCountErrorMsg;
- },
- },
- },
- data() {
- return {
- jobs: {
- list: [],
- },
- error: '',
- scope: null,
- infiniteScrollingTriggered: false,
- filterSearchTriggered: false,
- jobsCount: null,
- count: 0,
- };
- },
- computed: {
- loading() {
- return this.$apollo.queries.jobs.loading;
- },
- // Show when on All tab with no jobs
- // Show only when not loading and filtered search has not been triggered
- // So we don't show empty state when results are empty on a filtered search
- showEmptyState() {
- return (
- this.jobs.list.length === 0 && !this.scope && !this.loading && !this.filterSearchTriggered
- );
- },
- hasNextPage() {
- return this.jobs?.pageInfo?.hasNextPage;
- },
- showLoadingSpinner() {
- return this.loading && this.infiniteScrollingTriggered;
- },
- showSkeletonLoader() {
- return this.loading && !this.showLoadingSpinner;
- },
- showFilteredSearch() {
- return !this.scope;
- },
- validatedQueryString() {
- const queryStringObject = queryToObject(window.location.search);
-
- return validateQueryString(queryStringObject);
- },
- },
- watch: {
- // this watcher ensures that the count on the all tab
- // is not updated when switching to the finished tab
- jobsCount(newCount, oldCount) {
- if (this.scope) {
- this.count = oldCount;
- } else {
- this.count = newCount;
- }
- },
- },
- methods: {
- updateHistoryAndFetchCount(status = null) {
- this.$apollo.queries.jobsCount.refetch({ statuses: status });
-
- updateHistory({
- url: setUrlParams({ statuses: status }, window.location.href, true),
- });
- },
- fetchJobsByStatus(scope) {
- this.infiniteScrollingTriggered = false;
-
- if (this.scope === scope) return;
-
- this.scope = scope;
-
- if (!this.scope) this.updateHistoryAndFetchCount();
-
- this.$apollo.queries.jobs.refetch({ statuses: scope });
- },
- filterJobsBySearch(filters) {
- this.infiniteScrollingTriggered = false;
- this.filterSearchTriggered = true;
-
- // all filters have been cleared reset query param
- // and refetch jobs/count with defaults
- if (!filters.length) {
- this.updateHistoryAndFetchCount();
- this.$apollo.queries.jobs.refetch({ statuses: null });
-
- return;
- }
-
- // Eventually there will be more tokens available
- // this code is written to scale for those tokens
- filters.forEach((filter) => {
- // Raw text input in filtered search does not have a type
- // when a user enters raw text we alert them that it is
- // not supported and we do not make an additional API call
- if (!filter.type) {
- createAlert({
- message: RAW_TEXT_WARNING,
- type: 'warning',
- });
- }
-
- if (filter.type === 'status') {
- this.updateHistoryAndFetchCount(filter.value.data);
- this.$apollo.queries.jobs.refetch({ statuses: filter.value.data });
- }
- });
- },
- fetchMoreJobs() {
- if (!this.loading) {
- this.infiniteScrollingTriggered = true;
-
- this.$apollo.queries.jobs.fetchMore({
- variables: {
- fullPath: this.fullPath,
- after: this.jobs?.pageInfo?.endCursor,
- },
- });
- }
- },
- },
-};
-</script>
-
-<template>
- <div>
- <gl-alert
- v-if="error"
- class="gl-mt-2"
- variant="danger"
- data-testid="jobs-table-error-alert"
- dismissible
- @dismiss="error = ''"
- >
- {{ error }}
- </gl-alert>
-
- <jobs-table-tabs
- :all-jobs-count="count"
- :loading="loading"
- @fetchJobsByStatus="fetchJobsByStatus"
- />
- <div v-if="showFilteredSearch" :class="$options.filterSearchBoxStyles">
- <jobs-filtered-search
- :query-string="validatedQueryString"
- @filterJobsBySearch="filterJobsBySearch"
- />
- </div>
-
- <jobs-skeleton-loader v-if="showSkeletonLoader" class="gl-mt-5" />
-
- <jobs-table-empty-state v-else-if="showEmptyState" />
-
- <jobs-table v-else :jobs="jobs.list" class="gl-table-no-top-border" />
-
- <gl-intersection-observer v-if="hasNextPage" @appear="fetchMoreJobs">
- <gl-loading-icon
- v-if="showLoadingSpinner"
- size="lg"
- :aria-label="$options.i18n.loadingAriaLabel"
- />
- </gl-intersection-observer>
- </div>
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue b/app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue
deleted file mode 100644
index fcdd52b719c..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table_empty_state.vue
+++ /dev/null
@@ -1,35 +0,0 @@
-<script>
-import { GlEmptyState } from '@gitlab/ui';
-import { s__ } from '~/locale';
-
-export default {
- i18n: {
- title: s__('Jobs|Use jobs to automate your tasks'),
- description: s__(
- 'Jobs|Jobs are the building blocks of a GitLab CI/CD pipeline. Each job has a specific task, like testing code. To set up jobs in a CI/CD pipeline, add a CI/CD configuration file to your project.',
- ),
- buttonText: s__('Jobs|Create CI/CD configuration file'),
- },
- components: {
- GlEmptyState,
- },
- inject: {
- pipelineEditorPath: {
- default: '',
- },
- emptyStateSvgPath: {
- default: '',
- },
- },
-};
-</script>
-
-<template>
- <gl-empty-state
- :title="$options.i18n.title"
- :description="$options.i18n.description"
- :svg-path="emptyStateSvgPath"
- :primary-button-link="pipelineEditorPath"
- :primary-button-text="$options.i18n.buttonText"
- />
-</template>
diff --git a/app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue b/app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue
deleted file mode 100644
index 797facb1eb8..00000000000
--- a/app/assets/javascripts/jobs/components/table/jobs_table_tabs.vue
+++ /dev/null
@@ -1,88 +0,0 @@
-<script>
-import { GlBadge, GlTab, GlTabs, GlLoadingIcon } from '@gitlab/ui';
-import { s__ } from '~/locale';
-import CancelJobs from '~/pages/admin/jobs/components/cancel_jobs.vue';
-import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility';
-
-export default {
- components: {
- GlBadge,
- GlTab,
- GlTabs,
- GlLoadingIcon,
- CancelJobs,
- },
- inject: {
- jobStatuses: {
- default: {},
- },
- url: {
- type: String,
- default: '',
- },
- },
- props: {
- allJobsCount: {
- type: Number,
- required: true,
- },
- loading: {
- type: Boolean,
- required: true,
- },
- showCancelAllJobsButton: {
- type: Boolean,
- required: false,
- default: false,
- },
- },
- computed: {
- tabs() {
- return [
- {
- text: s__('Jobs|All'),
- count: limitedCounterWithDelimiter(this.allJobsCount),
- scope: null,
- testId: 'jobs-all-tab',
- showBadge: true,
- },
- {
- text: s__('Jobs|Finished'),
- scope: [this.jobStatuses.success, this.jobStatuses.failed, this.jobStatuses.canceled],
- testId: 'jobs-finished-tab',
- showBadge: false,
- },
- ];
- },
- showLoadingIcon() {
- return this.loading && !this.allJobsCount;
- },
- },
-};
-</script>
-
-<template>
- <div class="gl-display-flex align-items-lg-center">
- <gl-tabs content-class="gl-py-0">
- <gl-tab
- v-for="tab in tabs"
- :key="tab.text"
- :title-link-attributes="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ {
- 'data-testid': tab.testId,
- } /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */"
- @click="$emit('fetchJobsByStatus', tab.scope)"
- >
- <template #title>
- <span>{{ tab.text }}</span>
- <gl-loading-icon v-if="showLoadingIcon && tab.showBadge" class="gl-ml-2" />
-
- <gl-badge v-else-if="tab.showBadge" size="sm" class="gl-tab-counter-badge">
- {{ tab.count }}
- </gl-badge>
- </template>
- </gl-tab>
- </gl-tabs>
- <div class="gl-flex-grow-1"></div>
- <cancel-jobs v-if="showCancelAllJobsButton" :url="url" />
- </div>
-</template>