diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-05 03:07:57 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-05 03:07:57 +0300 |
commit | eaa9a0adf963293c678f30e73b7150e89f921a99 (patch) | |
tree | 8c6a16e5d477347a073a406a0b6b0549bbe06126 /app/assets/javascripts/ci | |
parent | 8fc2555ccce63aa5641b123c154389cff593e0d7 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/ci')
16 files changed, 849 insertions, 0 deletions
diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue b/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue new file mode 100644 index 00000000000..16bfc7f3abe --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/delete_pipeline_schedule_modal.vue @@ -0,0 +1,45 @@ +<script> +import { GlModal } from '@gitlab/ui'; +import { s__, __ } from '~/locale'; + +export default { + modal: { + id: 'delete-pipeline-schedule-modal', + deleteConfirmation: s__( + 'PipelineSchedules|Are you sure you want to delete this pipeline schedule?', + ), + actionPrimary: { + text: s__('PipelineSchedules|Delete pipeline schedule'), + attributes: [{ variant: 'danger' }], + }, + actionCancel: { + text: __('Cancel'), + attributes: [], + }, + }, + components: { + GlModal, + }, + props: { + visible: { + type: Boolean, + required: true, + }, + }, +}; +</script> + +<template> + <gl-modal + :visible="visible" + :title="$options.modal.actionPrimary.text" + :modal-id="$options.modal.id" + :action-primary="$options.modal.actionPrimary" + :action-cancel="$options.modal.actionCancel" + size="sm" + @primary="$emit('deleteSchedule')" + @hide="$emit('hideModal')" + > + {{ $options.modal.deleteConfirmation }} + </gl-modal> +</template> 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> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue new file mode 100644 index 00000000000..6e24ac6b8d4 --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/pipeline_schedules_form.vue @@ -0,0 +1,18 @@ +<script> +import { GlForm } from '@gitlab/ui'; + +export default { + components: { + GlForm, + }, + inject: { + fullPath: { + default: '', + }, + }, +}; +</script> + +<template> + <gl-form /> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue new file mode 100644 index 00000000000..8656e5d3536 --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_actions.vue @@ -0,0 +1,68 @@ +<script> +import { GlButton, GlButtonGroup, GlTooltipDirective as GlTooltip } from '@gitlab/ui'; +import { s__ } from '~/locale'; + +export const i18n = { + playTooltip: s__('PipelineSchedules|Run pipeline schedule'), + editTooltip: s__('PipelineSchedules|Edit pipeline schedule'), + deleteTooltip: s__('PipelineSchedules|Delete pipeline schedule'), + takeOwnershipTooltip: s__('PipelineSchedules|Take ownership of pipeline schedule'), +}; + +export default { + i18n, + components: { + GlButton, + GlButtonGroup, + }, + directives: { + GlTooltip, + }, + props: { + schedule: { + type: Object, + required: true, + }, + }, + computed: { + canPlay() { + return this.schedule.userPermissions.playPipelineSchedule; + }, + canTakeOwnership() { + return this.schedule.userPermissions.takeOwnershipPipelineSchedule; + }, + canUpdate() { + return this.schedule.userPermissions.updatePipelineSchedule; + }, + canRemove() { + return this.schedule.userPermissions.adminPipelineSchedule; + }, + }, +}; +</script> + +<template> + <div class="gl-display-flex gl-justify-content-end"> + <gl-button-group> + <gl-button v-if="canPlay" v-gl-tooltip :title="$options.i18n.playTooltip" icon="play" /> + <gl-button + v-if="canTakeOwnership" + v-gl-tooltip + :title="$options.i18n.takeOwnershipTooltip" + icon="user" + data-testid="take-ownership-pipeline-schedule-btn" + @click="$emit('showTakeOwnershipModal', schedule.id)" + /> + <gl-button v-if="canUpdate" v-gl-tooltip :title="$options.i18n.editTooltip" icon="pencil" /> + <gl-button + v-if="canRemove" + v-gl-tooltip + :title="$options.i18n.deleteTooltip" + icon="remove" + variant="danger" + data-testid="delete-pipeline-schedule-btn" + @click="$emit('showDeleteModal', schedule.id)" + /> + </gl-button-group> + </div> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue new file mode 100644 index 00000000000..216796b357c --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_last_pipeline.vue @@ -0,0 +1,32 @@ +<script> +import CiBadge from '~/vue_shared/components/ci_badge_link.vue'; + +export default { + components: { + CiBadge, + }, + props: { + schedule: { + type: Object, + required: true, + }, + }, + computed: { + hasPipeline() { + return this.schedule.lastPipeline; + }, + lastPipelineStatus() { + return this.schedule?.lastPipeline?.detailedStatus; + }, + }, +}; +</script> + +<template> + <div> + <ci-badge v-if="hasPipeline" :status="lastPipelineStatus" class="gl-vertical-align-middle" /> + <span v-else data-testid="pipeline-schedule-status-text"> + {{ s__('PipelineSchedules|None') }} + </span> + </div> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue new file mode 100644 index 00000000000..48d59bf6e7c --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_next_run.vue @@ -0,0 +1,32 @@ +<script> +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; + +export default { + components: { + TimeAgoTooltip, + }, + props: { + schedule: { + type: Object, + required: true, + }, + }, + computed: { + showTimeAgo() { + return this.schedule.active && this.schedule.nextRunAt; + }, + realNextRunTime() { + return this.schedule.realNextRun; + }, + }, +}; +</script> + +<template> + <div> + <time-ago-tooltip v-if="showTimeAgo" :time="realNextRunTime" /> + <span v-else data-testid="pipeline-schedule-inactive"> + {{ s__('PipelineSchedules|Inactive') }} + </span> + </div> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue new file mode 100644 index 00000000000..e7fa94eb7fc --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_owner.vue @@ -0,0 +1,29 @@ +<script> +import { GlAvatar, GlAvatarLink } from '@gitlab/ui'; + +export default { + components: { + GlAvatar, + GlAvatarLink, + }, + props: { + schedule: { + type: Object, + required: true, + }, + }, + computed: { + owner() { + return this.schedule.owner; + }, + }, +}; +</script> + +<template> + <div> + <gl-avatar-link :href="owner.webPath" :title="owner.name" class="gl-ml-3"> + <gl-avatar :size="32" :src="owner.avatarUrl" /> + </gl-avatar-link> + </div> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue new file mode 100644 index 00000000000..08efa794bcc --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/cells/pipeline_schedule_target.vue @@ -0,0 +1,36 @@ +<script> +import { GlIcon, GlLink } from '@gitlab/ui'; + +export default { + components: { + GlIcon, + GlLink, + }, + props: { + schedule: { + type: Object, + required: true, + }, + }, + computed: { + iconName() { + return this.schedule.forTag ? 'tag' : 'fork'; + }, + refPath() { + return this.schedule.refPath; + }, + refDisplay() { + return this.schedule.refForDisplay; + }, + }, +}; +</script> + +<template> + <div> + <gl-icon :name="iconName" /> + <span v-if="refPath"> + <gl-link :href="refPath" class="gl-text-gray-900">{{ refDisplay }}</gl-link> + </span> + </div> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue b/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue new file mode 100644 index 00000000000..1b97a35a51e --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/table/pipeline_schedules_table.vue @@ -0,0 +1,102 @@ +<script> +import { GlTableLite } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import PipelineScheduleActions from './cells/pipeline_schedule_actions.vue'; +import PipelineScheduleLastPipeline from './cells/pipeline_schedule_last_pipeline.vue'; +import PipelineScheduleNextRun from './cells/pipeline_schedule_next_run.vue'; +import PipelineScheduleOwner from './cells/pipeline_schedule_owner.vue'; +import PipelineScheduleTarget from './cells/pipeline_schedule_target.vue'; + +export default { + fields: [ + { + key: 'description', + label: s__('PipelineSchedules|Description'), + thClass: 'gl-border-t-none!', + columnClass: 'gl-w-40p', + }, + { + key: 'target', + label: s__('PipelineSchedules|Target'), + thClass: 'gl-border-t-none!', + columnClass: 'gl-w-10p', + }, + { + key: 'pipeline', + label: s__('PipelineSchedules|Last Pipeline'), + thClass: 'gl-border-t-none!', + columnClass: 'gl-w-10p', + }, + { + key: 'next', + label: s__('PipelineSchedules|Next Run'), + thClass: 'gl-border-t-none!', + columnClass: 'gl-w-15p', + }, + { + key: 'owner', + label: s__('PipelineSchedules|Owner'), + thClass: 'gl-border-t-none!', + columnClass: 'gl-w-10p', + }, + { + key: 'actions', + label: '', + thClass: 'gl-border-t-none!', + columnClass: 'gl-w-15p', + }, + ], + components: { + GlTableLite, + PipelineScheduleActions, + PipelineScheduleLastPipeline, + PipelineScheduleNextRun, + PipelineScheduleOwner, + PipelineScheduleTarget, + }, + props: { + schedules: { + type: Array, + required: true, + }, + }, +}; +</script> + +<template> + <gl-table-lite :fields="$options.fields" :items="schedules" stacked="md"> + <template #table-colgroup="{ fields }"> + <col v-for="field in fields" :key="field.key" :class="field.columnClass" /> + </template> + + <template #cell(description)="{ item }"> + <span data-testid="pipeline-schedule-description"> + {{ item.description }} + </span> + </template> + + <template #cell(target)="{ item }"> + <pipeline-schedule-target :schedule="item" /> + </template> + + <template #cell(pipeline)="{ item }"> + <pipeline-schedule-last-pipeline :schedule="item" /> + </template> + + <template #cell(next)="{ item }"> + <pipeline-schedule-next-run :schedule="item" /> + </template> + + <template #cell(owner)="{ item }"> + <pipeline-schedule-owner :schedule="item" /> + </template> + + <template #cell(actions)="{ item }"> + <pipeline-schedule-actions + :schedule="item" + @showTakeOwnershipModal="$emit('showTakeOwnershipModal', $event)" + @showDeleteModal="$emit('showDeleteModal', $event)" + /> + </template> + </gl-table-lite> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue new file mode 100644 index 00000000000..3ac52d4735d --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal.vue @@ -0,0 +1,54 @@ +<script> +import { GlModal } from '@gitlab/ui'; +import { __, s__ } from '~/locale'; + +export default { + modalId: 'pipeline-take-ownership-modal', + i18n: { + takeOwnership: s__('PipelineSchedules|Take ownership'), + ownershipMessage: s__( + 'PipelineSchedules|Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?', + ), + cancelLabel: __('Cancel'), + }, + components: { + GlModal, + }, + props: { + visible: { + type: Boolean, + required: true, + }, + }, + computed: { + actionCancel() { + return { text: this.$options.i18n.cancelLabel }; + }, + actionPrimary() { + return { + text: this.$options.i18n.takeOwnership, + attributes: [ + { + variant: 'confirm', + category: 'primary', + }, + ], + }; + }, + }, +}; +</script> +<template> + <gl-modal + :visible="visible" + :modal-id="$options.modalId" + :action-primary="actionPrimary" + :action-cancel="actionCancel" + :title="$options.i18n.takeOwnership" + size="sm" + @primary="$emit('takeOwnership')" + @hide="$emit('hideModal')" + > + <p>{{ $options.i18n.ownershipMessage }}</p> + </gl-modal> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue new file mode 100644 index 00000000000..7ded3945a32 --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/components/take_ownership_modal_legacy.vue @@ -0,0 +1,52 @@ +<script> +import { GlModal } from '@gitlab/ui'; +import { __, s__ } from '~/locale'; + +export default { + components: { + GlModal, + }, + props: { + ownershipUrl: { + type: String, + required: true, + }, + }, + modalId: 'pipeline-take-ownership-modal', + i18n: { + takeOwnership: s__('PipelineSchedules|Take ownership'), + ownershipMessage: s__( + 'PipelineSchedules|Only the owner of a pipeline schedule can make changes to it. Do you want to take ownership of this schedule?', + ), + cancelLabel: __('Cancel'), + }, + computed: { + actionCancel() { + return { text: this.$options.i18n.cancelLabel }; + }, + actionPrimary() { + return { + text: this.$options.i18n.takeOwnership, + attributes: [ + { + variant: 'confirm', + category: 'primary', + href: this.ownershipUrl, + 'data-method': 'post', + }, + ], + }; + }, + }, +}; +</script> +<template> + <gl-modal + :modal-id="$options.modalId" + :action-primary="actionPrimary" + :action-cancel="actionCancel" + :title="$options.i18n.takeOwnership" + > + <p>{{ $options.i18n.ownershipMessage }}</p> + </gl-modal> +</template> diff --git a/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql new file mode 100644 index 00000000000..8aab0b3fbde --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/delete_pipeline_schedule.mutation.graphql @@ -0,0 +1,6 @@ +mutation deletePipelineSchedule($id: CiPipelineScheduleID!) { + pipelineScheduleDelete(input: { id: $id }) { + clientMutationId + errors + } +} diff --git a/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql new file mode 100644 index 00000000000..e410ef91d8b --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/graphql/mutations/take_ownership.mutation.graphql @@ -0,0 +1,12 @@ +mutation takeOwnership($id: CiPipelineScheduleID!) { + pipelineScheduleTakeOwnership(input: { id: $id }) { + pipelineSchedule { + id + owner { + id + name + } + } + errors + } +} diff --git a/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql b/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql new file mode 100644 index 00000000000..9f6cb429cca --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/graphql/queries/get_pipeline_schedules.query.graphql @@ -0,0 +1,41 @@ +query getPipelineSchedulesQuery($projectPath: ID!, $status: PipelineScheduleStatus) { + project(fullPath: $projectPath) { + id + pipelineSchedules(status: $status) { + count + nodes { + id + description + forTag + refPath + refForDisplay + lastPipeline { + id + detailedStatus { + id + group + icon + label + text + detailsPath + } + } + active + nextRunAt + realNextRun + owner { + id + avatarUrl + name + webPath + } + userPermissions { + playPipelineSchedule + takeOwnershipPipelineSchedule + updatePipelineSchedule + adminPipelineSchedule + } + } + } + } +} diff --git a/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_app.js b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_app.js new file mode 100644 index 00000000000..4c06fa321e5 --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_app.js @@ -0,0 +1,34 @@ +import { GlToast } from '@gitlab/ui'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import PipelineSchedules from './components/pipeline_schedules.vue'; + +Vue.use(VueApollo); +Vue.use(GlToast); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); + +export default () => { + const containerEl = document.querySelector('#pipeline-schedules-app'); + + if (!containerEl) { + return false; + } + + const { fullPath } = containerEl.dataset; + + return new Vue({ + el: containerEl, + name: 'PipelineSchedulesRoot', + apolloProvider, + provide: { + fullPath, + }, + render(createElement) { + return createElement(PipelineSchedules); + }, + }); +}; diff --git a/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_form_app.js b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_form_app.js new file mode 100644 index 00000000000..d83417ab84a --- /dev/null +++ b/app/assets/javascripts/ci/pipeline_schedules/mount_pipeline_schedules_form_app.js @@ -0,0 +1,32 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import PipelineSchedulesForm from './components/pipeline_schedules_form.vue'; + +Vue.use(VueApollo); + +const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient(), +}); + +export default (selector) => { + const containerEl = document.querySelector(selector); + + if (!containerEl) { + return false; + } + + const { fullPath } = containerEl.dataset; + + return new Vue({ + el: containerEl, + name: 'PipelineSchedulesFormRoot', + apolloProvider, + provide: { + fullPath, + }, + render(createElement) { + return createElement(PipelineSchedulesForm); + }, + }); +}; |