petra-tool / frontend / src / components / UploadForm.vue
UploadForm.vue
Raw
<template>
    <div class="upload">

      <v-container class="px-0">
        <file-upload
          class=""
          style="width: inherit"
          accept="image/jpg,image/jpeg,image/gif,image/png,image/svg,.ai,.psd,
                            video/mp4,video/mov,video/wmv,video/mpg,video/mpeg,
                            audio/mp3,
                            .pdf,.doc,.docx,.ppt,.pptx,.xlsx,.xlsm,.csv,.txt,
                            .html,.notebook,.ipynb,.py,.cpp,.arduino,.r,.stl,.zip,.rar"
          :post-action="postAction()"
          :multiple="true"
          :size="1024 * 1024 * 100"
          v-model="files"
          @input-filter="inputFilter"
          @input-file="inputFile"
          :headers="postHeaders()"
          :drop="true"
          ref="upload">
          <v-card flat style="border: 3px dashed black"
                  :class="{'drop-active': $refs.upload && $refs.upload.dropActive}">
            <v-row class="text-center" style="height: 150px">
              <v-col align-self="center">
                <div class="text-h5 white--text" v-if="$refs.upload && $refs.upload.dropActive">
                  <v-icon x-large color="white">mdi-plus</v-icon>
                  <br>
                  Drop files to upload
                </div>
                <div class="body-1 text--primary" v-else>
                  <v-icon large color="accent">mdi-plus</v-icon>
                  <br>
                  Select files
                </div>
              </v-col>
            </v-row>
          </v-card>
        </file-upload>
      </v-container>

      <v-simple-table class="pb-6">
        <template v-slot:default>
          <thead>
          <tr>
            <th class="text-left body-2">
              Thumb
            </th>
            <th class="text-left body-2">
              Filename
            </th>
            <th class="text-left body-2">
              Size
            </th>
            <th class="text-left body-2">
              Description
            </th>
            <th class="text-left body-2">
              Status
            </th>
            <th class="text-left body-2">
              Action
            </th>
          </tr>
          </thead>
          <tbody>
          <tr v-for="file in files" :key="file.id">
            <td>
              <img v-if="file.thumb" :src="file.thumb" width="40" height="auto" alt="thumb"/>
              <span v-else></span>
            </td>
            <td>
              <div class="filename" v-text="file.name">
              </div>
              <div v-if="file.active || file.progress !== '0.00'">
                <v-progress-linear :value="file.progress" color="success"></v-progress-linear>
              </div>
            </td>
            <td>{{ file.size | formatSize }}</td>
            <td>
              <v-text-field
                label="Describe your file here"
                v-model="file.description"
                dense
                outlined
                counter maxlength="60"
                class="pt-5"
                style="min-width: 300px"
              >
              </v-text-field>
            </td>
            <td v-if="file.error">
              <v-chip dark small color="error">{{ file.error }}</v-chip>
            </td>
            <td v-else-if="file.success">
              <v-chip dark small color="success">success</v-chip>
            </td>
            <td v-else-if="file.active">
              <v-chip dark small color="secondary">active</v-chip>
            </td>
            <td v-else></td>
            <td>
              <v-btn icon class="grey--text" @click="$refs.upload.remove(file)">
                <v-icon>mdi-delete</v-icon>
              </v-btn>
            </td>
          </tr>
          </tbody>
        </template>
      </v-simple-table>

      <v-row>
        <v-col cols="12" md="8" class="body-2">
          <p>File size limit: 100 MB</p>
          <p>Allowed File Extensions:
            jpg, jpeg, gif, png, svg, ai, psd, mp4, mov, wmv,
            mpg, mpeg,
            mp3, pdf, doc, docx, ppt, pptx, xlsx, xlsm, csv, txt, html,
            notebook, ipynb, py, cpp, arduino, r, stl, zip, rar</p>
          <p :class="uploadError === 'upload' ? 'red--text' : ''" class="font-weight-bold">Start upload before submit!</p>
          <p v-show="uploadError === 'missing'" class="red--text font-weight-bold">Upload at least one image in the following form (jpg, jpeg, gif, png, svg, ai, psd, mp4, mov, wmv, mpg, mpeg, pdf)!</p>
        </v-col>
        <v-col cols="12" md="4" class="text-right" align-self="center">
          <v-btn depressed color="accent" class="body-2 px-8" v-if="!$refs.upload || !$refs.upload.active"
                 @click.prevent="$refs.upload.active = true">
            <v-icon left>mdi-upload</v-icon>
            Start Upload
          </v-btn>
          <v-btn depressed color="error" v-else class="body-2 px-8" @click.prevent="$refs.upload.active = false">
            <v-icon left>mdi-stop</v-icon>
            Stop Upload
          </v-btn>
