260 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			260 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Vue
		
	
	
	
<script>
 | 
						|
import {
 | 
						|
  GlModal,
 | 
						|
  GlForm,
 | 
						|
  GlFormGroup,
 | 
						|
  GlFormInput,
 | 
						|
  GlFormTextarea,
 | 
						|
  GlToggle,
 | 
						|
  GlButton,
 | 
						|
  GlAlert,
 | 
						|
} from '@gitlab/ui';
 | 
						|
import { createAlert } from '~/alert';
 | 
						|
import axios from '~/lib/utils/axios_utils';
 | 
						|
import { contentTypeMultipartFormData } from '~/lib/utils/headers';
 | 
						|
import { numberToHumanSize } from '~/lib/utils/number_utils';
 | 
						|
import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
 | 
						|
import { __ } from '~/locale';
 | 
						|
import UploadDropzone from '~/vue_shared/components/upload_dropzone/upload_dropzone.vue';
 | 
						|
import {
 | 
						|
  SECONDARY_OPTIONS_TEXT,
 | 
						|
  COMMIT_LABEL,
 | 
						|
  TARGET_BRANCH_LABEL,
 | 
						|
  TOGGLE_CREATE_MR_LABEL,
 | 
						|
} from '../constants';
 | 
						|
 | 
						|
const PRIMARY_OPTIONS_TEXT = __('Upload file');
 | 
						|
const MODAL_TITLE = __('Upload new file');
 | 
						|
const REMOVE_FILE_TEXT = __('Remove file');
 | 
						|
const NEW_BRANCH_IN_FORK = __(
 | 
						|
  'GitLab will create a branch in your fork and start a merge request.',
 | 
						|
);
 | 
						|
const ERROR_MESSAGE = __('Error uploading file. Please try again.');
 | 
						|
 | 
						|
