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/commit/pipelines/legacy_pipelines_table_wrapper.vue')
-rw-r--r--app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue342
1 files changed, 342 insertions, 0 deletions
diff --git a/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue
new file mode 100644
index 00000000000..5e84dcbe48e
--- /dev/null
+++ b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue
@@ -0,0 +1,342 @@
+<script>
+import { GlButton, GlEmptyState, GlLoadingIcon, GlModal, GlLink, GlSprintf } from '@gitlab/ui';
+import { helpPagePath } from '~/helpers/help_page_helper';
+import { getParameterByName } from '~/lib/utils/url_utility';
+import PipelinesTableComponent from '~/ci/common/pipelines_table.vue';
+import { PipelineKeyOptions } from '~/ci/constants';
+import eventHub from '~/ci/event_hub';
+import PipelinesMixin from '~/ci/pipeline_details/mixins/pipelines_mixin';
+import PipelinesService from '~/ci/pipelines_page/services/pipelines_service';
+import PipelineStore from '~/ci/pipeline_details/stores/pipelines_store';
+import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
+import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
+import { s__, __ } from '~/locale';
+
+export default {
+ PipelineKeyOptions,
+ components: {
+ GlButton,
+ GlEmptyState,
+ GlLink,
+ GlLoadingIcon,
+ GlModal,
+ GlSprintf,
+ PipelinesTableComponent,
+ TablePagination,
+ },
+ mixins: [PipelinesMixin, glFeatureFlagMixin()],
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ errorStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ emptyStateSvgPath: {
+ type: String,
+ required: true,
+ },
+ viewType: {
+ type: String,
+ required: false,
+ default: 'root',
+ },
+ canCreatePipelineInTargetProject: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ sourceProjectFullPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ targetProjectFullPath: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ projectId: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ mergeRequestId: {
+ type: Number,
+ required: false,
+ default: 0,
+ },
+ },
+
+ data() {
+ const store = new PipelineStore();
+
+ return {
+ store,
+ state: store.state,
+ page: getParameterByName('page') || '1',
+ requestData: {},
+ modalId: 'create-pipeline-for-fork-merge-request-modal',
+ };
+ },
+
+ computed: {
+ shouldRenderTable() {
+ return !this.isLoading && this.state.pipelines.length > 0 && !this.hasError;
+ },
+ shouldRenderErrorState() {
+ return this.hasError && !this.isLoading;
+ },
+ shouldRenderEmptyState() {
+ return this.state.pipelines.length === 0 && !this.shouldRenderErrorState;
+ },
+ /**
+ * The "Run pipeline" button can only be rendered when:
+ * - In MR view - we use `canCreatePipelineInTargetProject` for that purpose
+ * - If the latest pipeline has the `detached_merge_request_pipeline` flag
+ *
+ * @returns {Boolean}
+ */
+ canRenderPipelineButton() {
+ return this.latestPipelineDetachedFlag;
+ },
+ isForkMergeRequest() {
+ return this.sourceProjectFullPath !== this.targetProjectFullPath;
+ },
+ isLatestPipelineCreatedInTargetProject() {
+ const latest = this.state.pipelines[0];
+
+ return latest?.project?.full_path === `/${this.targetProjectFullPath}`;
+ },
+ shouldShowSecurityWarning() {
+ return (
+ this.canCreatePipelineInTargetProject &&
+ this.isForkMergeRequest &&
+ !this.isLatestPipelineCreatedInTargetProject
+ );
+ },
+ /**
+ * Checks if either `detached_merge_request_pipeline` or
+ * `merge_request_pipeline` are tru in the first
+ * object in the pipelines array.
+ *
+ * @returns {Boolean}
+ */
+ latestPipelineDetachedFlag() {
+ const latest = this.state.pipelines[0];
+ return (
+ latest &&
+ latest.flags &&
+ (latest.flags.detached_merge_request_pipeline || latest.flags.merge_request_pipeline)
+ );
+ },
+ },
+ created() {
+ this.service = new PipelinesService(this.endpoint);
+ this.requestData = { page: this.page };
+ },
+ methods: {
+ successCallback(resp) {
+ // depending of the endpoint the response can either bring a `pipelines` key or not.
+ const pipelines = resp.data.pipelines || resp.data;
+
+ this.store.storePagination(resp.headers);
+ this.setCommonData(pipelines);
+
+ if (resp.headers?.['x-total']) {
+ const updatePipelinesEvent = new CustomEvent('update-pipelines-count', {
+ detail: { pipelineCount: resp.headers['x-total'] },
+ });
+
+ // notifiy to update the count in tabs
+ if (this.$el.parentElement) {
+ this.$el.parentElement.dispatchEvent(updatePipelinesEvent);
+ }
+ }
+ },
+ /**
+ * When the user clicks on the "Run pipeline" button
+ * we need to make a post request and
+ * to update the table content once the request is finished.
+ *
+ * We are emitting an event through the eventHub using the old pattern
+ * to make use of the code in mixins/pipelines.js that handles all the
+ * table events
+ *
+ */
+ onClickRunPipeline() {
+ eventHub.$emit('runMergeRequestPipeline', {
+ projectId: this.projectId,
+ mergeRequestId: this.mergeRequestId,
+ });
+ },
+ tryRunPipeline() {
+ if (!this.shouldShowSecurityWarning) {
+ this.onClickRunPipeline();
+ } else {
+ this.$refs.modal.show();
+ }
+ },
+ },
+ modal: {
+ actionPrimary: {
+ text: s__('Pipeline|Run pipeline'),
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ actionCancel: {
+ text: __('Cancel'),
+ attributes: {
+ variant: 'default',
+ },
+ },
+ },
+ i18n: {
+ runPipelinePopoverTitle: s__('Pipeline|Run merge request pipeline'),
+ runPipelinePopoverDescription: s__(
+ 'Pipeline|To run a merge request pipeline, the jobs in the CI/CD configuration file %{linkStart}must be configured%{linkEnd} to run in merge request pipelines.',
+ ),
+ runPipelineText: s__('Pipeline|Run pipeline'),
+ emptyStateTitle: s__('Pipelines|There are currently no pipelines.'),
+ },
+ mrPipelinesDocsPath: helpPagePath('ci/pipelines/merge_request_pipelines.md', {
+ anchor: 'prerequisites',
+ }),
+ runPipelinesInTheParentProjectHelpPath: helpPagePath(
+ '/ci/pipelines/merge_request_pipelines.html',
+ {
+ anchor: 'run-pipelines-in-the-parent-project',
+ },
+ ),
+};
+</script>
+<template>
+ <div class="content-list pipelines">
+ <gl-loading-icon
+ v-if="isLoading"
+ :label="s__('Pipelines|Loading pipelines')"
+ size="lg"
+ class="prepend-top-20"
+ />
+
+ <gl-empty-state
+ v-else-if="shouldRenderErrorState"
+ :svg-path="errorStateSvgPath"
+ :title="
+ s__(`Pipelines|There was an error fetching the pipelines.
+ Try again in a few moments or contact your support team.`)
+ "
+ data-testid="pipeline-error-empty-state"
+ />
+ <template v-else-if="shouldRenderEmptyState">
+ <gl-empty-state
+ :svg-path="emptyStateSvgPath"
+ :svg-height="150"
+ :title="$options.i18n.emptyStateTitle"
+ data-testid="pipeline-empty-state"
+ >
+ <template #description>
+ <gl-sprintf :message="$options.i18n.runPipelinePopoverDescription">
+ <template #link="{ content }">
+ <gl-link
+ :href="$options.mrPipelinesDocsPath"
+ target="_blank"
+ data-testid="mr-pipelines-docs-link"
+ >{{ content }}</gl-link
+ >
+ </template>
+ </gl-sprintf>
+ </template>
+
+ <template #actions>
+ <div class="gl-vertical-align-middle">
+ <gl-button
+ variant="confirm"
+ :loading="state.isRunningMergeRequestPipeline"
+ data-testid="run_pipeline_button"
+ @click="tryRunPipeline"
+ >
+ {{ $options.i18n.runPipelineText }}
+ </gl-button>
+ </div>
+ </template>
+ </gl-empty-state>
+ </template>
+
+ <div v-else-if="shouldRenderTable">
+ <gl-button
+ v-if="canRenderPipelineButton"
+ block
+ class="gl-mt-3 gl-mb-3 gl-lg-display-none"
+ variant="confirm"
+ data-testid="run_pipeline_button_mobile"
+ :loading="state.isRunningMergeRequestPipeline"
+ @click="tryRunPipeline"
+ >
+ {{ $options.i18n.runPipelineText }}
+ </gl-button>
+
+ <pipelines-table-component
+ :pipelines="state.pipelines"
+ :update-graph-dropdown="updateGraphDropdown"
+ :view-type="viewType"
+ :pipeline-key-option="$options.PipelineKeyOptions[0]"
+ >
+ <template #table-header-actions>
+ <div v-if="canRenderPipelineButton" class="gl-text-right">
+ <gl-button
+ data-testid="run_pipeline_button"
+ :loading="state.isRunningMergeRequestPipeline"
+ @click="tryRunPipeline"
+ >
+ {{ $options.i18n.runPipelineText }}
+ </gl-button>
+ </div>
+ </template>
+ </pipelines-table-component>
+ </div>
+
+ <gl-modal
+ v-if="canRenderPipelineButton || shouldRenderEmptyState"
+ :id="modalId"
+ ref="modal"
+ :modal-id="modalId"
+ :title="s__('Pipelines|Are you sure you want to run this pipeline?')"
+ :action-primary="$options.modal.actionPrimary"
+ :action-cancel="$options.modal.actionCancel"
+ @primary="onClickRunPipeline"
+ >
+ <p>
+ {{
+ s__(
+ 'Pipelines|This pipeline will run code originating from a forked project merge request. This means that the code can potentially have security considerations like exposing CI variables.',
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__(
+ "Pipelines|It is recommended the code is reviewed thoroughly before running this pipeline with the parent project's CI resource.",
+ )
+ }}
+ </p>
+ <p>
+ {{
+ s__('Pipelines|If you are unsure, please ask a project maintainer to review it for you.')
+ }}
+ </p>
+ <gl-link :href="$options.runPipelinesInTheParentProjectHelpPath" target="_blank">
+ {{ s__('Pipelines|More Information') }}
+ </gl-link>
+ </gl-modal>
+
+ <table-pagination
+ v-if="shouldRenderPagination"
+ :change="onChangePage"
+ :page-info="state.pageInfo"
+ />
+ </div>
+</template>