<!--          <div v-if="error" class="pt-1 caption error&#45;&#45;text">Start or finish upload<br> before submit.</div>-->
        </v-col>
      </v-row>

    </div>
</template>

<script>
import FileUpload from 'vue-upload-component'

const config = require('../config');

export default {
  name: "UploadForm",
  components: {
    FileUpload,
  },
  props: ['parentFiles', 'error', 'uploadError'],
  data() {
    return {
      files: this.parentFiles,
    }
  },
  methods: {
    postAction() {
      return `${config.apiUrl}/upload`
    },
    postHeaders() {
      return {
        'Authorization': `Bearer ${this.$auth.token()}`
      }
    },
    inputFilter(newFile, oldFile, prevent) {
      if (newFile && !oldFile) {
        // Before adding a file, Filter system files or hide files
        if (/(\/|^)(Thumbs\.db|desktop\.ini|\..+)$/.test(newFile.name)) {
          return prevent()
        }
        // Filter php html js file
        if (/\.(php5?|jsx?)$/i.test(newFile.name)) {
          return prevent()
        }
      }

      if (newFile && (!oldFile || newFile.file !== oldFile.file)) {
        // Create a blob field
        newFile.blob = ''
        let URL = window.URL || window.webkitURL
        if (URL && URL.createObjectURL) {
          newFile.blob = URL.createObjectURL(newFile.file)
        }
        // Thumbnails
        newFile.thumb = ''
        if (newFile.blob && newFile.type.substr(0, 6) === 'image/') {
          newFile.thumb = newFile.blob
        }
      }
    },
    inputFile(newFile, oldFile) {
      if (newFile && !oldFile) {
        // add
        // console.log('add', newFile)
        this.$emit('updateFiles', this.files)
      }
      if (newFile && oldFile) {
        // update
        // console.log('update', newFile)
        this.$emit('updateFiles', this.files)
      }
      if (!newFile && oldFile) {
        // remove
        // Automatically delete files on the server
        if (oldFile.success && oldFile.response.id) {
          // $.ajax({
          //   type: 'DELETE',
          //   url: '/file/delete?id=' + oldFile.response.id,
          // });
        }
        // console.log('remove', oldFile)
        this.$emit('updateFiles', this.files)
      }
    },
    addText() {
      let file = new window.File(['foo'], 'foo.txt', {
        type: "text/plain",
      })
      this.$refs.upload.add(file)
    }
  },
  filters: {
    formatSize: function (size) {
      if (size > 1024 * 1024 * 1024 * 1024) {
        return (size / 1024 / 1024 / 1024 / 1024).toFixed(2) + ' TB'
      } else if (size > 1024 * 1024 * 1024) {
        return (size / 1024 / 1024 / 1024).toFixed(2) + ' GB'
      } else if (size > 1024 * 1024) {
        return (size / 1024 / 1024).toFixed(2) + ' MB'
      } else if (size > 1024) {
        return (size / 1024).toFixed(2) + ' KB'
      }
      return size.toString() + ' B'
    }
  },
}
</script>

<style>
.upload .drop-active {
  top: 0;
  bottom: 0;
  right: 0;
  left: 0;
  /*position: fixed;*/
  z-index: 9999;
  opacity: .6;
  text-align: center;
  background: #000;
}
</style>