export default {
 | 
						|
  components: {
 | 
						|
    GlModal,
 | 
						|
    GlForm,
 | 
						|
    GlFormGroup,
 | 
						|
    GlFormInput,
 | 
						|
    GlFormTextarea,
 | 
						|
    GlToggle,
 | 
						|
    GlButton,
 | 
						|
    UploadDropzone,
 | 
						|
    GlAlert,
 | 
						|
  },
 | 
						|
  i18n: {
 | 
						|
    COMMIT_LABEL,
 | 
						|
    TARGET_BRANCH_LABEL,
 | 
						|
    TOGGLE_CREATE_MR_LABEL,
 | 
						|
    REMOVE_FILE_TEXT,
 | 
						|
    NEW_BRANCH_IN_FORK,
 | 
						|
  },
 | 
						|
  props: {
 | 
						|
    modalTitle: {
 | 
						|
      type: String,
 | 
						|
      default: MODAL_TITLE,
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
    primaryBtnText: {
 | 
						|
      type: String,
 | 
						|
      default: PRIMARY_OPTIONS_TEXT,
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
    modalId: {
 | 
						|
      type: String,
 | 
						|
      required: true,
 | 
						|
    },
 | 
						|
    commitMessage: {
 | 
						|
      type: String,
 | 
						|
      required: true,
 | 
						|
    },
 | 
						|
    targetBranch: {
 | 
						|
      type: String,
 | 
						|
      required: true,
 | 
						|
    },
 | 
						|
    originalBranch: {
 | 
						|
      type: String,
 | 
						|
      required: true,
 | 
						|
    },
 | 
						|
    canPushCode: {
 | 
						|
      type: Boolean,
 | 
						|
      required: true,
 | 
						|
    },
 | 
						|
    path: {
 | 
						|
      type: String,
 | 
						|
      required: true,
 | 
						|
    },
 | 
						|
    replacePath: {
 | 
						|
      type: String,
 | 
						|
      default: null,
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
  },
 | 
						|
  data() {
 | 
						|
    return {
 | 
						|
      commit: this.commitMessage,
 | 
						|
      target: this.targetBranch,
 | 
						|
      createNewMr: true,
 | 
						|
      file: null,
 | 
						|
      filePreviewURL: null,
 | 
						|
      fileBinary: null,
 | 
						|
      loading: false,
 | 
						|
    };
 | 
						|
  },
 | 
						|
  computed: {
 | 
						|
    primaryOptions() {
 | 
						|
      return {
 | 
						|
        text: this.primaryBtnText,
 | 
						|
        attributes: {
 | 
						|
          variant: 'confirm',
 | 
						|
          loading: this.loading,
 | 
						|
          disabled: !this.formCompleted || this.loading,
 | 
						|
        },
 | 
						|
      };
 | 
						|
    },
 | 
						|
    cancelOptions() {
 | 
						|
      return {
 | 
						|
        text: SECONDARY_OPTIONS_TEXT,
 | 
						|
        attributes: {
 | 
						|
          disabled: this.loading,
 | 
						|
        },
 | 
						|
      };
 | 
						|
    },
 | 
						|
    formattedFileSize() {
 | 
						|
      return numberToHumanSize(this.file.size);
 | 
						|
    },
 | 
						|
    showCreateNewMrToggle() {
 | 
						|
      return this.canPushCode && this.target !== this.originalBranch;
 | 
						|
    },
 | 
						|
    formCompleted() {
 | 
						|
      return this.file && this.commit && this.target;
 | 
						|
    },
 | 
						|
  },
 | 
						|
  methods: {
 | 
						|
    show() {
 | 
						|
      this.$refs[this.modalId].show();
 | 
						|
    },
 | 
						|
    setFile(file) {
 | 
						|
      this.file = file;
 | 
						|
 | 
						|
      const fileUurlReader = new FileReader();
 | 
						|
 | 
						|
      fileUurlReader.readAsDataURL(this.file);
 | 
						|
 | 
						|
      fileUurlReader.onload = (e) => {
 | 
						|
        this.filePreviewURL = e.target?.result;
 | 
						|
      };
 | 
						|
    },
 | 
						|
    removeFile() {
 | 
						|
      this.file = null;
 | 
						|
      this.filePreviewURL = null;
 | 
						|
    },
 | 
						|
    submitForm() {
 | 
						|
      return this.replacePath ? this.replaceFile() : this.uploadFile();
 | 
						|
    },
 | 
						|
    submitRequest(method, url) {
 | 
						|
      return axios({
 | 
						|
        method,
 | 
						|
        url,
 | 
						|
        data: this.formData(),
 | 
						|
        headers: {
 | 
						|
          ...contentTypeMultipartFormData,
 | 
						|
        },
 | 
						|
      })
 | 
						|
        .then((response) => {
 | 
						|
          visitUrl(response.data.filePath);
 | 
						|
        })
 | 
						|
        .catch(() => {
 | 
						|
          this.loading = false;
 | 
						|
          createAlert({ message: ERROR_MESSAGE });
 | 
						|
        });
 | 
						|
    },
 | 
						|
    formData() {
 | 
						|
      const formData = new FormData();
 | 
						|
      formData.append('branch_name', this.target);
 | 
						|
      formData.append('create_merge_request', this.createNewMr);
 | 
						|
      formData.append('commit_message', this.commit);
 | 
						|
      formData.append('file', this.file);
 | 
						|
 | 
						|
      return formData;
 | 
						|
    },
 | 
						|
    replaceFile() {
 | 
						|
      this.loading = true;
 | 
						|
 | 
						|
      // The PUT path can be geneated from $route (similar to "uploadFile") once router is connected
 | 
						|
      // Follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/332736
 | 
						|
      return this.submitRequest('put', this.replacePath);
 | 
						|
    },
 | 
						|
    uploadFile() {
 | 
						|
      this.loading = true;
 | 
						|
 | 
						|
      const {
 | 
						|
        $route: {
 | 
						|
          params: { path },
 | 
						|
        },
 | 
						|
      } = this;
 | 
						|
      const uploadPath = joinPaths(this.path, path);
 | 
						|
 | 
						|
      return this.submitRequest('post', uploadPath);
 | 
						|
    },
 | 
						|
  },
 | 
						|
  validFileMimetypes: [],
 | 
						|
};
 | 
						|
</script>
 | 
						|
<template>
 | 
						|
  <gl-form>
 | 
						|
    <gl-modal
 | 
						|
      :ref="modalId"
 | 
						|
      :modal-id="modalId"
 | 
						|
      :title="modalTitle"
 | 
						|
      :action-primary="primaryOptions"
 | 
						|
      :action-cancel="cancelOptions"
 | 
						|
      @primary.prevent="submitForm"
 | 
						|
    >
 | 
						|
      <upload-dropzone
 | 
						|
        class="gl-h-200! gl-mb-4"
 | 
						|
        single-file-selection
 | 
						|
        :valid-file-mimetypes="$options.validFileMimetypes"
 | 
						|
        :is-file-valid="() => true"
 | 
						|
        @change="setFile"
 | 
						|
      >
 | 
						|
        <div
 | 
						|
          v-if="file"
 | 
						|
          class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
 | 
						|
        >
 | 
						|
          <img v-if="filePreviewURL" :src="filePreviewURL" class="gl-h-11" />
 | 
						|
          <div>{{ formattedFileSize }}</div>
 | 
						|
          <div>{{ file.name }}</div>
 | 
						|
          <gl-button
 | 
						|
            category="tertiary"
 | 
						|
            variant="confirm"
 | 
						|
            :disabled="loading"
 | 
						|
            @click="removeFile"
 | 
						|
            >{{ $options.i18n.REMOVE_FILE_TEXT }}</gl-button
 | 
						|
          >
 | 
						|
        </div>
 | 
						|
      </upload-dropzone>
 | 
						|
      <gl-form-group :label="$options.i18n.COMMIT_LABEL" label-for="commit_message">
 | 
						|
        <gl-form-textarea v-model="commit" name="commit_message" :disabled="loading" no-resize />
 | 
						|
      </gl-form-group>
 | 
						|
      <gl-form-group
 | 
						|
        v-if="canPushCode"
 | 
						|
        :label="$options.i18n.TARGET_BRANCH_LABEL"
 | 
						|
        label-for="branch_name"
 | 
						|
      >
 | 
						|
        <gl-form-input v-model="target" :disabled="loading" name="branch_name" />
 | 
						|
      </gl-form-group>
 | 
						|
      <gl-toggle
 | 
						|
        v-if="showCreateNewMrToggle"
 | 
						|
        v-model="createNewMr"
 | 
						|
        :disabled="loading"
 | 
						|
        :label="$options.i18n.TOGGLE_CREATE_MR_LABEL"
 | 
						|
      />
 | 
						|
      <gl-alert v-if="!canPushCode" variant="info" :dismissible="false" class="gl-mt-3">
 | 
						|
        {{ $options.i18n.NEW_BRANCH_IN_FORK }}
 | 
						|
      </gl-alert>
 | 
						|
    </gl-modal>
 | 
						|
  </gl-form>
 | 
						|
</template>
 |