diff options
Diffstat (limited to 'app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue')
-rw-r--r-- | app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue | 256 |
1 files changed, 256 insertions, 0 deletions
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue new file mode 100644 index 00000000000..fe16cb7a92e --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules.vue @@ -0,0 +1,256 @@ +<script> +import { GlAlert, GlBadge, GlButton, GlLoadingIcon, GlTabs, GlTab } from '@gitlab/ui'; +import { s__, sprintf } from '~/locale'; +import { limitedCounterWithDelimiter } from '~/lib/utils/text_utility'; +import { queryToObject } from '~/lib/utils/url_utility'; +import deletePipelineScheduleMutation from '../graphql/mutations/delete_pipeline_schedule.mutation.graphql'; +import takeOwnershipMutation from '../graphql/mutations/take_ownership.mutation.graphql'; +import getPipelineSchedulesQuery from '../graphql/queries/get_pipeline_schedules.query.graphql'; +import PipelineSchedulesTable from './table/pipeline_schedules_table.vue'; +import TakeOwnershipModal from './take_ownership_modal.vue'; +import DeletePipelineScheduleModal from './delete_pipeline_schedule_modal.vue'; + +export default { + i18n: { + schedulesFetchError: s__('PipelineSchedules|There was a problem fetching pipeline schedules.'), + scheduleDeleteError: s__( + 'PipelineSchedules|There was a problem deleting the pipeline schedule.', + ), + takeOwnershipError: s__( + 'PipelineSchedules|There was a problem taking ownership of the pipeline schedule.', + ), + newSchedule: s__('PipelineSchedules|New schedule'), + deleteSuccess: s__('PipelineSchedules|Pipeline schedule successfully deleted.'), + }, + components: { + DeletePipelineScheduleModal, + GlAlert, + GlBadge, + GlButton, + GlLoadingIcon, + GlTabs, + GlTab, + PipelineSchedulesTable, + TakeOwnershipModal, + }, + inject: { + fullPath: { + default: '', + }, + }, + apollo: { + schedules: { + query: getPipelineSchedulesQuery, + variables() { + return { + projectPath: this.fullPath, + status: this.scope, + }; + }, + update(data) { + const { pipelineSchedules: { nodes: list = [], count } = {} } = data.project || {}; + + return { + list, + count, + }; + }, + error() { + this.reportError(this.$options.i18n.schedulesFetchError); + }, + }, + }, + data() { + const { scope } = queryToObject(window.location.search); + return { + schedules: { + list: [], + }, + scope, + hasError: false, + errorMessage: '', + scheduleId: null, + showDeleteModal: false, + showTakeOwnershipModal: false, + count: 0, + }; + }, + computed: { + isLoading() { + return this.$apollo.queries.schedules.loading; + }, + schedulesCount() { + return this.schedules.count; + }, + tabs() { + return [ + { + text: s__('PipelineSchedules|All'), + count: limitedCounterWithDelimiter(this.count), + scope: null, + showBadge: true, + attrs: { 'data-testid': 'pipeline-schedules-all-tab' }, + }, + { + text: s__('PipelineSchedules|Active'), + scope: 'ACTIVE', + showBadge: false, + attrs: { 'data-testid': 'pipeline-schedules-active-tab' }, + }, + { + text: s__('PipelineSchedules|Inactive'), + scope: 'INACTIVE', + showBadge: false, + attrs: { 'data-testid': 'pipeline-schedules-inactive-tab' }, + }, + ]; + }, + }, + watch: { + // this watcher ensures that the count on the all tab + // is not updated when switching to other tabs + schedulesCount(newCount) { + if (!this.scope) { + this.count = newCount; + } + }, + }, + methods: { + reportError(error) { + this.hasError = true; + this.errorMessage = error; + }, + setDeleteModal(id) { + this.showDeleteModal = true; + this.scheduleId = id; + }, + setTakeOwnershipModal(id) { + this.showTakeOwnershipModal = true; + this.scheduleId = id; + }, + hideModal() { + this.showDeleteModal = false; + this.showTakeOwnershipModal = false; + this.scheduleId = null; + }, + async deleteSchedule() { + try { + const { + data: { + pipelineScheduleDelete: { errors }, + }, + } = await this.$apollo.mutate({ + mutation: deletePipelineScheduleMutation, + variables: { id: this.scheduleId }, + }); + + if (errors.length > 0) { + throw new Error(); + } else { + this.$apollo.queries.schedules.refetch(); + this.$toast.show(this.$options.i18n.deleteSuccess); + } + } catch { + this.reportError(this.$options.i18n.scheduleDeleteError); + } + }, + async takeOwnership() { + try { + const { + data: { + pipelineScheduleTakeOwnership: { pipelineSchedule, errors }, + }, + } = await this.$apollo.mutate({ + mutation: takeOwnershipMutation, + variables: { id: this.scheduleId }, + }); + + if (errors.length > 0) { + throw new Error(); + } else { + this.$apollo.queries.schedules.refetch(); + + if (pipelineSchedule?.owner?.name) { + const toastMsg = sprintf( + s__('PipelineSchedules|Successfully taken ownership from %{owner}.'), + { + owner: pipelineSchedule.owner.name, + }, + ); + + this.$toast.show(toastMsg); + } + } + } catch { + this.reportError(this.$options.i18n.takeOwnershipError); + } + }, + fetchPipelineSchedulesByStatus(scope) { + this.scope = scope; + this.$apollo.queries.schedules.refetch(); + }, + }, +}; +</script> + +<template> + <div> + <gl-alert v-if="hasError" class="gl-mb-2" variant="danger" @dismiss="hasError = false"> + {{ errorMessage }} + </gl-alert> + + <template v-else> + <gl-tabs + sync-active-tab-with-query-params + query-param-name="scope" + nav-class="gl-flex-grow-1 gl-align-items-center" + > + <gl-tab + v-for="tab in tabs" + :key="tab.text" + :title-link-attributes="tab.attrs" + :query-param-value="tab.scope" + @click="fetchPipelineSchedulesByStatus(tab.scope)" + > + <template #title> + <span>{{ tab.text }}</span> + + <template v-if="tab.showBadge"> + <gl-loading-icon v-if="tab.scope === scope && isLoading" class="gl-ml-2" /> + + <gl-badge v-else-if="tab.count" size="sm" class="gl-tab-counter-badge"> + {{ tab.count }} + </gl-badge> + </template> + </template> + + <gl-loading-icon v-if="isLoading" size="lg" /> + <pipeline-schedules-table + v-else + :schedules="schedules.list" + @showTakeOwnershipModal="setTakeOwnershipModal" + @showDeleteModal="setDeleteModal" + /> + </gl-tab> + + <template #tabs-end> + <gl-button variant="confirm" class="gl-ml-auto" data-testid="new-schedule-button"> + {{ $options.i18n.newSchedule }} + </gl-button> + </template> + </gl-tabs> + + <take-ownership-modal + :visible="showTakeOwnershipModal" + @takeOwnership="takeOwnership" + @hideModal="hideModal" + /> + + <delete-pipeline-schedule-modal + :visible="showDeleteModal" + @deleteSchedule="deleteSchedule" + @hideModal="hideModal" + /> + </template> + </div> +</template> |